12. 形态学--轮廓、多边形逼近与凸包
1. 轮廓
findContours(image, mode, method[, contours[, hierarchy[, offset]]])
- mode查找轮廓的模式
cv2.RETR_EXTERNAL = 0,表示指检测外围扩阔
cv2.RETR_LIST = 1,检测的轮廓不建立等级关系,即检测所有的轮廓
cv2.RETR_CCOMP = 2,每层最多两级,从小到大,从里到外
cv2.RETR_TREE = 3,按照树型存储轮廓,从大到小,从右到左,较为常用 - method 轮廓近似方法,也叫ApproximationMode
cv2.CHAIN_APPROX_NONE 保存所有轮廓上的点
cv2.CHAIN_APPROX_SIMPLE 只保存角点,存储信息少,比较常用 - 反馈contours和hierarchy 即轮廓和层级
img = cv2.imread('./contors1.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
# 注意contours是一个list,里面的元素是ndarray,每个ndarray表示一个contour
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 注意,会直接在原图上进行操作,如果要原图保持不变,就需要copy一份
img_copy = img.copy()
cv2.drawContours(img_copy, contours, 1, (0,0,255), 2)
# 计算轮廓面积
area = cv2.contourArea(contours[1])
# 计算轮廓周长
cv2.arcLength(contours[1], closed=True)
# 返回结果是一个Rotated Rect 旋转的矩形,矩形的起始坐标(x, y), 矩形的长宽,矩形的旋转角度
# boundingRect(points) 最大外接矩阵
rect = cv2.minAreaRect(contours[1])
# cv的工具,将旋转矩阵的四个坐标点计算出来
# 注意:这个计算出来后的数据是float,而在绘图的时候,要求像素点位置,是int的
box = cv2.boxPoints(rect)
# 对boxPoints的结果进行处理
box = np.round(box).astype('int64')
cv2.drawContours(img, [box], 0, (255,0,0), 2)
cv2.imshow('img', img)
2. 多边形逼近与凸包
findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似,这就是轮廓的多边形逼近;
DP算法原理核心,不断找多边形最远的点加入形成新的多边形,直到最短距离小于指定的精度;
approxPolyDP(curve, epsilon, closed, approxCurve=None)
- curve 要近似逼近的轮廓
- epsilon 即DP算法使用的阈值
- closed 轮廓是否闭合
# 获取单个轮廓
cnt = contours[0]
# 根据轮廓周长来逼近
epsilon = 0.05*cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
# 将res使用cv2.im_show()展示出来
# 边界矩形
x, y, w, h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x,y), (x+w, y+h), (0,255,0), 2)
# im_show()
# 最小外接圆
(x,y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
img = cv2.circle(img, center, radius, (0,255,0), 2)
# im_show()