【46】【OpenCv】模板匹配问题

OpenCv提供cv::matchTemplate()进行模板匹配,该函数不基于直方图,而是使用一个图像块在输入图像上进行“滑动”,并使用设置的匹配方法进行比较。

函数声明:

void cv::matchTemplate(
	cv::InputArray image,  // input image to be searched,8U or 32F, size W-by-H
	cv::InputArray temp1,  // template to use,same type as 'image',size w-by-h
	cv::OutputArray result,  // result image, type32F,size (W-w+0)-by-(H-h+1)
	int method  // comparsion method to use
);

参数image是输入的要匹配的图片,类型是8为或浮点型灰度或彩色图。

参数temp1是匹配的模板,包含给定的物体。

参数result是结果图像,是单通道,大小为(image.width - temp1.width+1, image.height - temp1.height+1)的以整数字节或浮点存储的图片。

参数method可以设置为如下的方法,每种方法都有一个归一化的版本。归一化的版本可以降低模板和图片之间由于光照不同引起的效果。

如下公式中I表示输入图像,T表示模板,R表示输出的结果图像

1. 方差匹配方法 cv::TM_SQDIFF g归一化版本cv::TM_SQDIFF_NORMED

以方差为依据进行匹配,完全匹配结果为0,不匹配会得到一个很大的值。

R_{sq-diff} = \sum_{x^{'},y^{'}}^{}[T(x^{'},y^{'}) - I(x + x^{'},y+y^{'})]^{2}

R_{sq-diff-normed} = \frac{\sum_{x^{'},y^{'}}^{}[T(x^{'},y^{'}) - I(x+x^{'},y+y^{'})]^{2}}{\sqrt{\sum_{x^{'},y^{'}}^{}T(x^{'},y^{'})^{2} \cdot \sum_{x^{'},y^{'}}^{} I(x+x^{'},y+y^{'})^{2}}}

2. 相关性匹配方法 cv::TM_CCORR/cv::TM_CCORR_NORMED

相关性匹配方式以相乘的方式进行模板匹配,完全匹配得到一个很大的值,不匹配得到一个很小的值或0。

R_{ccorr} = \sum_{x^{'},y^{'}}^{}T(x^{'},y^{'})\cdot I(x+x^{'},y+y^{'})

R_{ccorr-normed} = \frac{\sum_{x^{'},y^{'}}^{}[T(x^{'},y^{'}) \cdot I(x+x^{'},y+y^{'})]^{2}}{\sqrt{\sum_{x^{'},y^{'}}^{}T(x^{'},y^{'})^{2} \cdot \sum_{x^{'},y^{'}}^{} I(x+x^{'},y+y^{'})^{2}}}

3. 相关系数匹配方法 cv::TM_CCOEFF/cv::TM_CCOEFF_NORMED

相关系数匹配方法对模板相对于其平均值的变化和图片相对于其平均值的变化进行匹配。完全匹配得到1,完全无匹配得到-1。如果用随机图片匹配得到0,表示两张图片毫无关联。

R_{ccoeff} = \sum_{x^{'},y^{'}}^{}T^{'}(x^{'},y^{'})\cdot I^{'}(x+x^{'},y+y^{'})

R_{ccoeff-normed} = \frac{\sum_{x^{'},y^{'}}^{}T^{'}(x^{'},y^{'})\cdot I^{'}(x+x^{'},y+y^{'})}{\sqrt{\sum_{x^{'},y^{'}}^{}T'(x^{'},y^{'})^{2} \cdot \sum_{x^{'},y^{'}}^{} I'(x+x^{'},y+y^{'})^{2}}}

T^{'}(x',y') = T(x',y') - \frac{\sum_{x^{n},y^{n}} T(x^{n},y^{n})}{(w-h)}

I^{'}(x+x',y+y') = I(x+x',y+y') - \frac{\sum_{x^{n},y^{n}} I(x^{n},y^{n})}{(w-h)}

通常情况下,从一个相对简单的度量方法(方差)换程一个更复杂的度量方法(相关系数)时,会得到更精确的结果(以更长的计算时间为代价)。

cv::matchTemplate()获得result后,可以使用cv::minMaxLoc()或着cv::minMaxIdx()找到最优匹配出现的位置。

为了避免随机性引起的该位置恰好匹配的很好,期望在找到最优匹配的邻域内也有不错的匹配结果。好的匹配点附近也应该有很好的匹配值。可以在寻找最优匹配值之前,先对结果进行轻微的平滑。

如下代码读入模板图片和要匹配的图片,分别使用6种方法进行匹配,匹配结果标示在原图中。

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

using namespace cv;
using namespace std;

int main(int argc,char *argv[])
{

	cv::Mat src,temp1,ftemp[6];

	// 读取匹配模板
	temp1 = cv::imread(argv[1],cv::IMREAD_COLOR);
	if(temp1.empty())
	{
		cout << "Load image faile," << argv[1] << endl;
		return -1;
	}

	// 读取图像
	src = cv::imread(argv[2],cv::IMREAD_COLOR);
	if(src.empty())
	{
		cout << "Load image faile," << argv[2] << endl;
		return -1;
	}
	

	double maxval,minval;
	cv::Point ptmin,ptmax;
	cv::Point pt;
	cv::imshow("template",temp1);
	const char *szMethod[] = {
		"SQDIFF",
		"SQDIFF_NORMED",
		"CCORR",
		"CCORR_NORMED",
		"CCOEFF",
		"CCOEFF_NORMED"
	};
	cv::Mat srctmp,tmpblur;
	for(int i=0;i<6;i++)
	{
		srctmp = src.clone();
		cv::matchTemplate(src,temp1,ftemp[i],i);
		cv::normalize(ftemp[i],ftemp[i],1,0,cv::NORM_MINMAX);

		// 平滑处理
		cv::blur(ftemp[i],tmpblur,cv::Size(3,3));
		cv::minMaxLoc(tmpblur,&minval,&maxval,&ptmin,&ptmax);
		pt=ptmin;
		if(i > 1)
			pt=ptmax;
		cv::rectangle(srctmp,cv::Rect(pt.x,pt.y,temp1.cols,temp1.rows),cv::Scalar(0,0,255),2,8);
		cv::imshow("image",srctmp);
		cv::imshow(szMethod[i],ftemp[i]);

		cv::waitKey(0);
	}

	cv::waitKey(0);

	return 0;

}

模板图片:

要匹配的图片:

匹配结果:

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值