如何在opencv中检测打开和关闭的形状。
这些是我想要检测的简单样本形状。我使用findContours
和approxPolyDP
检测到矩形,然后检查矢量之间的角度。
现在我想要检测打开的形状,approxPolyDP
函数已将bool用于关闭的形状设置为true,并且还会检查返回的点isCounterConvex
以及contourArea
限制。
任何想法我应该如何检测这类图像。
答案 0 :(得分:24)
只需在图像中使用findContours(),然后通过检查传递给findContours()函数的层次结构来确定轮廓是否关闭。从第二个图中可以清楚地看出,与第一个图像相比,没有轮廓具有子轮廓,您将从层次参数获得此数据,该参数是可选的输出向量,包含有关图像拓扑的信息。它具有与轮廓数量一样多的元素。
这里我们将使用层次结构
vector< Vec4i > hierarchy
其中第i个轮廓
hierarchy[i][0] = next contour at the same hierarchical level
hierarchy[i][1] = previous contour at the same hierarchical level
hierarchy[i][2] = denotes its first child contour
hierarchy[i][3] = denotes index of its parent contour
如果轮廓i没有下一个,前一个,父级或嵌套轮廓,则hierarchy[i]
的相应元素将为负数。有关详细信息,请参阅findContours()函数。
因此,通过检查值hierarchy[i][2]
,您可以确定轮廓属于是否关闭,如果hierarchy[i][2] = -1
然后没有孩子并且它属于打开,则轮廓属于轮廓。
还有一件事是在findContours()函数中你应该使用CV_RETR_CCOMP来检索所有轮廓并将它们组织成一个两级层次结构。
这是C ++代码如何实现它。
Mat tmp,thr;
Mat src=imread("1.png",1);
cvtColor(src,tmp,CV_BGR2GRAY);
threshold(tmp,thr,200,255,THRESH_BINARY_INV);
vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;
findContours( thr, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
for( int i = 0; i< contours.size(); i=hierarchy[i][0] ) // iterate through each contour.
{
Rect r= boundingRect(contours[i]);
if(hierarchy[i][2]<0) //Check if there is a child contour
rectangle(src,Point(r.x-10,r.y-10), Point(r.x+r.width+10,r.y+r.height+10), Scalar(0,0,255),2,8,0); //Opened contour
else
rectangle(src,Point(r.x-10,r.y-10), Point(r.x+r.width+10,r.y+r.height+10), Scalar(0,255,0),2,8,0); //closed contour
}
<强>结果:强>
答案 1 :(得分:5)
虽然对于所提出的问题是正确的,但@Haris有用的答案不应被视为使用findContours()识别闭合轮廓的一般解决方案。
一个原因是填充的对象没有内部轮廓,因此会返回hierarchy[i][2] = -1
,这意味着此测试本身会错误地将这些轮廓标记为“打开”。
填充对象的轮廓在轮廓层次结构中应该没有子级或父级,即位于顶层。因此,检测填充物体的封闭轮廓至少需要额外的测试:if(hierarchy[i][2] < 0 && hierarchy[i][3] < 0)
。
我认为@Haris的回答可能是倾向于这一点,但我认为值得澄清的是像我一样的人,他们正在学习如何使用opencv。
答案 2 :(得分:4)
与下面相同的Python实现。
import cv2
src = cv2.imread('test.png', cv2.IMREAD_COLOR)
#Transform source image to gray if it is not already
if len(src.shape) != 2:
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
else:
gray = src
ret, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
hierarchy = hierarchy[0]
for i, c in enumerate(contours):
if hierarchy[i][2] < 0 and hierarchy[i][3] < 0:
cv2.drawContours(src, contours, i, (0, 0, 255), 2)
else:
cv2.drawContours(src, contours, i, (0, 255, 0), 2)
#write to the same directory
cv2.imwrite("result.png", src)
答案 3 :(得分:0)
答案取决于您的图像,更具体地说,取决于预设的轮廓数量,是否存在其他物体,噪音等。在单个轮廓的简单情况下,封闭轮廓内部开始的填充不会溢出整个形象;如果从外面开始它就不会进入中间。所以你会在两种情况下保留一些白色区域。