cv2.findContours OpenCV图形轮廓函数python

contours, hierarchy = cv2.findContours(img, mode=cv2.RETR_EXTERNAL,                                                                                                          method=cv2.CHAIN_APPROX_NONE)

输入参数:

  1. img   : 单通道二值图像,白色是前景
  2. RETR_EXTERNAL  : 只返回最外边的轮廓, hierarchy[i][2]=hierarchy[i][3]=-1
  3. CHAIN_APPROX_NONE   :  存储轮廓上的所有点

输出参数:

  1. contours    : 轮廓  M*N  M是轮廓个数  N是每个轮廓的点
  2. hierarchy   : 轮廓等级关系 M*4

不同版本的opencv中输出参数个数有3个的,有2个的,我的版本是opencv-python 4.5.3.56 

这个函数输出数里的contours很好理解,主要是后面这个hierarchy(等级关系)和后面这个mode与method的关系不是很好理解,其中,method主要是表示存储方式的不同,如下

CV_CHAIN_APPROX_NONE  :存储轮廓的所有点

CV_CHAIN_APPROX_SIMPLE :不保存轮廓中水平、垂直、对角的线段,只保存轮廓的角点

CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS  应用了 Teh-Chin 链近  似算法的一种存储风格,这个我也没搞懂

剩下的就是重点,就是输出参数hierarchy和mode的关系到底是什么样的,hierarchy的四个参数到底表示的是什么意思,这四个值分别表示当前轮廓的“后前子父”对象的序号,下面看验证,首先看mode的四个选项,

  • CV_RETR_EXTERNAL :返回最外层轮廓, hierarchy[i][2]=hierarchy[i][3]=-1 
  • CV_RETR_LIST :返回所有的轮廓,但是没建立等级关系
  • CV_RETR_CCOMP :返回所有轮廓,包含两个层级结构
  • CV_RETR_TREE :返回所有轮廓,建立完整的层次结构

例子:采用图片如下:

验证1、 contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_EXTERNAL,                                                                                                                      cv2.CHAIN_APPROX_NONE)

 cv2.RETR_EXTERNAL:返回最外侧轮廓线

得到结果:如下图,找到了所有最外侧的边框

 此时,hierarchy的值很好理解

表1

序号
0-1-1-1
12  -1-1
2-1 1-1-1

 表1中第一列是hierarchy中的轮廓序号,后四列分别是该轮廓的“后前子父”的轮廓序号,这里 mode= cv2.RETR_EXTERNAL,所以只返回最外侧轮廓,那么每一个轮廓都是单独的,也就没有子父轮廓,所以后两行都是-1,表示没有。

表1中第一行[1 -1 -1 -1 ]表示序号为0的轮廓,它的下一个是序号为1 的轮廓,前一个是序号为-1的轮廓,也就是没有前一个,它是第一个。同样可以推出,轮廓顺序为:0  1  2

验证2、contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_LIST,                                                                                                                       cv2.CHAIN_APPROX_NONE)

cv2.RETR_LIST:返回所有轮廓线,不建立等级关系

得到结果:图4

此时,hierarchy的值为:

序       后  前  子  父

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

可以看出,图4中,找到了全部的轮廓线,“后前子父”中,子父都为-1,他们之间没有任何等级关系。

验证3:contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_CCOMP,                                                                                                                                    cv2.CHAIN_APPROX_NONE)

 cv2.RETR_CCOMP :返回所有轮廓,包含两个层级结构

得到结果如图:

 此时,hierarchy的值为

序       后  前  子  父

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

 mode= cv2.RETR_CCOMP :包含了两个层级结构,如上图所示,两个层级分别是一个图形的两侧,如[0 1],[2  3]表示的是左下侧回字形框的两个口的内外侧轮廓;[4  5]表示左上侧五角星的内外侧轮廓;右侧的葫芦形最外侧轮廓是6,内侧轮廓分别有3个,从下到上分别是7、8、9,所以它的两层级结构是[6  (7\8\9)];

从hierarchy的值中也可以看出,0的后一个是2, 2的后一个是4, 4的后一个是6,即[0  2  4  6]是最外侧轮廓;0的子轮廓是1,1的父轮廓是0,并且轮廓1没有并列的轮廓,所以前后都是-1;轮廓2和轮廓3,轮廓4和轮廓5同理;轮廓6的子轮廓有7、8、9,这里将排序第一的子轮廓7,放在hierarchy的第二位上,轮廓7的后一位是8,前一位没有,轮廓8的后一位是9,前一位是7,轮廓9的后一位没有,前一位是8,他们三个都是6的子轮廓,可以看到,他们hierarchy的最后一位都是6.

验证4:contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_TREE,                                                                                                                                   cv2.CHAIN_APPROX_NONE)

cv2.RETR_TREE :返回所有轮廓,建立完整的层次结构

得到结果如图 

此时,hierarchy的值:

序       后  前  子  父

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

 从图中可以看出,cv2.RETR_TREE :返回所有轮廓,建立完整的层次结构。从左下角的回字形开始,从最外到最内,分别是0、1、2、3,左上角的五角星轮廓分别是4、5,右侧的葫芦形,从最外6,到内侧并列的7、8、9.   在hierarchy中完整的形成了树结构,比如0的子轮廓是1,1的子轮廓是2,2的子轮廓是3;0的下一个轮廓是4,4的子轮廓是5;4的下一个轮廓是6,6的子轮廓是7,7的后一个轮廓是8,  8的后一个轮廓是9.

 最后附上验证程序:验证程序中比较乱七八糟,懒得改了

import numpy as np
import cv2

fgmask = cv2.imread('D:\cycFeng\Data\\contours.jpg')  # 绝对路径
fgmask = cv2.cvtColor(fgmask, cv2.COLOR_BGR2GRAY)
ret, fgmask = cv2.threshold(fgmask, 100, 255, cv2.THRESH_BINARY_INV)
# cv2.imwrite('D:\cycFeng\Data\\contour.jpg',fgmask)
contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#查找轮廓,输入的是二值图像
i = 0
# for c in contours:
#     perimeter = cv2.arcLength(c, True) #计算这个轮廓的周长
#     if perimeter > 2: #轮廓周长大于188才画出来
#         m = i
#         x, y, w, h = cv2.boundingRect(c) #找到三角形的上右边界
#         cv2.rectangle(fgmask, (x, y), (x + w, y + h), (123, 123, 17), 2)
#         # cv2.imshow(str(i), fgmask)
#         # cv2.imwrite('D:\cycFeng\Data\\'+str(i)+'.jpg', fgmask)
#         print(hierarchy[0][i])
#     i += 1
fgmask = cv2.cvtColor(fgmask, cv2.COLOR_GRAY2BGR)
for cnt in contours:
    fgmask = cv2.drawContours(fgmask, cnt, -1, (0, 0, 255), 2)
cv2.imwrite('D:\cycFeng\Data\\fgmask.jpg', fgmask)
print(hierarchy[0])
cv2.imshow('fgmask', fgmask)
cv2.waitKey()

  • 41
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值