关于opencv的矩形检测

我用opencv的minAreaRect检测轮廓后,结果如下,第一张图是原图,第二张是检测出来的最小矩形图,第三张是画在空板上的,一共检测出来三个矩形,我要怎么分辨出来那个是内框图,哪个是外框图,哪位老大给讲解下

img

img

img

opencv的cv2.findContours()这个函数的cv2.RETR_TREE方法提供了轮廓间的层级关系,4.0版本以上的有两个返回值:
contours, hierarchy=cv2.findContours(gray,minThresh,255,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
前面一个contours就是所有找到的轮廓,重点在于后面这个hierachy

img


img


hierarchy=[A,B,C,D]这4个值,表示嵌套关系,其中A为同级的下一个轮廓在contours中的下标(弟弟级别轮廓),B为同级的前一个轮廓(哥哥级),C为目前轮廓的第一个轮廓(嫡长子),D为该轮廓的父轮廓,-1表示不存在。搞清楚了这个,你这种的就很清晰了
hierarchy[0]=[-1,-1,1,-1],表示0号轮廓有子轮廓,嫡长子下标为1,
hierarchy[0]=[2,-1,-1,0],表示1号轮廓,弟弟为2号轮廓,没有哥哥级别,没有孩子,0号为其父轮廓。
hierarchy[0]=[-1,1,-1,0],表示2号轮廓,其下无弟,兄长为1号轮廓,无孩子,0号为其父轮廓。
所以,除非你能保证说你的轮廓层级只有两级,那么直接遍历0号轮廓和0号轮廓的兄弟,他们的孩子就都是2级轮廓(广度遍历)

通过识别出来的几组坐标数据,来判断一下包含关系。

根据区域做差的面积判断也是可以的.
情况一:大小区域没有包含关系,做差后大区域面积不变.
情况二:大区域非完全包含小区域,做差后大区域面积大于做差前大区域面积与小区域面积之差.
情况三:大区域完全包含小区域,做差后大区域面积等于做差前大区域面积与小区域面积之差.

用QPainterPath的contains方法

Contours Hierarchy https://docs.opencv.org/3.4/d9/d8b/tutorial_py_contours_hierarchy.html

昨天发的博客正好讲这个内容。

通过 hierarchy 可以根据轮廓的层次结构筛选最外层/内层轮廓:

  • 绘制最外层轮廓, hierarchy[0][i][3]=-1 表示没有父轮廓,即为最外层轮廓
  • 绘制最内层轮廓, hierarchy[0][i][2]=-1 表示没有子轮廓,即为最内层轮廓

OpenCV 提供函数 cv.findContours() 从二值图像中寻找轮廓,函数 cv2.drawContours() 绘制轮廓。
返回值 hierarchy 表示轮廓的层次结构和拓扑信息,是一个形如 (1,k,4) 的 Numpy 数组。hierarchy[0][i] 表示第 i 个轮廓的层次结构,是包含 4个值的数组 [Next, Previous, First Child, Parent],分别代表第 i 个轮廓的同层的后一个轮廓、同层的前一个轮廓、第一个子轮廓、父轮廓的编号。
注意7:对实际图像进行轮廓查找时,得到的轮廓数量很多,包括大量的噪声和细微的目标。轮廓的层次结构有助于筛选轮廓,例如只关注最外层轮廓时可以使用 hierarchy[0][i][3]=-1 (没有父轮廓,即为最外层轮廓)。

参考例程:

    # 12.2 绘制轮廓
    img = cv2.imread("../images/pattern1.png", flags=1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度图像
    _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY_INV)
    # 寻找二值化图中的轮廓
    binary, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  # OpenCV3
    # contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  # OpenCV4~

    #  绘制最内层轮廓, hierarchy[0][i][3]=-1 表示没有父轮廓,即为最外层轮廓
    contourEx = img.copy()  # OpenCV3.2 之前的早期版本,查找轮廓函数会修改原始图像
    for i in range(len(contours)):  # 绘制第 i 个轮廓
        if hierarchy[0][i][3]==-1:  # 最外层轮廓
            x, y, w, h = cv2.boundingRect(contours[i])  # 外接矩形
            text = "{}({},{})".format(i, x, y)
            contourEx = cv2.drawContours(contourEx, contours, i, (205, 0, 0), thickness=-1)  # 第 i 个轮廓,内部填充

参考资料:
https://youcans.blog.csdn.net/article/details/124997148
https://youcans.blog.csdn.net/article/details/124997075

如果已知白色轮廓一直是最大的一个的话,可以将检测到的矩形轮廓吗面积按照大小进行排列,最大的那一个一定是白色轮廓,不过这个方法仅仅局限于白色框是最大或者最小的那一个的情况。