Opencv之利用matchshape算子实现简单的形状匹配

Opencv之利用matchshape算子实现简单的形状匹配

算子:

matchShapes( InputArray contour1, InputArray contour2, int method, double parameter )

(1)参数1是待匹配轮廓或者灰度图像

(2)参数2同参数1

(3)比较参数1和2相似度的方法,opencv提供了三种如下:

                CV_CONTOURS_MATCH_I1
                CV_CONTOURS_MATCH_I2
                CV_CONTOURS_MATCH_I3

(4)参数4为目前还不支持,使用时赋个0就ok。

针对三种匹配方法进行比较,结果如下:

形状匹配过程:

1. 将待识别图像 -> 灰度处理 -> 自动阈值分割

2. 通过轮廓检索函数 cv.findContours 找到待识别图像所有轮廓

3. 模板图像 -> 灰度图像 -> 自动阈值分割

4. 通过轮廓检索函数 cv.findContours 找到模板图像中目标的外轮廓

5. 将第2步得到的轮廓逐一和第4步得到的轮廓 通过 cv.matchShapes 函数进行形状匹配。找到其中最小值,最小值对应的待识别图像中的轮廓即为匹配到的模板图像

6. 标出在待识别图像中找到的模板图像

注意利用mathshape得到的匹配分值越小,则两个轮廓越相似,越大则越不相似。在匹配过程中会通过匹配分值与设定的分值进行比较,在保证匹配效果完美的情况下,设定的分值越低越好,如果设定的匹配分值略高,可能会导致两个完全不相似的形状匹配成功(亲身实验,分值设高,利用三角形会匹配到圆形)。

另外,matchShapes函数其实比较的是两个轮廓的Hu不变矩。Hu矩特性:具有旋转,缩放和平移不变性。由Hu矩组成的特征量对图片进行识别,优点就是速度很快,缺点是识别率比较低。 因此Hu不变矩一般用来识别图像中大的物体,对于物体的形状描述得比较好,图像的纹理特征不能太复杂

示例:

利用matchshape方法寻找下图中的圆形。

代码:

(1)创建形状轮廓模板

vector<Point> ImageTemplateContours(Mat img_template)
{
	//灰度化
	Mat gray_img_template;
	cvtColor(img_template, gray_img_template, COLOR_BGR2GRAY);

	//阈值分割
	Mat thresh_img_template;
	threshold(gray_img_template, thresh_img_template, 0, 255, THRESH_OTSU);
	//膨胀处理
	Mat ellipse = getStructuringElement(MORPH_ELLIPSE, Size(15, 15));
	Mat erode_img_template;
	//erode(thresh_img_template, erode_img_template, ellipse);
	morphologyEx(thresh_img_template, thresh_img_template, MORPH_OPEN, ellipse, Point(-1, -1), 1);

	//寻找边界
	vector<vector<Point>> contours_template;
	vector<Vec4i> hierarchy;
	findContours(thresh_img_template, contours_template, hierarchy, RETR_LIST, CHAIN_APPROX_NONE, Point());

	//绘制边界
	drawContours(img_template, contours_template, 0, Scalar(0, 0, 255), 1, 8, hierarchy);


	return contours_template[0];
}

注:之所以返回findContours算子发现的所有轮廓中的第0个,这是因为第0个就是我想要的圆形模板

(2)进行形状模板匹配

vector<Point2d> ShapeTemplateMatch(Mat image, vector<Point> imgTemplatecontours, double minMatchValue)
{
	vector<Point2d> image_coordinates;
	//灰度化
	Mat gray_img;
	cvtColor(image, gray_img, COLOR_BGR2GRAY);

	//阈值分割
	Mat thresh_img;
	threshold(gray_img, thresh_img, 0, 255, THRESH_OTSU);
	
	//寻找边界
	vector<vector<Point>> contours_img;
	vector<Vec4i> hierarchy;
	findContours(thresh_img, contours_img, hierarchy, RETR_LIST, CHAIN_APPROX_NONE, Point());
	//根据形状模板进行匹配
	int min_pos = -1;
	double	min_value = minMatchValue;//匹配分值,小于该值则匹配成功
	for (int i = 0; i < contours_img.size(); i++)
	{
	        //计算轮廓面积,筛选掉一些没必要的小轮廓
		if (contourArea(contours_img[i])>12000)
		{
	                //得到匹配分值 
			double value = matchShapes(contours_img[i], imgTemplatecontours, CONTOURS_MATCH_I3, 0.0);
	                //将匹配分值与设定分值进行比较 
			if (value < min_value)
			{
				min_pos = i;
				//绘制目标边界
				drawContours(image, contours_img, min_pos, Scalar(0, 0, 255), 1, 8, hierarchy, 0);

				//获取重心点
				Moments M;
				M = moments(contours_img[min_pos]);
				double cX = double(M.m10 / M.m00);
				double cY = double(M.m01 / M.m00);
				//显示目标中心并提取坐标点
				circle(image, Point2d(cX, cY), 1, Scalar(0, 255, 0), 2, 8);
				//putText(image, "center", Point2d(cX - 20, cY - 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 1, 8);
	                        //将目标的重心坐标都存在数组中 
				image_coordinates.push_back(Point2d(cX, cY));//向数组中存放点的坐标
			}
		}
	}
	return image_coordinates;
}

参考文章: opencv 利用cv.matchShapes()函数实现图像识别技术

                   OpenCV学习(33) 轮廓的特征矩Moment

                 【OpenCV学习笔记】之图像轮廓特征与图像的矩

猜你喜欢

转载自blog.csdn.net/Kevin_Sun777/article/details/111395898