模板匹配

模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术.

实现:

  • 我们需要2幅图像:

    1. 原图像 (I): 在这幅图像里,我们希望找到一块和模板匹配的区域
    2. 模板 (T): 将和原图像比照的图像块

    我们的目标是检测最匹配的区域:

  • 为了确定匹配区域, 我们不得不滑动模板图像和原图像进行 比较 :

  • 通过 滑动, 我们的意思是图像块一次移动一个像素 (从左往右,从上往下). 在每一个位置, 都进行一次度量计算来表明它是 “好” 或 “坏” 地与那个位置匹配 (或者说块图像和原图像的特定区域有多么相似).

  • 对于 T 覆盖在 I 上的每个位置,你把度量值 保存 到 结果图像矩阵 (R) 中. 在 R 中的每个位置  都包含匹配度量值:

    上图就是 TM_CCORR_NORMED 方法处理后的结果图像 R . 最白的位置代表最高的匹配. 正如您所见, 红色椭圆框住的位置很可能是结果图像矩阵中的最大数值, 所以这个区域 (以这个点为顶点,长宽和模板图像一样大小的矩阵) 被认为是匹配的.

  • 实际上, 我们使用函数 minMaxLoc 来定位在矩阵 R 中的最大值点 (或者最小值, 根据函数输入的匹配参数) .

opencv实现方法:

  • 使用OpenCV函数 matchTemplate 在模板块和输入图像之间寻找匹配,获得匹配结果图像
  • 使用OpenCV函数 minMaxLoc 在给定的矩阵中寻找最大和最小值(包括它们的位置).

归一化作用:

定义:标准化是将不同变化范围的值映射到相同的固定范围中,常见的是 [0,1],此时亦称归一化,也可以是[-1,1]范围。

形式:

min_max标准化:

也称为离差标准化,是对原始数据的线性变换,使结果值映射到[0 - 1]之间。转换函数如下:

2.Z-score标准化方法

这种方法给予原始数据的均值(mean)和标准差(standard deviation)进行数据的标准化。经过处理的数据符合标准正态分布,即均值为0,标准差为1,转化函数为:

作用:

1.无量纲化
例如房子数量和收入,从业务层知道这两者的重要性一样,所以把它们全部归一化,这是从业务层面上作的处理。

2.避免数值问题
不同的数据在不同列数据的数量级相差过大的话,计算起来大数的变化会掩盖掉小数的变化。

3.一些模型求解的需要
例如梯度下降法,如果不归一化,当学习率较大时,求解过程会呈之字形下降。学习率较小,则会产生直角形路线,不管怎么样,都不会是好路线。

4.时间序列
进行log分析时,会将原本绝对化的时间序列归一化到某个基准时刻,形成相对时间序列,方便排查。

5.收敛速度
加快求解过程中参数的收敛速度。

例子:

假设有两个变量,都是均匀分布,x1范围是[10000,20000],x2范围是[1,2]。有很多处于同一直线上的点,我们称这条直线为L。如果现在我们要做一个分类的话,x2几乎可以被忽略,x2很无辜的***掉了,仅仅因为所谓量纲的问题。即便x2不***掉,现在继续求解,来做梯度下降。 很显然,如果某一步我们求得的下降方向不在直线L上,几乎可以肯定肯定这步不会下降。这就会导致不收敛,或者收敛很慢。

模板匹配实例:

#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src1,src2, dst;
int value = 0;
int max_value = 5;
void demo(int, void*);
int main()
{
	src1 = imread("C:\\Users\\马迎伟\\Desktop\\heibao.jpg");
	src2 = imread("C:\\Users\\马迎伟\\Desktop\\heibao1.png");
	if (src1.empty())
	{
		printf("cannot load!!\n");
		system("pause");
		return -1;
	}
	namedWindow("src",CV_WINDOW_AUTOSIZE);
	namedWindow("output",CV_WINDOW_AUTOSIZE);
	createTrackbar("trackbar","output",&value,max_value,demo);
	demo(0, 0);
	//imshow("output", dst);
	waitKey(0);
	return 0;
}
void demo(int, void*)
{
	int dst_col = src1.cols - src2.cols + 1;
	int dst_row = src1.rows - src2.rows + 1;
	//dst必须规定是 这个尺寸和类型
	dst.create(Size(dst_col,dst_row),CV_32FC1);
	//模板匹配
	matchTemplate(src1,src2,dst,value,Mat());
	//归一化
	normalize(dst,dst,0,1,NORM_MINMAX,-1,Mat());
	double minval, maxval;
	Point minloc, maxloc, loc;
	//找到模板匹配的最大值最小值和位置
	minMaxLoc(dst,&minval,&maxval,&minloc,&maxloc,Mat());
	if (value==CV_TM_SQDIFF||value==CV_TM_SQDIFF_NORMED)
	{
		loc = minloc;
	}
	else
	{
		loc = maxloc;
	}
	rectangle(dst,Rect(loc.x,loc.y,src2.cols,src2.rows),Scalar(0,0,255),2,LINE_AA);
	rectangle(src1,Rect(loc.x, loc.y, src2.cols, src2.rows), Scalar(255, 255, 255), 2, LINE_AA);
	imshow("output",dst);
	imshow("src", src1);
}