0

I am trying to code a desktop app for calculating score of shooting target range paper.
After researching, find some article can help, but still the problem how to work with openCv or emguCv, I am good at C# but C++ need time to learn it.
Another questio, what is the best approach to detect overlapping bullet holes in a shooting target?
like this image
enter image description here Image is above. In the rings 7 and 8 there are two bullet holes overlapping. In this case it would be easy to solve it by simply performing an erosion.

However, in cases where the circles are almost completely overlapped i don't see how i can identify them.

Some links can help:

Community
  • 1
  • 1
Juste3alfaz
  • 295
  • 4
  • 21
  • 1
    For the overlapping circles, you could try to measure the area of the hole and compare the area to a "stanard" single hole. It might be more robust than erosion and simpler than finding circles. – Anders Jan 28 '17 at 09:57

2 Answers2

2

You can isolate overlapping bullets by following these steps:

  • Isolate your bullets from the rest of the image
  • Apply opening on the bullets (erode then dilate)
  • Compute the distance for each white pixel to the closest black pixel
  • Apply thresholding

Original image

thresholded & distances

isolated bullets

The C++ code:

cv::Mat preprocess(const cv::Mat image) {
    display(image, "Original");

    // Color thresholds
    cv::Scalar minColor(141, 0, 0);
    cv::Scalar maxColor(255, 255, 124);
    cv::Mat filtered;

    // Isolate the interesting range of colors
    cv::inRange(image, minColor, maxColor, filtered);
    filtered.convertTo(filtered, CV_8U);

    // Apply opening (erode then dilate)
    cv::Mat opening;
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
    cv::morphologyEx(filtered, opening, cv::MORPH_OPEN, kernel, cv::Point(-1,-1), 2);

    // Compute the distance to the closest zero pixel (euclidian)
    cv::Mat distance;
    cv::distanceTransform(opening, distance, CV_DIST_L2, 5);
    cv::normalize(distance, distance, 0, 1.0, cv::NORM_MINMAX);

    display(distance, "Distance");

    // Thresholding using the longest distance
    double min, max;
    cv::minMaxLoc(distance, &min, &max);
    cv::Mat thresholded;
    cv::threshold(distance, thresholded, 0.7 * max, 255, CV_THRESH_BINARY);
    thresholded.convertTo(thresholded, CV_8U);

    // Find connected components
    cv::Mat labels;
    int nbLabels = cv::connectedComponents(thresholded, labels);

    // Assign a random color to each label
    vector<int> colors(nbLabels, 0);
    for (int label = 1; label < nbLabels; ++label) {
        colors[label] = rand() & 255;
    }
    cv::Mat result(distance.size(), CV_8U);
    for (int r = 0; r < result.rows; ++r) {
        for (int c = 0; c < result.cols; ++c) {
            int label = labels.at<int>(r, c);

            result.at<uchar>(r, c) = colors[label];
        }
    }

    display(result, "Labels");

    return result;
}
Jspdown
  • 424
  • 3
  • 11
1

there are two ways in which you can complete your task.

  1. The simpler method is to subtract the images. Take an ideal Target image and subtract it with the target image after each hit or at last after completing the entire shoot.
  2. The other method would be to separate colors. If the Color of bullet is blue, then you can us inRange function to filter out the color. You can even make a library of different color bullets so the user can choose it from the option. I have recently done similar project in C#. For more details contact be on my email.(rajkumarm704@gmail.com)
Raj Kumar Mishra
  • 516
  • 4
  • 16