Contours OpenCV:如何消除二值图像中的小轮廓。

9
我正在处理图像处理项目。我使用Opencv2.3.1和VC++。我已经编写了代码以便将输入图像过滤为只有蓝色,并转换为二进制图像。二进制图像中有一些小物体,我不需要它们。我想要消除这些小物体,所以我使用了openCV的cvFindContours() 方法来检测二进制图像中的轮廓。但是问题是我无法消除图像输出中的小物体。我使用了cvContourArea()函数,但没有正常工作...腐蚀函数也没有正常工作。
所以请有人帮我解决这个问题... 我获得的二进制图像: enter image description here 我想要获得的结果/输出图像: enter image description here
6个回答

10

好的,我相信OpenCV最近推出的边界框演示可以解决你的问题。

enter image description here

你可能已经注意到,你感兴趣的对象应该在图片中最大矩形内部。幸运的是,这段代码并不是非常复杂,我相信你可以通过调查和实验来解决所有问题。


你有代码吗?因为链接失效了。 - mrid
@mrid 更新了失效的链接。 - karlphillip

8

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

通常情况下,您会得到像这样的轮廓。

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()是指非零像素的数量。


1

你确定按小轮廓面积过滤不起作用吗?对我来说它总是有效的。我们可以看一下你的代码吗?

另外,就像 Sue-Ling 提到的那样,使用腐蚀和膨胀结合起来大致保留面积是个好主意。要去除小的噪点,请先使用侵蚀操作,要填补空洞,请先使用扩张操作。

还有一个提示,如果你还不知道的话,你可能想看看新的 C++ 版本的cv* 函数(文档 有关于findContours的)。在我看来,它们要容易得多。


谢谢您的建议,但我不知道如何编写代码来查找已检测到的每个斑点/轮廓的面积。我编写的代码在以下链接中。您能否请纠正它并回复:http://textuploader.com/?p=6&id=YwRl。 - Manoj M
哦!我刚忘了,cvutility的头文件和cpp文件可以在以下链接中找到:http://textuploader.com/?p=6&id=Dtnvj http://textuploader.com/?p=6&id=TSlRQ 请将它们包含在源目录和包含路径中。 - Manoj M
我对C api不是很熟悉,但看起来你只是在计算第一个轮廓的面积。你需要遍历所有轮廓,并且只绘制面积大于某个阈值的轮廓。如果你只想找到那一个对象,你应该绘制面积最大的轮廓。 - fferen

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

谢谢您的建议,但我还不知道如何编写代码来找到已检测到的每个斑点/轮廓的面积。 - Manoj M
谢谢您的建议,但我不知道如何编写代码来查找已检测到的每个斑点/轮廓的面积。我编写的代码在以下链接中。您能否请纠正它并回复:http://textuploader.com/?p=6&id=YwRl。 - Manoj M
哦!我刚忘了,cvutility的头文件和cpp文件可以在以下链接中找到:http://textuploader.com/?p=6&id=Dtnvj http://textuploader.com/?p=6&id=TSlRQ。请将它们包含在源代码目录和包含路径中。 - Manoj M
链接已经失效。 - sunside

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

0

这可能不是一种快速的方法,但在某些情况下可能很有用。 OpencCV 3.0 中有一个新函数 - connectedComponentsWithStats。使用它,我们可以获取连接组件的面积并消除不必要的部分。因此,我们可以轻松地删除带有孔的圆形,并具有与实心圆相同的边界框。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接