# Python+OpenCV教程14：轮廓特征

## 目标

• 计算物体的周长、面积、质心、最小外接矩形等
• OpenCV函数：cv2.contourArea(), cv2.arcLength(), cv2.approxPolyDP() 等

## 教程

``````img = cv2.imread('handwriting.jpg', 0)
_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
image, contours, hierarchy = cv2.findContours(thresh, 3, 2)

# 以数字3的轮廓为例
cnt = contours[0]
``````

``````img_color1 = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
img_color2 = np.copy(img_color1)
cv2.drawContours(img_color1, [cnt], 0, (0, 0, 255), 2)
``````

### 轮廓面积

``````area = cv2.contourArea(cnt)  # 4386.5
``````

### 轮廓周长

``````perimeter = cv2.arcLength(cnt, True)  # 585.7
``````

### 图像矩

``````M = cv2.moments(cnt)
``````

M中包含了很多轮廓的特征信息，比如`M['m00']`表示轮廓面积，与前面`cv2.contourArea()`计算结果是一样的。质心也可以用算：

``````cx, cy = M['m10'] / M['m00'], M['m01'] / M['m00']  # (205, 281)
``````

### 外接矩形

``````x, y, w, h = cv2.boundingRect(cnt)  # 外接矩形
cv2.rectangle(img_color1, (x, y), (x + w, y + h), (0, 255, 0), 2)
``````
``````rect = cv2.minAreaRect(cnt)  # 最小外接矩形
box = np.int0(cv2.boxPoints(rect))  # 矩形的四个角点取整
cv2.drawContours(img_color1, [box], 0, (255, 0, 0), 2)
``````

### 最小外接圆

``````(x, y), radius = cv2.minEnclosingCircle(cnt)
cv2.circle(img_color2, (x, y), radius, (0, 0, 255), 2)
``````

### 拟合椭圆

``````ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img_color2, ellipse, (255, 255, 0), 2)
``````

### 形状匹配

`cv2.matchShapes()`可以检测两个形状之间的相似度，返回值越小，越相似。先读入下面这张图片：

``````img = cv2.imread('shapes.jpg', 0)
_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
image, contours, hierarchy = cv2.findContours(thresh, 3, 2)
img_color = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)  # 用于绘制的彩色图
``````

``````cnt_a, cnt_b, cnt_c = contours[0], contours[1], contours[2]
print(cv2.matchShapes(cnt_b, cnt_b, 1, 0.0))  # 0.0
print(cv2.matchShapes(cnt_b, cnt_c, 1, 0.0))  # 2.17e-05
print(cv2.matchShapes(cnt_b, cnt_a, 1, 0.0))  # 0.418
``````

## 练习

1. 我们是对手写字符图片中的数字1进行轮廓特征计算，大家换成数字1看看
2. （选做）用形状匹配比较两个字母或数字（这相当于很简单的一个OCR噢）

## 小结

• cv2.contourArea()算面积，cv2.arcLength()算周长，cv2.boundingRect()算外接矩
• cv2.minAreaRect()算最小外接矩，cv2.minEnclosingCircle()算最小外接圆
• cv2.matchShapes()进行形状匹配