0

I've read this post, but even after using cv::threshold to create a really binarry image, I still get ~500 contours. What am I doing wrong?

Shouldn't cv::findContours return only 13 contours since there are clear 13 blobs?

Mat img = imread("img.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_thresh;
threshold(img, img_thresh, 0, 255, CV_THRESH_BINARY);

vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
cv::findContours(img_thresh, contours, hierarchy, RetrievalModes::RETR_TREE, ContourApproximationModes::CHAIN_APPROX_SIMPLE);

RNG rng(12345);
Mat drawing = Mat::zeros(img_thresh.size(), CV_8UC3);
for (int i = 0; i< contours.size(); i++)
{
    Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
imshow("drawing", drawing);
waitKey();

binary_img enter image description here

UPDATE1 Using cv::RETR_EXTERNAL instead of cv::RETR_TREE, but still return much more contours than should be.
enter image description here

theateist
  • 13,879
  • 17
  • 69
  • 109

1 Answers1

3

If you check your binary image you will see there are a lot of independent contours:

enter image description here

So you first need to clean up them by eroding and dilating as below code:

And you will get this result:

enter image description here

Which is cleaner than the original.

It is all the code:

cv::namedWindow("result", cv::WINDOW_FREERATIO);
cv::Mat img = cv::imread(R"(rUYLL.png)");

// to gray
cv::Mat gray;
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);

cv::threshold(gray, gray, 0, 255, cv::THRESH_BINARY);
cv::erode(gray, gray, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)));
cv::dilate(gray, gray, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)));

std::vector<std::vector<cv::Point> > contours;
cv::findContours(gray, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
cv::drawContours(img, contours, -1, cv::Scalar(0, 255, 0), 2, 8);

cv::imshow("result", img);
cv::waitKey();

And it is the output:

enter image description here

Hope it helps!


And one simplest way which you can also consider if it works for you, just increase the lower threshold from 0 to 80, and DONE

cv::threshold(gray, gray, 80, 255, cv::THRESH_BINARY);

JUST PLAY WITH THRESHOLD and check the result.

The same output just with changing the threshold value:

enter image description here

Bahramdun Adil
  • 5,907
  • 7
  • 35
  • 68