本系列代码托管于:https://github.com/chintsan-code/opencv4-tutorials

本篇使用的项目为:match_shapes

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

RNG rng(12345);
void contour_info(Mat &image, vector<vector<Point>> &contours);
int main(int argc, const char** argv) {
	Mat src1 = imread("../sample/abc.png");
	Mat src2 = imread("../sample/a.png");
	if (src1.empty() || src2.empty()) {
		cout << "could not load image..." << endl;
		return -1;
	}
	imshow("input1", src1);
	imshow("input2", src2);
	vector<vector<Point>> contours1;
	vector<vector<Point>> contours2;
	contour_info(src1, contours1);
	contour_info(src2, contours2);

	Moments mm2 = moments(contours2[0]);
	Mat hu2;
	HuMoments(mm2, hu2);

	for (size_t t = 0; t < contours1.size(); t++) {
		Moments mm = moments(contours1[t]);
		double cx = mm.m10 / mm.m00;  // 轮廓中心x
		double cy = mm.m01 / mm.m00;  // 轮廓中心y
		drawMarker(src1, Point(cx, cy), Scalar(255, 0, 0), MARKER_TILTED_CROSS, 10, 2, 8);
		Mat hu;
		HuMoments(mm, hu);
		double dist = matchShapes(hu, hu2, CONTOURS_MATCH_I1, 0);
		if (dist < 1.0) {
			printf("matched distance value : %.2f\n", dist);
			drawContours(src1, contours1, t, Scalar(0, 0, 255), 2, 8);
		}
	}
	imshow("match contours demo", src1);

	waitKey(0);
	destroyAllWindows();
	return 0;
}

void contour_info(Mat &image, vector<vector<Point>> &contours) {
	// 二值化
	Mat dst;
	GaussianBlur(image, dst, Size(3, 3), 0);
	Mat gray, binary;
	cvtColor(dst, gray, COLOR_BGR2GRAY);
	threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);

	// 轮廓发现
	vector<Vec4i> hirearchy;
	findContours(binary, contours, hirearchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
}

几何距

(1)n阶距
opencv4入门笔记(31):轮廓匹配-萤火

阶数:\(p+q\)

例如:

  • 0阶距:\(m_{00}\)
  • 1阶距:\(m_{10}、m_{01}\)
  • 2阶距:\(m_{11}、m_{20}、m_{02}\)
(2)中心距
opencv4入门笔记(31):轮廓匹配-萤火
(3)归一化中心矩
opencv4入门笔记(31):轮廓匹配-萤火
(4)Hu距:平移不变性、旋转不变性、放缩不变性
opencv4入门笔记(31):轮廓匹配-萤火

moments:计算几何距,最高计算3阶

Moments moments( InputArray array, bool binaryImage = false );
  • array:输入
  • binaryImage:如果为true,非0像素将会被视为1
  • @return:返回几何距信息
    • n阶距:m00, m10, m01, m20, m11, m02, m30, m21, m12, m03
      • 计算轮廓中心:
        • Xavg = m10 / m00
        • Yavg = m01 / m00
    • 中心距:mu20, mu11, mu02, mu30, mu21, mu12, mu03
    • 归一化中心距:nu20, nu11, nu02, nu30, nu21, nu12, nu03

HuMoments:计算Hu距

void HuMoments( const Moments& m, OutputArray hu );
  • m:输入的几何距
  • hu:输出的Hu距

matchShapes:轮廓匹配

double matchShapes( InputArray contour1, InputArray contour2, int method, double parameter );
  • contour1:输入的第一个轮廓或灰度图,如果要用基于Hu距的匹配,应该输入轮廓的Hu距
  • contour2:输入的第二个轮廓或灰度图,如果要用基于Hu距的匹配,应该输入轮廓的Hu距
  • method:比较方法,见下图。
    • CONTOURS_MATCH_I1
    • CONTOURS_MATCH_I2
    • CONTOURS_MATCH_I3
  • parameter:比较方法的特定参数(目前不支持),设为0即可
  • @return:匹配值,是一个距离,距离越小越相似
opencv4入门笔记(31):轮廓匹配-萤火