Python-OpenCV 笔记6 – 轮廓(Contours)
参考文档: https://docs.opencv.org/3.4/dd/d49/tutorial_py_contour_features.html
1、查找轮廓 findContours
函数原型
image, contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
参数:
- image:8位单通道二值图,如果为灰度图非0值为1
- mode:轮廓的检索模式
- cv2.RETR_EXTERNAL:表示只检测外轮廓
- cv2.RETR_LIST:检测的轮廓不建立等级关系
- cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层
- cv2.RETR_TREE:建立一个等级树结构的轮廓
- method:轮廓的近似办法
- cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))== 1
- cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
- cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
返回值:
- image:被处理的图片,正常没用
- contours:numpy的ndarray,每个元素都是图像中的一个轮廓,每个元素包括多个点
- hierarchy:numpy的ndarray,元素个数和轮廓个数相同,轮廓 contours[i] 对应于hierarchy[i],每个 hierarchy 元素包括四个元素 hierarchy[i][0] ~ hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。
# 实例
img = cv2.imread('1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
_, contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
2、绘制轮廓 findContours
函数原型
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
参数:
- image:输入图像
- contours:轮廓,一个轮廓2个点的维数为(1,1,2,1,2)
- contourIdx:绘制contours中的哪条轮廓,如果是-1,则绘制其中的所有轮廓
- color:绘制的轮廓的颜色
- thickness:轮廓线的宽度,如果是 -1(cv2.FILLED),则为填充模式
# 实例
cv2.drawContours(img,contours,-1,(0,0,255),3)
cv2.imshow("img", img)
cv2.waitKey(0)
3、轮廓的特征 Contour Features
3.1、矩:cv2.moments()
函数原型:
cv2.moments(array[, binaryImage])
- array:单个轮廓,1xNx1x2维的数组,即N个二维点
- binaryImage:如果为True,非0的像素值=1,默认为False
- 返回轮廓区域的矩的字典
实例:
import numpy as np
import cv2
img = cv2.imread('star.jpg',0)
ret, thresh = cv2.threshold(img,127,255,0)
im2,contours,hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)
# 计算x,y轴的矩
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
3.2、面积:cv2.contourArea()
函数原型:
cv2.contourArea(contour[, oriented])
- contour:单个轮廓,1xNx1x2维的数组,即N个二维点
- oriented:如果为True,可以获得轮廓的方向标志,默认为False
- 返回轮廓区域的面积
实例:
area = cv2.contourArea(cnt)
3.3、周长:cv2.arcLength()
函数原型:
cv2.arcLength(curve, closed)
- curve:单个轮廓,1xNx1x2维的数组,即N个二维点
- closed:指示曲线是否闭合的标志
- 返回轮廓区域的周长
实例:
perimeter = cv2.arcLength(cnt, True)
3.4、凸性检测:cv2.isContourConvex()
函数原型:
cv2.isContourConvex(contour)
- contour:单个轮廓,1xNx1x2维的数组,即N个二维点
- 返回轮廓是否为凸性的,是为True,否为False
实例:
k = cv2.isContourConvex(cnt)
4、轮廓近似 Contour Approximation
4.1、多边形近似:cv2.approxPolyDP()
函数原型:
cv2.approxPolyDP(curve, epsilon, closed[, approxCurve])
- curve:单个轮廓,1xNx1x2维的数组,即N个二维点
- epsilon:点的最大距离
- closed:设置曲线是否闭合,即得到首尾两点是否为同一点
- 返回近似轮廓的二维点集
实例:
epsilon = 0.1*cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
4.2、凸包近似:cv2.convexHull()
函数原型:
cv2.convexHull(points[, hull[, clockwise[, returnPoints]]])
- points:单个轮廓,1xNx1x2维的数组,即N个二维点
- hull:输出数组,正常不用
- clockwise:如果True,输出的凸包是顺时针方向,否则为默认的逆时针。
- returnPoints:默认值为True,返回凸包上点的坐标,如果为False,返回与凸包点对应的轮廓上的点。
- 返回近似轮廓的二维点集
实例:
hull = cv2.convexHull(cnt)
4.3、矩形近似:Bounding Rectangle
函数原型:
# 普通矩形
cv2.boundingRect(points) # 1
# 可旋转矩形,即最小的外包矩形
cv2.minAreaRect(points) # 2
# 矩形表达形式的装换
cv2.boxPoints(box) # 3
- points:单个轮廓,1xNx1x2维的数组,即N个二维点
- box:四个二维点的数组
- 返回:
- 1:近似矩形的左上角点坐标、矩形的宽和高(x,y,w,h)
- 2:近似矩形的最上角点坐标(x,y),矩形的宽和高(w,h)及旋转角度θ(°)
- 3:转换为矩形的四个角点坐标
实例:
# 普通矩形
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
# 可旋转矩形,即最小的外包矩形
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(0,0,255),2)
4.4、其它近似
# 最小外接圆
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img,center,radius,(0,255,0),2)
# 最小外接椭圆
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img,ellipse,(0,255,0),2)
# 拟合直线
rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)