Detecting small squares attached to something else on the image

Question:

I want to detect small squares circled in red on the image. But the problem is that they are on another white line. I want to know how to separate those squares from the white line and detect them.

Squares to be detected encircled in red

I have used OpenCV Python to write the code. What I have done until now is that I cropped the image so that I get access only to the circular part of the image. Then I cropped the image to get the required part that is the white line. Then I used erosion so that the white line will vanish and the squares remain in the image. Then used Hough circles to detect the squares. This does work for some images but it cannot be generalized. Please help me in finding a generalized code for this. Let me know the logic and also the python code.
Cropped image with the arena(ring)

Cropped image with the white line

Eroded image with remains of those 8 squares after erosion

Final image with detected squares

Also could anyone help me detect that aruco marker on the image. Its getting rejected. I dont know why.
Image is in this link. Detect small squares on an image

Asked By: Roshan Nayak

||

Answers:

here’s C++ code with distanceTransform.
Since I nearly only used openCV functions, you can probably easily convert it to Python code.

I removed the white stripe at the top of the image manually, hope this isn’t a problem.

int main()
{
    cv::Mat input =  cv::imread("C:/StackOverflow/Input/SQUARES.png", cv::IMREAD_GRAYSCALE);
    cv::Mat thres = input > 0; // make binary mas
    cv::Mat dst;
    cv::distanceTransform(thres, dst, CV_DIST_L2, 3);

    double min, max;
    cv::Point minPt, maxPt;
    cv::minMaxLoc(dst, &min, &max, 0, 0);

    double distThres = max*0.65; // a real clustering would be better. This assumes that the white circle thickness is a bout 50% of the square size, so 65% should be ok...

    cv::Mat squaresMask = dst >= distThres;

    cv::imwrite("C:/StackOverflow/Input/SQUARES_mask.png", squaresMask);

    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(squaresMask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);


    cv::Mat output;
    cv::cvtColor(input, output, cv::COLOR_GRAY2BGR);
    for (int i = 0; i < contours.size(); ++i)
    {
        cv::Point2f center;
        float radius;
        cv::minEnclosingCircle(contours[i], center, radius);

        cv::circle(output, center, 5, cv::Scalar(255, 0, 255), -1);
        //cv::circle(output, center, radius, cv::Scalar(255, 0, 255), 1);
    }

    cv::imwrite("C:/StackOverflow/Input/SQUARES_output.png", output);

    cv::imshow("output", output);
    cv::waitKey(0);
}

this is the input:

enter image description here

this it the squaresMask after distance transform

enter image description here

and this is the result

enter image description here

Answered By: Micka