-计算轮廓的矩和Hu矩,通过比较Hu矩的形状匹配来判断轮廓是否相似
1. 理论基础
• 在图像的矩(Moments)理论中,对于一个平面区域(在这种情况下是图像中的轮廓),零阶矩表示轮廓的面积。一阶矩和用于计算轮廓的质心坐标。
• 质心(也称为重心)的坐标计算公式为,坐标计算公式为。
2. 在OpenCV中的实现
• 在OpenCV的Moments结构中,m00、m10和m01分别对应理论中的、和。
• 所以,在OpenCV的这个代码环境下,只要是通过moments函数计算得到的Moments对象,计算轮廓质心坐标的方式就是固定的m10/m00(坐标)和m01/m00(坐标),这是基于数学原理和OpenCV库对矩的定义来确定的。
double cx = mm.m10 / mm.m00;
double cy = mm.m01 / mm.m00;
代码演示
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void found_demo(Mat& image, vector<vector<Point>>& sky);
int main(int argc, char** argv) {
Mat sqw, swe, ser;
Mat src1 = imread("C:/newword/image/6.png");
Mat src2 = imread("C:/newword/image/7.png");
if (src1.empty() || src2.empty()) {
printf("no");
return -1;
}
//imshow("1", src1);
//imshow("2", src2);
vector<vector<Point>>sky1;
vector<vector<Point>>sky2;
found_demo(src1, sky1);
found_demo(src2, sky2);
Moments mm2 = moments(sky2[0]);
Mat hu2;
HuMoments(mm2, hu2);
for (size_t t = 0; t < sky1.size(); t++) {
Moments mm1 = moments(sky1[t]);
double cx = mm1.m10 / mm1.m00;
double cy = mm1.m01 / mm1.m00;
circle(src1, Point(cx, cy), 3, Scalar(0, 0, 255), 2, 8, 0);
Mat hu1;
HuMoments(mm1, hu1);
double dist = matchShapes(hu1, hu2, CONTOURS_MATCH_I1, 0);
if (dist < 1.0) {
printf("matched distance value : %.2f\n", dist);
drawContours(src1, sky1, t, Scalar(255, 0, 0), 2, 8, 0);
}
}
imshow("sss", src1);
waitKey(0);
return 0;
}
void found_demo(Mat& image, vector<vector<Point>>& sky)
{
Mat dsv, dsk, dsb;
GaussianBlur(image, dsv, Size(3, 3), 0);
cvtColor(dsv, dsk, COLOR_BGR2GRAY);
threshold(dsk, dsb, 0, 255, THRESH_BINARY | THRESH_OTSU);
vector<Vec4i>sea;
findContours(dsb, sky, sea, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
}