用法:cnt, hierarchy = cv2.findContours( 图 , 检索模式 , 轮廓近似办法 )
cv2.RETR_EXTERNAL:
只检测外轮廓
cv2.RETR_LIST:
检测的轮廓建立等级关系:
外轮廓为同一层级 ,同一外轮廓的内轮廓为同一层级
双层轮廓顺序基于外轮廓最上像素点Y坐标从大到小排序(图 片的从下到上),若存在Y坐标相同情况下 根据X坐标从大到 小排序(图片的从右到左)
若有多个内轮廓,内轮廓排序基于内轮廓最上像素点Y坐标从 大到小排序(图片的从下到上),若存在Y 坐标相同情况下根 据X坐标从大到小排序(图片的从右到左)
cv2.RETR_TREE :
不同层级的轮廓顺序从里到外:
同级轮廓根据轮廓最上像素点Y坐标从大到小排序(图片的从 下到上),若存在Y坐标相同情况下根据X坐 标从大到小排序 (图片的从右到左)
若一个轮廓内有子轮廓,回先查找该轮廓的所有子轮廓后才会 继续同级轮廓的查找。(有点像深搜)
2.轮廓近似办法:
cv2.CHAIN_APPROX_NONE:
存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE:
压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
3.CNT:
4.hierarchy:
各轮廓之间的关系
下面具体解释下hierarchy输出的矩阵参数的意义
其输出矩矩阵大小为NXM, 其中N为轮廓的个数,M恒等于4,也就是说每一行的4个数,能够表示出轮廓间的相互关系,那么具体是怎样表示的呢
第一个数:表示同一级轮廓的下个轮廓的编号,如果这一级轮廓没有下一个轮廓,一般是这一级轮廓的最后一个的时候,则为-1
第二个数:表示同一级轮廓的上个轮廓的编号,如果这一级轮廓没有上一个轮廓,一般是这一级轮廓的第一个的时候,则为-1
第三个数:表示该轮廓包含的下一级轮廓的第一个的编号,假如没有,则为-1
第四个数: 表示该轮廓的上一级轮廓的编号,假如没有上一级,则为-1
常用:
from cv2 import cv2
import numpy as np
img = cv2.imread('D:/xxx.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #findContours只能检测二值化后的图片
contours,Hierarchy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
print (type(contours))
print (type(contours[0]))
>>> <class 'list'> # 第一个返回值类型为list
<class 'numpy.ndarray'> # list 的中的每个元素是numpy中的ndarray
用法:rect = cv2.minAreaRect(cnt)
其中cnt要求最小外接矩形的点集数组或向量,这个点集不定个数。
返回一个Box2D结构rect:
rect [0] : 矩形中点坐标
rect [1] [0] : 宽度width
rect [1] [1] :长度heith
rect [2] : 旋转角度
其中旋转角度θ是水平轴(x轴)逆时针旋转,与碰到的矩形的第一条边的夹角,且width与height不是按照长短来定义的,而是将这第一条边作为width。
当使用findContours返回的轮廓不止一个时,使用循环得到每个轮廓的最小外接矩形:
for cnt in contours:
rect = cv2.minAreaRect(cnt)
print("中心坐标:", rect[0])
print("宽度:", rect[1][0])
print("长度:", rect[1][1])
print("旋转角度:", rect[2])
>>> 中心坐标: ( x1 , y1 )
宽度: width1
长度: heith1
旋转角度: θ1
中心坐标: ( x2 , y2 )
宽度: width2
长度: heith2
旋转角度: θ2
······
用法:box = cv2.boxPoints(rect) # 获取矩形四个顶点,浮点型
box = np.int0(box) # 取整
但这四个坐标的对应点我们并不明确,对此,可从坐标值的大小特征入手,将四个坐标与矩形的四个顶点匹配:
在opencv的坐标体系下,纵坐标最小的是top_point,纵坐标最大的是bottom_point, 横坐标最小的是 left_point,横坐标最大的是right_point。
box = cv2.boxPoints(rect)
box = np.int0(box)
left_point_x = np.min(box[:, 0]) # 获取四个顶点坐标
right_point_x = np.max(box[:, 0])
top_point_y = np.min(box[:, 1])
bottom_point_y = np.max(box[:, 1])
left_point_y = box[:, 1][np.where(box[:, 0] == left_point_x)][0]
right_point_y = box[:, 1][np.where(box[:, 0] == right_point_x)][0]
top_point_x = box[:, 0][np.where(box[:, 1] == top_point_y)][0]
bottom_point_x = box[:, 0][np.where(box[:, 1] == bottom_point_y)][0]
# 上下左右四个点坐标
vertices = np.array([[top_point_x, top_point_y], [bottom_point_x, bottom_point_y], [left_point_x, left_point_y], [right_point_x, right_point_y]])
用法:x, y, w, h = cv2.boundingRect(cnt)
其中 x,y 为矩形左上角顶点的坐标
w,h为矩形的宽和长
for cnt in contours
x, y, w, h = cv2.boundingRect(cnt)
print(x)
print(y)
print(w)
print(h)
>>> x1
y1
w1
h1
·······
用法:cv2.drawContours(img , list , a , ( b , g , r ) , thickness )
用法:cv2.drawContours(img , list , a , ( b , g , r ) , thickness )