cvFindContours()
方法来检测二进制图像中的轮廓。但是问题是我无法消除图像输出中的小物体。我使用了cvContourArea()
函数,但没有正常工作...腐蚀函数也没有正常工作。所以请有人帮我解决这个问题... 我获得的二进制图像:
![enter image description here](https://istack.dev59.com/YEyQQ.webp)
![enter image description here](https://istack.dev59.com/tmYa8.webp)
cvFindContours()
方法来检测二进制图像中的轮廓。但是问题是我无法消除图像输出中的小物体。我使用了cvContourArea()
函数,但没有正常工作...腐蚀函数也没有正常工作。这里是我消除小轮廓的解决方案。 基本思路是检查每个轮廓的长度/面积,然后从向量容器中删除较小的轮廓。
通常情况下,您会得到像这样的轮廓。
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()是指非零像素的数量。
你确定按小轮廓面积过滤不起作用吗?对我来说它总是有效的。我们可以看一下你的代码吗?
另外,就像 Sue-Ling 提到的那样,使用腐蚀和膨胀结合起来大致保留面积是个好主意。要去除小的噪点,请先使用侵蚀操作,要填补空洞,请先使用扩张操作。
还有一个提示,如果你还不知道的话,你可能想看看新的 C++ 版本的cv
* 函数(文档 有关于findContours
的)。在我看来,它们要容易得多。
我相信你可以使用形态学运算符,如腐蚀和膨胀(在此处阅读更多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 );
这可能不是一种快速的方法,但在某些情况下可能很有用。 OpencCV 3.0 中有一个新函数 - connectedComponentsWithStats。使用它,我们可以获取连接组件的面积并消除不必要的部分。因此,我们可以轻松地删除带有孔的圆形,并具有与实心圆相同的边界框。