• 【OpenCV-Python】教程:3-9 轮廓(5)轮廓层级


    OpenCV Python 轮廓层次

    【目标】

    • 学习轮廓的层次关系

    在前几个课程里面,学习了 cv2.findContours() 函数, 传递了参数 Contour Retrieval Mode . 通常是 cv.RETR_LIST or cv.RETR_TREE 工作的很好,但是他们是什么意思呢?
    hierarchy 到底是什么呢?
    在某些情况下,有些形状是在其他形状内部,就像层级一样。我们称上层的为 parent,内部的为 child。表达这种“父-子”关系形状轮廓称之为 Hierarchy

    一个例子如下:

    在这里插入图片描述

    在这个图像中,有许多形状,我们标号为 0~522a 表明外部轮廓和内部轮廓。

    0,1,2 都是最外层的轮廓,层级为0

    轮廓 22a 的父轮廓,2a2 的子轮廓,定义为层级1;轮廓 3 是轮廓 2a 的子轮廓。

    轮廓 4 是 轮廓 3a 的第一个子轮廓。

    OpenCV 用 [Next, Previous, First_Child, Parent] 表示轮廓层级关系信息。

    Next: 下一个的意思就是同一层级里下一个轮廓。如果第 0 个轮廓的下一个轮廓是 1 ,那么 Next = 1; 如果同一层级没有下一个轮廓,简单的就设置 Next = -1

    Previous: 同一层级里前一个轮廓,与 Next 相反;同样,没有前一个轮廓,也设置为 -1

    First_Child: 第一个子轮廓,不需要过多解释,对于轮廓 2 来说, 2a 是其子轮廓;对于轮廓 3a 来说,有两个子轮廓,轮廓 4是第一个子轮廓。

    Parent: 父轮廓的索引,与 First_Child 相反。对于轮廓 4和轮廓 5 来说,他们的父轮廓都是 3a;

    如果没有父轮廓或子轮廓,都设置为 -1

    所以,我们已经直到了OpenCV里的轮廓层级关系,cv.RETR_LIST, cv.RETR_TREE, cv.RETR_CCOMP, cv.RETR_EXTERNAL 等等是什么意思呢?

    1. RETR_LIST

    这是4个标志里最简单的,提取所有的轮廓并存储下来,没有父子关系,在这里,他们都是同一个级别。

    所以,第 3 个和第 4 个参数始终为 -1;但是很明显,下一个和前一个都是对应的值。例如存储的 层次信息如下:

    [[  [ 1, -1, -1, -1],  # contours- 0
        [ 2,  0, -1, -1],  # contours- 1
        [ 3,  1, -1, -1],
        [ 4,  2, -1, -1],
        [ 5,  3, -1, -1],
        [ 6,  4, -1, -1],
        [ 7,  5, -1, -1],
        [-1,  6, -1, -1]]] # contours- 7
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2. RETR_EXTERNAL

    如果使用这个标志,那么只提取轮廓的最外层轮廓,所有子轮廓将不被存储,换句话说,一个轮廓有子轮廓和孙轮廓,一直向上回溯到该父轮廓没有父轮廓,才保留下来(一个轮廓家族留下最老的 😃)。

    上图中,只有 0, 1, 2 才是最外层(最老的,没有父轮廓,层级为0)。

    [[  [ 1, -1, -1, -1],   # contours- 0
        [ 2,  0, -1, -1],   # contours- 1
        [-1,  1, -1, -1]]]  # contours- 2
    
    • 1
    • 2
    • 3

    3. RETR_CCOMP

    使用该标志时,将轮廓赋值为 2 个级别。最外层的级别为 1, 内部的层级为 2; 如果内部还有其他内部层级,循环使用级别1 和 2

    如下图所示:

    在这里插入图片描述

    绿色数字表示层级,外层的橙色表示轮廓序号;

    轮廓 0 的层级为 1, 有两个洞(层级都是2),分别是轮廓 1 和轮廓 2,对于轮廓 0 来说,下一个轮廓是轮廓 3, 没有上一个轮廓; [3, -1, 1, -1]

    [[  [ 3, -1,  1, -1],
        [ 2, -1, -1,  0],
        [-1,  1, -1,  0],
        [ 5,  0,  4, -1],
        [-1, -1, -1,  3],
        [ 7,  3,  6, -1],
        [-1, -1, -1,  5],
        [ 8,  5, -1, -1],
        [-1,  7, -1, -1]]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4. RETR_TREE

    这是最后一个标志,也是最完美的。检索所有轮廓并创建一个家族,告诉谁是儿子,谁是孙子,谁是父亲,谁是祖父等等。

    结果如下:

    在这里插入图片描述

    对于轮廓 0 来说,层级为 0, 下一个同级轮廓为 7, 没有上一个轮廓,子轮廓为 1, 没有父轮廓,所以存储为

    [7, -1, 1, -1]

    [[ [ 7, -1,  1, -1],
        [-1, -1,  2,  0],
        [-1, -1,  3,  1],
        [-1, -1,  4,  2],
        [-1, -1,  5,  3],
        [ 6, -1, -1,  4],
        [-1,  5, -1,  4],
        [ 8,  0, -1, -1],
        [-1,  7, -1, -1]]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    【代码】

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    import cv2 
    
    img = cv2.imread("contours.png", 0)
    imgcolor = cv2.imread("contours.png", 1)
    ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
    
    # RETR_LIST
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    colorRETR_LIST = imgcolor.copy()
    
    print("\n")
    print("RETR_LIST 轮廓的个数:", len(contours))
    print("RETR_LIST 层级关系如下: ")
    print(hierarchy)
    
    font = cv2.FONT_HERSHEY_SIMPLEX
    for i in range(len(contours)):
        # print("contour ", i, " contours pt =  ", contours[i][0, 0])
        # print("contour ", i, " hierarchy = ", hierarchy[0][i])
        textstr = str(i) + '-' + str(hierarchy[0][i])
        showpt = (contours[i][0, 0, 0] - 3, contours[i][0, 0, 1] + 3)
        cv2.putText(colorRETR_LIST, textstr, showpt, font, 0.4,
                    (0, 0, 255), 1, cv2.LINE_AA)
    cv2.imshow("colorRETR_LIST", colorRETR_LIST)
        
    # RETR_EXTERNAL
    contours, hierarchy = cv2.findContours(
        thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    colorRETR_EXTERNAL = imgcolor.copy()
    
    print("\n")
    print("RETR_EXTERNAL 轮廓的个数:", len(contours))
    print("RETR_EXTERNAL 层级关系如下: ")
    print(hierarchy)
    
    font = cv2.FONT_HERSHEY_SIMPLEX
    for i in range(len(contours)):
        textstr = str(i) + '-' + str(hierarchy[0][i])
        showpt = (contours[i][0, 0, 0] - 3, contours[i][0, 0, 1] + 3)
        cv2.putText(colorRETR_EXTERNAL, textstr, showpt, font, 0.4,
                    (0, 0, 255), 1, cv2.LINE_AA)
    cv2.imshow("colorRETR_EXTERNAL", colorRETR_EXTERNAL)
    
    
    # RETR_CCOMP
    contours, hierarchy = cv2.findContours(
        thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    colorRETR_CCOMP = imgcolor.copy()
    
    print("\n")
    print("RETR_CCOMP 轮廓的个数:", len(contours))
    print("RETR_CCOMP 层级关系如下: ")
    print(hierarchy)
    
    font = cv2.FONT_HERSHEY_SIMPLEX
    for i in range(len(contours)):
        textstr = str(i) + '-' + str(hierarchy[0][i])
        showpt = (contours[i][0, 0, 0] - 3, contours[i][0, 0, 1] + 3)
        cv2.putText(colorRETR_CCOMP, textstr, showpt, font, 0.4,
                    (0, 0, 255), 1, cv2.LINE_AA)
    cv2.imshow("colorRETR_CCOMP", colorRETR_CCOMP)    
                
                
    # RETR_TREE
    contours, hierarchy = cv2.findContours(
        thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    colorRETR_TREE = imgcolor.copy()
    
    print("\n")
    print("RETR_TREE 轮廓的个数:", len(contours))
    print("RETR_TREE 层级关系如下: ")
    print(hierarchy)
    
    font = cv2.FONT_HERSHEY_SIMPLEX
    for i in range(len(contours)):
        textstr = str(i) + '-' + str(hierarchy[0][i])
        showpt = (contours[i][0, 0, 0] - 3, contours[i][0, 0, 1] + 3)
        cv2.putText(colorRETR_TREE, textstr, showpt, font, 0.4,
                    (0, 0, 255), 1, cv2.LINE_AA)
    cv2.imshow("colorRETR_TREE", colorRETR_TREE)
    
    
    # cv2.imshow("img", thresh)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    输出结果如下:

    RETR_LIST 轮廓的个数: 10
    RETR_LIST 层级关系如下: 
    [[[ 1 -1 -1 -1]
      [ 2  0 -1 -1]
      [ 3  1 -1 -1]
      [ 4  2 -1 -1]
      [ 5  3 -1 -1]
      [ 6  4 -1 -1]
      [ 7  5 -1 -1]
      [ 8  6 -1 -1]
      [ 9  7 -1 -1]
      [-1  8 -1 -1]]]
    
    
    RETR_EXTERNAL 轮廓的个数: 5
    RETR_EXTERNAL 层级关系如下: 
    [[[ 1 -1 -1 -1]
      [ 2  0 -1 -1]
      [ 3  1 -1 -1]
      [ 4  2 -1 -1]
      [-1  3 -1 -1]]]
    
    
    RETR_CCOMP 轮廓的个数: 10
    RETR_CCOMP 层级关系如下: 
    [[[ 2 -1  1 -1]
      [-1 -1 -1  0]
      [ 3  0 -1 -1]
      [ 5  2  4 -1]
      [-1 -1 -1  3]
      [ 7  3  6 -1]
      [-1 -1 -1  5]
      [ 8  5 -1 -1]
      [ 9  7 -1 -1]
      [-1  8 -1 -1]]]
    
    
    RETR_TREE 轮廓的个数: 10
    RETR_TREE 层级关系如下: 
    [[[ 1 -1 -1 -1]
      [ 7  0  2 -1]
      [-1 -1  3  1]
      [ 5 -1  4  2]
      [-1 -1 -1  3]
      [-1  3  6  2]
      [-1 -1 -1  5]
      [ 8  1 -1 -1]
      [ 9  7 -1 -1]
      [-1  8 -1 -1]]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    【参考】

    1. OpenCV官方文档
  • 相关阅读:
    《LKD3粗读笔记》(15)进程地址空间
    Dockerfile 命令详解及最佳实践
    C++:CMake常用变量【CMAKE_CXX_FLAGS、CMAKE_BUILD_TYPE、×_BINARY_DIR】
    vue各种时间类型转换
    echarts点击按钮排序
    VSCode 如何设置背景图片
    免费小程序商城搭建之b2b2c o2o 多商家入驻商城 直播带货商城 电子商务b2b2c o2o 多商家入驻商城 直播带货商城 电子商务
    《Python基础教程》专栏总结篇
    【论文翻译】增强复制状态机的两阶段提交协议
    学生网页设计作品 dreamweaver作业静态HTML网页设计模板 美食文化网页作业制作
  • 原文地址:https://blog.csdn.net/zhoujinwang/article/details/128041250