How to remove the small blobs?
I want to erase the small white spots areas to keep the largest area (white colour) in the picture:
【这个显然易见是一个形态学的问题】
Before
I used findContours and found the largest area then used drawContours. I got the following result:
My code【他的这种写法,显然不是使用轮廓的好方法。轮廓的处理应该是在形态学后面的,而且寻找联通区域也能够解决这个问题。】
findContours(image, vtContours, vtHierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
for (int i = 0; i < vtContours.size(); i++)
{
double area = contourArea(vtContours[i]);
if (area <= 100) {
continue;
}
// Get only one
if (area > dMaxArea)
{
dMaxArea = area;
nSavedContour = i;
}
}
if (nSavedContour == -1)
{
return false;
}
image = Scalar::all(0);
drawContours(image, vtContours, nSavedContour, Scalar(255), CV_FILLED, 8);
2 answers
If you want to draw hole in your surface you have to use RETR_TREE instead of CV_RETR_EXTERNAL in findContours
About hierarchy :Original image is :
Contours with hierarchy are
0 = [-1, -1, 1, -1] // contour 0 :-1 no next contour,-1 no previous contour, 1 contour #1 is a child, -1 no parent contour
1 = [3, -1, 2, 0] // contour 1 :-3 next contour,-1 no previous contour, 1 contour #2 is a child, 0 is parent contour
2 = [-1, -1, -1, 1]
3 = [-1, 1, -1, 0]
program is :
Mat img = imread("C:/Users/Laurent.PC-LAURENT-VISI/Desktop/14887743804853655.jpg", CV_LOAD_IMAGE_GRAYSCALE);
imshow("original", img);
Mat y;
threshold(img, y, 50, 255, THRESH_BINARY);
imshow("threshold", y);
double ccMin, ccMax;
findContours(y, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
Mat c = Mat::zeros(img.size(), CV_8U);
for (int i = 0; i <contours.size(); i++)
{
cout<<i<<" = "<<hierarchy[i]<<"\n";
}
for (int i = 0; i <contours.size(); i++)
{
drawContours(c, contours, i, Scalar(255), 1, LINE_8, hierarchy, 0);
putText(c,format("%d",i),contours[i][0], FONT_HERSHEY_SIMPLEX,0.5,Scalar(255));
}
imshow("ctr",c);
imwrite("c.png",c);
waitKey(0);
Comments
If the problem you‘re asking for help with is the contour being filled in, probably the easiest way to make it how you want is to use that filled in contour as a mask on your image:
Mat mask = Mat::zeros(image.size(), CV_8U);
Mat newImage;
drawContours(mask, vtContours, nSavedContour, Scalar(255), CV_FILLED, 8);
image.copyTo(newImage, mask);
Then you‘ll have the contour you want in newImage.
Also if you want the largest contour, it‘s probably easiest to just sort the vector of contours. This is the function I always use for that:
void sortContours(vector<vector<Point>>& contours)
{
auto contourComparator = [](vector<Point> a, vector<Point> b) { return contourArea(a) > contourArea(b); };
sort(contours.begin(), contours.end(), contourComparator);
}
Then the largest one will just be the first one in the vector, so it would just be this to make the mask:
sortContours(vtContours);
drawContours(mask, vtContours, 0, Scalar(255), CV_FILLED, 8);
Thank for supporting. I used morphological operators. But I want to use based on findContours. After change RETR_TREE instead of CV_RETR_EXTERNAL, what do I need to do? Tks!