Contours opencv:如何消除二进制图像中的小轮廓

时间:2012-04-20 00:36:18

标签: c++ c visual-c++ opencv image-processing

我目前正致力于图像处理项目。我在VC ++中使用Opencv2.3.1。 我编写的代码使得输入图像仅被过滤为蓝色并转换为二进制图像。二进制图像有一些我不想要的小物体。我想消除那些小对象,所以我使用openCV的cvFindContours()方法来检测二进制图像中的轮廓。但问题是我无法消除图像输出中的小物体。我使用了cvContourArea()函数,但没有正常工作..,侵蚀函数也无法正常工作。

所以请有人帮我解决这个问题..

我获得的二进制图片

enter image description here

我想要获取的结果/输出图像:

enter image description here

6 个答案:

答案 0 :(得分:10)

好的,我相信您的问题可能可以通过OpenCV最近推出的the bounding box demo来解决。

enter image description here

您可能已经注意到,您感兴趣的对象应位于图片中最大的矩形绘制区域内。幸运的是,这段代码并不复杂,我相信你可以通过调查和实验来解决这个问题。

答案 1 :(得分:7)

这是我消除小轮廓的解决方案。 基本思路是检查每个轮廓的长度/面积,然后从矢量容器中删除较小的一个。

通常你会得到这样的轮廓

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));

使用Canny()预处理,您将获得轮廓线段,但每个线段都以边界像素存储为闭环。在这种情况下,您可以检查长度并删除像

这样的小长度
for (vector<vector<Point> >::iterator it = contours.begin(); it!=contours.end(); )
{
    if (it->size()<contour_length_threshold)
        it=contours.erase(it);
    else
        ++it;
}

如果没有Canny()预处理,您将获得对象的轮廓。 相似之处,您也可以使用区域来定义阈值以消除小对象,如OpenCV教程所示

vector<Point> contour = contours[i];
double area0 = contourArea(contour);

此contourArea()是非零像素的数量

答案 2 :(得分:1)

您确定按小轮廓区域过滤不起作用吗?它一直对我有用。我们能看到您的代码吗?

另外,正如sue-ling所提到的,使用侵蚀和扩张来大致保留区域是一个好主意。要去除小的噪声位,首先使用侵蚀,并填充孔,首先使用扩张。

除此之外,您可能想查看cv *函数的新C ++版本(如果您还没有意识到它们)documentation findContours) 。在我看来,它们更容易使用。

答案 3 :(得分:0)

根据前后图像判断,需要确定所有白色区域或斑点的面积,然后应用阈值区域值。这将消除小于该值的所有区域,并且仅留下在第二图像中看到的大的白色区域。使用cvFindContours函数后,尝试使用0阶时刻。这将返回图像中斑点的区域。此链接可能有助于实现我刚才描述的内容。 http://www.aishack.in/2010/07/tracking-colored-objects-in-opencv/

答案 4 :(得分:0)

我相信你可以使用形态学操作员,如侵蚀和扩张(阅读更多here

您需要使用靠近右侧圆圈半径的内核大小(您要消除的内核)执行侵蚀。 然后使用相同的内核进行扩张,以填补侵蚀步骤产生的空隙。

使用相同内核进行扩张后的FYI侵蚀称为开放。

代码将是这样的

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 );

答案 5 :(得分:0)

这不是一种快速的方式,但在某些情况下可能有用。 OpencCV 3.0中有一个新功能 - connectedComponentsWithStats。有了它,我们可以获得连接组件的区域,并消除不必要的。因此,我们可以轻松地删除带孔的圆,使用与实心圆相同的边界框。