【问题标题】:Recognize open and closed shapes opencv识别开放和封闭的形状opencv
【发布时间】:2014-04-10 01:10:12
【问题描述】:

如何在 opencv 中检测开放和封闭的形状。

这些是我想要检测的简单样本形状。我使用findContoursapproxPolyDP 检测到矩形,然后检查向量之间的角度。

现在我想检测开放形状,approxPolyDP 函数将封闭形状的 bool 设置为 true,并且在返回的点上检查 isCounterConvex,加上 contourArea 限制。

我应该如何继续检测此类图像的任何想法。

【问题讨论】:

    标签: c++ opencv image-processing shape-recognition


    【解决方案1】:

    只需在图像中使用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
        }
    

    结果:

    【讨论】:

      【解决方案2】:

      虽然对所提出的问题是正确的,但 @Haris 有用的答案不应被视为使用 findContours() 识别闭合轮廓的一般解决方案。

      一个原因是填充的对象将没有内部轮廓,因此会返回hierarchy[i][2] = -1,这意味着该测试本身会错误地将此类轮廓标记为“开放”。

      填充对象的轮廓在轮廓层次结构中不应有子级或父级,即位于顶层。因此,要检测填充对象的闭合轮廓至少需要额外的测试:if(hierarchy[i][2] &lt; 0 &amp;&amp; hierarchy[i][3] &lt; 0)

      我认为@Haris 的回答可能暗示了这一点,但我认为对于像我这样正在学习如何使用 opencv 的人来说,这是值得澄清的。

      【讨论】:

        【解决方案3】:

        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)
        

        【讨论】:

        • 你是救命稻草 :)
        【解决方案4】:

        答案取决于您的图像,更具体地说,预设了多少轮廓,是否有其他对象,噪声等。在一个简单的情况下,在闭合轮廓内部开始的单个轮廓泛滥填充不会溢出整个图像;如果从外面开始,它就不会进入中间。所以你会在这两种情况下保留一些白色区域。

        【讨论】:

          【解决方案5】:

          上面的简化 Python 代码

          import cv2
          
          # get contours from image
          img = cv2.imread("image.png")
          gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
          ret, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
          thresh, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
          
          # draw all contours to image (green if opened else red)
          for i in range(len(contours)):
              opened = hierarchy[0][i][2]<0 and hierarchy[0][i][3]<0
              cv2.drawContours(img, contours, i, (0,255,0) if opened else (0,0,255), 2)
          
          cv2.imshow("Contours", img)
          cv2.waitKey(0)
          cv2.destroyAllWindows()
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-04-22
            • 1970-01-01
            • 2019-01-07
            • 2017-03-08
            • 1970-01-01
            • 1970-01-01
            • 2020-11-09
            • 2012-07-25
            相关资源
            最近更新 更多