OpenCV4(C++)——模板匹配

matchTemplate

模板匹配和卷积运算大致相同,模板图类似于卷积核,从原图的左上角开始进行滑动窗口的操作,最后得到一个特征图,这个特征图里的数值就是每次计算得到的相似度,通用匹配方式,相似值是(0-1)之间。
(最简单的一个例子,用两张相同的图片传入模板匹配函数中,只会进行一次相似计算,最后得到的特征图数值为([1,])

  OpenCV中的模板匹配函数为matchTemplate,参数如下,其中的result就是得到的特征图,里面记录了每次匹配计算的相似度。

void cv::matchTemplate(InputArray image,
                       InputArray templ,
                       OutputArray result,
                       int  method, // 匹配方法:TM_SQDIFF、TM_CCORR、TM_CCOEFF等
                       InputArray mask = noArray()
                    )

  得到相似度特征图后,再找到其中最大的值(或自定义一个阈值)的坐标,根据模板图的宽高,就能找到在原图的所在位置。
下面是最大值的例子:

int main()
{
	cv::Mat image = cv::imread("C:/Users/Opencv/temp/yuan.png");
	cv::Mat matchImg = cv::imread("C:/Users/Opencv/temp/match.png");

	if (image.empty() || matchImg.empty()) {
		cout << "打开图片失败" << endl;
		return -1;
	}

	cv::Mat result;
	cv::matchTemplate(image, matchImg, result, cv::TM_CCOEFF_NORMED);

	double maxVal, minVal;
	cv::Point minLoc, maxLoc;
	//寻找匹配结果中的最大值和最小值以及坐标位置
	minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
	// 绘制最佳匹配区域
	cv::rectangle(image, cv::Rect(maxLoc.x, maxLoc.y, matchImg.cols, matchImg.rows), cv::Scalar(0, 0, 255), 2);

	cv::imshow("原图", image);
	cv::imshow("模板图", matchImg);
	cv::imshow("结果图", result);
	cv::waitKey(0);
	cv::destroyAllWindows();

	return 0;
}


result图的数值为灰度值,最白的那个点就是匹配度最高的那个创建。再来看一下result里的数值
OpenCV4(C++)——模板匹配_第1张图片

  使用最大值的操作,只能匹配到一个位置。而在实际应用中,往往遇到的场景是一副图片中存在多个相似目标需要被找到,可以要设定阈值来进行判定。

代码如下(示例):

int main()
{
	cv::Mat img0 = cv::imread("C:/Users/jutze/ljw_C++/Opencv/temp/on.png");
	cv::Mat img1 = img0.clone();
	//cv::Mat img1;
	//cv::flip(img, img1, 0);
	cv::Mat img2 = img0.clone();
	cv::Mat img3 = img0.clone();
	cv::Mat out1, out2, image;
	cv::hconcat(img0, img1, out1);
	cv::hconcat(img2, img3, out2);
	cv::vconcat(out1, out2, image);

	cv::Mat matchImg = cv::imread("C:/Users/jutze/ljw_C++/Opencv/temp/onmatch.png");

	if (image.empty() || matchImg.empty()) {
		cout << "打开图片失败" << endl;
		return -1;
	}

	cv::Mat result;
	cv::matchTemplate(image, matchImg, result, cv::TM_CCOEFF_NORMED);


	float threshold = 0.85;
	cv::Mat Loc;
	cv::findNonZero(result >= threshold, Loc);  // 寻找大于阈值的点

	for (int i = 0; i < Loc.total(); i++)
	{
		cv::Point pt = Loc.at<cv::Point>(i);
		cv::rectangle(image, pt, cv::Point(pt.x + matchImg.cols, pt.y + matchImg.rows), cv::Scalar(0, 0, 255), 1);
	}

	cv::imshow("原图", image);
	cv::imshow("模板图", matchImg);
	cv::imshow("结果图", result);

	cv::waitKey(0);
	cv::destroyAllWindows();

	return 0;
}

OpenCV4(C++)——模板匹配_第2张图片
上面的图是作了一个拼接处理,但一般实际应用的图中,目标通常会存在一些旋转角度,尺寸大小不一致等问题,这些都会影响匹配结果,如下图所示。目前我自己所用到解决方式:一种是对原图进行旋转、缩放等相关处理。另一种是对模板图进行旋转、缩放等处理。都是通过多次匹配来进行,无疑会增加很大时间消耗,可能会有更好的办法吧,以后遇到再说。
OpenCV4(C++)——模板匹配_第3张图片

你可能感兴趣的:(opencv,c++,opencv)