2012-04-20 245 views
7

我目前正在处理图像处理项目。我正在使用VC++的Opencv2.3.1。 我写过这样的代码,输入图像被过滤为只有蓝色并转换为二进制图像。二进制图像有一些我不想要的小物体。我想消除这些小物体,所以我使用openCV的cvFindContours()方法来检测二值图像中的轮廓。但问题是我无法消除图像输出中的小物体。我用cvContourArea()函数,但没有正常工作..,侵蚀功能也没有正常工作。轮廓opencv:如何消除二进制图像中的小轮廓

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

我获得二进制图像:

enter image description here

,我想获得结果/输出图像:

enter image description here

回答

1

是否确定按小轮廓区域过滤不起作用?它一直为我工作。我们可以看到你的代码吗?

另外,正如sue-ling所说,使用侵蚀剂和扩张剂来大致保存区域是个不错的主意。要去除小嘈杂的钻头,首先使用侵蚀剂,然后填充孔,首先使用扩张剂。

另一方面,如果您不知道它们的功能(documentationfindContours),您可能需要查看cv *函数的新C++版本。在我看来,它们更容易使用。

+0

感谢您的建议,但我没有得到如何编写代码来查找已检测到的每个斑点/轮廓的区域。我写的代码在以下链接中。你能否纠正它并回复。 :http://textuploader.com/?p=6&id=YwRl。 – 2012-04-20 02:16:39

+0

哦!我只是忘了,cvutility的头文件和cpp文件可以在这些链接中找到:http://textuploader.com/?p = 6&id = Dtnvj http://textuploader.com/?p=6&id=TSlRQ请将它们包含在源目录和包含路径。 – 2012-04-20 02:28:55

+0

我对C api不太熟悉,但看起来你只是计算第一个轮廓的面积。您需要遍历轮廓,并只绘制区域大于某个阈值的轮廓。如果你只是想找到一个物体,你应该绘制最大面积的轮廓。 – fferen 2012-04-20 03:09:34

0

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

+0

感谢您的建议,但Iam没有得到如何编写代码来查找已检测到的每个斑点/轮廓的区域。 – 2012-04-20 02:09:36

+0

感谢您的建议,但我不知道如何编写代码来查找已检测到的每个斑点/轮廓的区域。我写的代码在以下链接中。你能否纠正它并回复。 :http://textuploader.com/?p=6&id=YwRl。 – 2012-04-20 02:16:18

+0

哦!我只是忘了,cvutility的头文件和cpp文件可以在这些链接中找到:http://textuploader.com/?p = 6&id = Dtnvj http://textuploader.com/?p=6&id=TSlRQ请将它们包含在源目录和包含路径。 – 2012-04-20 02:28:38

10

好吧,我相信你的问题可以与最近推出的OpenCV被the bounding box demo解决。

enter image description here

正如你可能已经注意到了,你有兴趣的对象应该是里面最大的矩形画面绘制。幸运的是,这段代码并不复杂,我相信你可以通过调查和实验来弄明白。

+0

thnx ..我会检查出来。 – 2012-04-21 23:54:28

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

没有坎尼()预处理,你会得到对象的轮廓。 相似,也可以使用区域来定义阈值,以消除小物件,如)所示

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

此contourArea(OpenCV的教程是非零的像素数

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。有了它,我们可以获得连接组件的区域,并消除不必要的。所以我们可以很容易地去除有孔的圆,与实心圆相同的边界框。