opencv-051-二值图像分析(使用轮廓逼近)

知识点

对图像二值图像的每个轮廓,可以使用轮廓逼近,逼近每个轮廓的真实几何形状,从而通过轮廓逼近的输出结果判断一个对象是什么形状。

API

1
2
3
4
5
6
7
8
9
10
11
void cv::approxPolyDP(
InputArray curve,
OutputArray approxCurve,
double epsilon,
bool closed
)
其中
Curve表示轮廓曲线
approxCurve 表示轮廓逼近输出的顶点数目
epsilon 轮廓逼近的顶点距离真实轮廓曲线的最大距离,该值越小表示越逼近真实轮廓
close 表示是否为闭合区域

代码(c++,python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
Mat src = imread("../images/contours.png");
if (src.empty()) {
cout << "could not load image.." << endl;
}
imshow("input", src);

// 去噪声与二值化
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);

// 轮廓发现与绘制
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
Scalar color = Scalar(255, 0, 0);
for (size_t t = 0; t < contours.size(); ++t) {
RotatedRect rrt = minAreaRect(contours[t]);
Point2f cpt = rrt.center;
circle(src, cpt, 2, Scalar(0, 255, 0), 2);

Mat result;
approxPolyDP(contours[t], result, 4, true);
if (result.rows == 6) {
putText(src, "poly", cpt, FONT_HERSHEY_SIMPLEX, .7, color);
}
if (result.rows == 3) {
putText(src, "triangle", cpt, FONT_HERSHEY_SIMPLEX, .7, color);
}
if (result.rows == 4) {
putText(src, "rectangle", cpt, FONT_HERSHEY_SIMPLEX, .7, color);
}
if(result.rows > 10) {
putText(src, "circle", cpt, FONT_HERSHEY_SIMPLEX, .7, color);
}
}

imshow("contours", src);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import cv2 as cv
import numpy as np

src = cv.imread("D:/images/contours.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)

# 轮廓发现
out, contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
rect = cv.minAreaRect(contours[c])
cx, cy = rect[0]
result = cv.approxPolyDP(contours[c], 4, True)
vertexes = result.shape[0]
if vertexes == 3:
cv.putText(src, "triangle", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
if vertexes == 4:
cv.putText(src, "rectangle", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
if vertexes == 6:
cv.putText(src, "poly", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
if vertexes > 10:
cv.putText(src, "circle", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
print(vertexes)


# 显示
cv.imshow("contours_analysis", src)
cv.imwrite("D:/contours_analysis.png", src)
cv.waitKey(0)
cv.destroyAllWindows()

结果

代码地址

github