opencv-053-二值图像分析(使用Hu矩实现轮廓匹配)

知识点

对图像二值图像的每个轮廓,可以计算轮廓几何矩,根据几何矩可以计算图像的中心位置,估计得到中心位置可以计算中心矩、然后再根据中心矩可以计算胡矩。

OpenCV中可以通过如下的API一次计算出上述三种矩,API如下:

1
2
3
4
5
6
Moments cv::moments(
InputArray array,
bool binaryImage = false
)
array是输入的图像轮廓点集合
输出的图像几何矩

根据几何矩输出结果可以计算胡矩,胡矩计算的API如下:

1
2
3
4
5
6
void cv::HuMoments(
const Moments & moments,
double hu[7]
)
moments参数表示输入的图像矩
hu[7]表示输出的胡矩七个值

然后我们可以使用hu矩作为输入,对轮廓进行匹配,进行轮廓外形匹配的API如下:

1
2
3
4
5
6
7
8
9
10
11
12
double cv::matchShapes(
InputArray contour1,
InputArray contour2,
int method,
double parameter
)
contour1第一个轮廓点集合,或者灰度图像
contour2第二个轮廓点集合,或者灰度图像
method表示比较方法,最常见有
CONTOURS_MATCH_I1
CONTOURS_MATCH_I2
CONTOURS_MATCH_I3

代码(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
50
51
52
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void contours_info(Mat &image, vector<vector<Point>> &pts);

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

// 轮廓发现
vector<vector<Point>> contours1;
vector<vector<Point>> contours2;
contours_info(src, contours1);
contours_info(src2, contours2);

// 几何矩计算与hu矩计算
Moments mm2 = moments(contours2[0]);
Mat hu2;
HuMoments(mm2, hu2);

// 轮廓匹配
for (size_t t = 0; t < contours1.size(); ++t) {
Moments mm = moments(contours1[t]);
Mat hu;
HuMoments(mm, hu);
double dist = matchShapes(hu, hu2, CONTOURS_MATCH_I1, 0);
if (dist < 1) {
drawContours(src, contours1, t, Scalar(0,0,255), 2);
}
}

imshow("match_result", src);

waitKey(0);
return 0;
}

void contours_info(Mat &image, vector<vector<Point>> &pts) {
Mat gray, binary;
vector<Vec4i> hierarchy;
cvtColor(image, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
findContours(binary, pts, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
}
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
import cv2 as cv
import numpy as np


def contours_info(image):
gray = cv.cvtColor(image, 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)
return contours


src = cv.imread("D:/images/abc.png")
cv.namedWindow("input1", cv.WINDOW_AUTOSIZE)
cv.imshow("input1", src)
src2 = cv.imread("D:/images/a5.png")
cv.imshow("input2", src2)

# 轮廓发现
contours1 = contours_info(src)
contours2 = contours_info(src2)

# 几何矩计算与hu矩计算
mm2 = cv.moments(contours2[0])
hum2 = cv.HuMoments(mm2)

# 轮廓匹配
for c in range(len(contours1)):
mm = cv.moments(contours1[c])
hum = cv.HuMoments(mm)
dist = cv.matchShapes(hum, hum2, cv.CONTOURS_MATCH_I1, 0)
if dist < 1:
cv.drawContours(src, contours1, c, (0, 0, 255), 2, 8)
print("dist %f"%(dist))

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

结果

代码地址

github