C++ 轮廓 opencv:如何消除二值图像中的小轮廓
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10238765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Contours opencv : How to eliminate small contours in a binary image
提问by Manoj M
I am currently working on image processing project. I am using Opencv2.3.1 with VC++.
I have written the code such that, the input image is filtered to only blue color and converted to a binary image. The binary image has some small objects which I don't want. I wanted to eliminate those small objects, so i used openCV's cvFindContours()
method to detect contours in Binary image. but the problem is I cant eliminate the small objects in the image output. I used cvContourArea()
function , but didn't work properly.. , erode function also didn't work properly.
我目前正在从事图像处理项目。我在 VC++ 中使用 Opencv2.3.1。我已经编写了这样的代码,将输入图像过滤为仅蓝色并转换为二进制图像。二值图像有一些我不想要的小对象。我想消除那些小物体,所以我使用 openCV 的cvFindContours()
方法来检测二进制图像中的轮廓。但问题是我无法消除图像输出中的小物体。我使用了cvContourArea()
function ,但没有正常工作.. , erode 功能也没有正常工作。
So please someone help me with this problem..
所以请有人帮我解决这个问题..
The binary image which I obtained:
我获得的二进制图像:
The result/output image which I wantto obtain :
我想获得的结果/输出图像:
回答by karlphillip
Ok, I believe your problem couldbe solved with the bounding box demorecently introduced by OpenCV.
好的,我相信您的问题可以通过 OpenCV 最近推出的边界框演示来解决。
As you have probably noticed, the object you are interested at should be inside the largest rectangle draw in the picture. Luckily, this code is not very complex and I'm sure you can figure it all out by investigating and experimenting with it.
您可能已经注意到,您感兴趣的对象应该在图片中最大的矩形绘制内。幸运的是,这段代码并不是很复杂,我相信你可以通过调查和试验来弄清楚。
回答by Mass Zhou
Here is my solution to eliminate small contours. The basic idea is check the length/area for each contour, then delete the smaller one from vector container.
这是我消除小轮廓的解决方案。基本思想是检查每个轮廓的长度/面积,然后从矢量容器中删除较小的。
normally you will get contours like this
通常你会得到这样的轮廓
Mat canny_output; //example from OpenCV Tutorial
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny(src_img, canny_output, thresh, thresh*2, 3);//with or without, explained later.
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0,0));
With Canny() pre-processing, you will get contour segments, however each segment is stored with boundary pixels as a closed ring. In this case, you can check the length and delete the small one like
通过 Canny() 预处理,您将获得轮廓段,但是每个段都与边界像素一起存储为封闭环。在这种情况下,您可以检查长度并删除小的像
for (vector<vector<Point> >::iterator it = contours.begin(); it!=contours.end(); )
{
if (it->size()<contour_length_threshold)
it=contours.erase(it);
else
++it;
}
Without Canny() preprocessing, you will get contours of objects. Similarity, you can also use area to define a threshold to eliminate small objects, as OpenCV tutorial shown
如果没有 Canny() 预处理,您将获得对象的轮廓。类似的,你也可以使用area来定义一个阈值来消除小物体,如OpenCV教程所示
vector<Point> contour = contours[i];
double area0 = contourArea(contour);
this contourArea() is the number of non-zero pixels
这个contourArea() 是非零像素的数量
回答by fferen
Are you sure filtering by small contour area didn't work? It's always worked for me. Can we see your code?
您确定按小轮廓区域过滤不起作用吗?它总是对我有用。我们可以看看你的代码吗?
Also, as sue-ling mentioned, it's a good idea to use both erode and dilate to approximately preserve area. To remove small noisy bits, use erode first, and to fill in holes, use dilate first.
此外,正如 sue-ling 所提到的,最好同时使用 erode 和 dilate 来近似保留区域。要去除小的嘈杂位,请先使用腐蚀,然后填充孔,先使用膨胀。
And another aside, you may want to check out the new C++ versions of the cv
* functions if you weren't aware of them already (documentationfor findContours
). They're much easier to use, in my opinion.
而另一边,你可能要检查出的新的C ++版本cv
*功能,如果你不知道他们已经(文档的findContours
)。在我看来,它们更容易使用。
回答by sue-ling
Judging by the before and after images, you need to determine the area of all the white areas or blobs, then apply a threshold area value. This would eliminate all areas less than the value and leave only the large white region which is seen in the 2nd image. After using the cvFindContours function, try using 0 order moments. This would return the area of the blobs in the image. This link might be helpful in implementing what I've just described. http://www.aishack.in/2010/07/tracking-colored-objects-in-opencv/
根据前后图像判断,您需要确定所有白色区域或斑点的面积,然后应用阈值面积值。这将消除所有小于该值的区域,只留下第二张图像中看到的大白色区域。使用 cvFindContours 函数后,尝试使用 0 阶矩。这将返回图像中斑点的区域。此链接可能有助于实现我刚刚描述的内容。 http://www.aishack.in/2010/07/tracking-colored-objects-in-opencv/
回答by Ashraf Saleh
I believe you can use morphological operators like erode and dilate (read more here)
我相信你可以使用像 erode 和 dilate 这样的形态学运算符(在这里阅读更多)
You need to perform erosion with a kernel size near to the radius of the circle on the right (the one you want to eliminate). followed by dilation using the same kernel to fill the gaps created by the erosion step.
您需要使用接近右侧圆(要消除的圆)半径的内核大小执行侵蚀。然后使用相同的内核进行膨胀以填充腐蚀步骤产生的间隙。
FYI erosion followed by dilation using the same kernel is called opening.
仅供参考,使用相同的内核进行腐蚀和膨胀称为开运算。
the code will be something like this
代码将是这样的
int erosion_size = 30; // adjust with you application
Mat erode_element = getStructuringElement( MORPH_ELLIPSE,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
erode( binary_img, binary_img, erode_element );
dilate( binary_img, binary_img, erode_element );
回答by Nick
It is not a fast way but may be usefull in some cases. There is a new function in OpencCV 3.0 - connectedComponentsWithStats. With it we can get area of connected components and eliminate unnecessary. So we can easy remove circle with holes, with the same bounding box as solid circle.
这不是一种快速的方法,但在某些情况下可能很有用。OpencCV 3.0 中有一个新功能 - connectedComponentsWithStats。有了它,我们可以获得连接组件的区域并消除不必要的。因此,我们可以轻松删除带孔的圆,其边界框与实心圆相同。