opencv 模板匹配&&形状匹配


这是第四次作业要求

image-20220428142137548

所以今天就趁机会讲讲模板匹配,正好之前的项目有一部分重要工作就是和模板匹配紧密相关,对于今天作业来说,之前的项目难度更大,因为涉及到许多要考虑的因素,还要考虑效率实时性等问题。太详细的我也不方便展开,下面先看看之前的效果

17_50_13_9

17_50_13_9

当然也有其他的车型,视频就不放了直接上结果图

18_00_13_1

17_50_13_3

17_50_13_8

现在就正式开始解决今天这个作业

1. 找圆垫子

9_1

在上面视频拼车里模板都是在每一帧中取得,并且为了模板匹配能匹配得上还要预处理每一帧图片,调整模板区域、大小以及匹配方法。但是在拼车中我们只需要匹配一次,而作业中明显是需要多目标匹配的,并且待匹配目标的角度差异很大,在这种情况下使用opencv中的matchTemplate()效果肯定很差,至于为什么这可以从原理上解释。

image-20220428193221641

有兴趣的可以去看看相关资料,我就根据上图简单来说说模板匹配流程

  1. 得到原图和模板
  2. 滑动模板,与原图作对比
  3. 比较依据也就是评价指标如下图

image-20220428193436767

平方差方法匹配值越小越好,相关性方法匹配值越大越好,这样就会得到一个result矩阵,其中有最亮/最暗的地方就是我们匹配到的地方。利用minMaxLoc()找到这些地方,那也就代表找到了待匹配目标。

但是,我在上面也说过了,这些待匹配目标和模板的角度差异特别大,你用模板匹配最多也只能匹配出和模板一样大小、方向的待匹配目标。或者利用一堆复杂的操作,把模板图片进行角度变换搞一个任意角度都有的模板组然后再一一匹配,这个倒是可行,但是效率上不敢说。所以干脆换一种思路,不用模板匹配而是用形状去匹配。

匹配嘛就是根据相似性进行比较,上面已经说了因为角度导致模板匹配失效,那就得想办法排除掉角度干扰,最容易想到的就是利用某些角度不变特性的算子,所以很自然就想到HuMoments,关于Hu不变矩可以看看opencv的解释

image-20220428195311262

利用归一化中心矩构造了不变特征矩,这个对于平移,旋转都可以保持不变性,这不就是我们需要的吗?然后利用这个开始实现作业。

image-20220428195703459

image-20220428195730804

这是opencv中形状匹配的函数以及参数,我之前也没用过所以放在这一起学习一下。

1.1 得到模板

我们只有原图,并没有模板图。自己想去截图但是待匹配图之间挨得比较近,截下来的模板图不太容易找轮廓,因此直接在待匹配图操作,找到其中一个的轮廓作为模板。

vector<Point> TemplateContours(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);

	imshow("b", thresh_img_template);

	//膨胀处理
	Mat ellipse = getStructuringElement(MORPH_ELLIPSE, Size(15, 15));
	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_SIMPLE, Point());

	//绘制边界,查看是否是我们的目标轮廓
	drawContours(img_template, contours_template, 0, Scalar(0, 0, 255), 1, 8, hierarchy);
	imshow("img_template", img_template);
	waitKey(0);
	return contours_template[0];
}

image-20220428200330063

1.2 形状匹配

那个红色的圈就是每个圆形垫子的共有特征,然后根据这个圈作为模板轮廓对图像进行形状匹配,并根据设定的阈值排除掉不是相同形状物体的干扰。

void ShapeTemplateMatch(Mat image, vector<Point> imgTemplatecontours, double thresh)
{
	//灰度化
	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;

	for (int i = 0; i < contours_img.size(); i++)
	{
		//计算轮廓面积,筛选掉一些没必要的小轮廓
		// 根据计算面积以及可视化结果确定下面的阈值
		//cout << contourArea(contours_img[i]) << endl;
		if (contourArea(contours_img[i]) > 120)
		{
			//进行形状匹配,形状越相似value越小
			double value = matchShapes(contours_img[i], imgTemplatecontours, CONTOURS_MATCH_I3, 0.0);

			//查看value以及边界图得到thresh阈值
			//cout << value << endl;

			//将匹配分值与设定阈值比较 
			if (value < thresh)
			{
				min_pos = i;
				//绘制目标边界
				drawContours(image, contours_img, min_pos, Scalar(0, 255,0), 5, 8, hierarchy, 0);
				imshow("1", image);
			}
		}
	}
	waitKey(0);
}

image-20220428200455886

2. 找瓜子

9_2

和上面的函数一样,只是改了一下阈值

int main() {
	Mat src = imread("D:/9_2.jpg");
	resize(src, src, Size(src.cols / 4, src.rows / 4));
	vector<Point> tempContours =TemplateContours(src.clone());

	//圆垫阈值0.03,瓜子阈值0.2
	ShapeTemplateMatch(src.clone(),tempContours, 0.2);
	return 0;
}

image-20220428201530908

image-20220428201554768

  • 14
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shelgi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值