模板匹配——数字图像处理学习四(C++版)

一、理论基础

        模板匹配技术是为了寻找子图像。对于大小为MxN的图像f(x,y)和大小为JxK的子图像w(x,y),f与w的相关可表示为:

\large c\left ( x,y \right )=\sum_{x=0}^{K}\sum_{t=0}^{J}w\left ( s,t \right )f\left ( x+s,y+t \right )

其种,x=0,1,2,…N-K,y=0,1,2,…M-J。

        此处的目的是寻找匹配而不是对f(x,y)进行滤波操作,因此w的原点被设置在子图像的左上角,并且公式给出的形式也完全适用于J和K 为偶数的情况。

        计算相关c(x,y)的过程就是在图像f(x,y)中逐点地移动子图像w(x,y),使w 的原点和点(x,y)重合,然后计算w与f中被w覆盖的图像区域对应像素的乘积之和,以此计算结果作为相关图像c(x,y)在(x,y)点的响应。相关可用于在图像f(x,y)中找到与子图像w(x,y)匹配的所有位置。实际上,当w按照上段中描述的过程移过整幅图像f之后,最大的响应点(x,y)即为最佳匹配的左上角点。我们
也可以设定一个阈值T,认为响应值大于该阈值的点均是可能的匹配位置。

        模板匹配相关公式:

\large r\left ( x,y \right )= \frac{\sum_{x=0}^{K}\sum_{t=0}^{J}w\left ( s,t \right )f\left ( x+s,y+t \right )}{\sqrt{\sum_{x=0}^{K}\sum_{t=0}^{J}f^{2}\left ( x+s,y+t \right )\cdot \sum_{x=0}^{K}\sum_{t=0}^{J}w^{2}\left ( s,t \right )}}

二、代码

例:

void MyFrame::OnPaint()
{

	CPaintDC dc(this);

	FILE* fp1;
	if (fopen_s(&fp1, "C:\\Users\\Administrator\\Desktop\\BMP1\\BMP1\\1.bmp", "rb") != 0) {
		return;
	}
	bmpFileHeader bfHead1;
	bmpInfoHeader biHead1;
	fread_s(&bfHead1, 14, 14, 1, fp1);
	fread_s(&biHead1, 40, 40, 1, fp1);
	uchar* p1 = (uchar*)malloc(biHead1.biSizeImage * sizeof(uchar));
	fseek(fp1, bfHead1.bfOffBits, SEEK_SET);
	fread_s(p1, biHead1.biSizeImage * sizeof(uchar), biHead1.biSizeImage * sizeof(uchar), 1, fp1);

	FILE* fp2;
	if (fopen_s(&fp2, "C:\\Users\\Administrator\\Desktop\\BMP1\\BMP1\\2.bmp", "rb") != 0) {
			return;
	}
	bmpFileHeader bfHead2;
	bmpInfoHeader biHead2;
	
	fread_s(&bfHead2, 14, 14, 1, fp2);
	fread_s(&biHead2, 40, 40, 1, fp2);

	uchar* p2 = (uchar*)malloc(biHead2.biSizeImage * sizeof(uchar));
	fseek(fp2, bfHead2.bfOffBits, SEEK_SET);
	fread_s(p2, biHead2.biSizeImage * sizeof(uchar), biHead2.biSizeImage * sizeof(uchar), 1, fp2);

	double dSumT=0; //模板元素的平方和
	double dSumS; //图像子区域元素的平方和
	double dSumST; //图像子区域和模板的点积    
	double R; //响应值
	double MaxR=0;//记录当前的最大响应
	//最大响应出现位置
	int nMaxX;
	int nMaxY;

	//计算2.bmp模板元素的平方和
	unsigned long x1 = 0;//原图
	unsigned long x2 = 0;//模板图

	x1 = 0;
	for (int i = 0; i < biHead1.biHeight; i++)
	{
		for (int j = 0; j < biHead1.biWidth; j++)
		{
			dc.SetPixel(j / time, (biHead1.biHeight - i) / time, RGB(p1[x1 + 2], p1[x1 + 1], p1[x1]));
			x1 += 3;
		}
	}


	for (int m = 0; m < biHead2.biHeight; m++)
	{
		for (int n = 0; n < biHead2.biWidth; n++)
		{
			// 模板图像第x个象素的灰度值,b通道
			dSumT += (double)p2[x2] * p2[x2];
			x2 = x2 + 3;
		}
	}

	//找到图像中最大响应的出现位置
	for (int i = 0; i < biHead1.biHeight - biHead2.biHeight + 1; i=i+ biHead2.biHeight/4)
	{
		for (int j = 0; j < biHead1.biWidth - biHead2.biWidth + 1; j++)
		{
			dSumST = 0;
			dSumS = 0;
			x2 = 0;
			for (int m = 0; m < biHead2.biHeight; m++)
			{
				x1 = 3 * (i * biHead1.biWidth + j) + 3 * m * biHead1.biWidth;
				for (int n = 0; n < biHead2.biWidth; n++)
				{
					// 原图像第i+m行,第j+n列象素的灰度值b通道
					int nGraySrc =p1[x1];
					x1 = x1 + 3;
					// 模板图像第m行,第n个象素的灰度值b通道
					int nGrayTpl = p2[x2];
					x2 = x2 + 3;
					dSumS += (double)nGraySrc * nGraySrc;
					dSumST += (double)nGraySrc * nGrayTpl;
				}
			}
			R = dSumST / (sqrt(dSumS) * sqrt(dSumT));//计算相关响应

			//与最大相似性比较
			if (R > MaxR)
			{
				MaxR = R;
				nMaxX = j;
				nMaxY = biHead1.biHeight - i;
			}
		}
	}
	//在原图上画框框
	dc.MoveTo(nMaxX / time, nMaxY / time);
	dc.LineTo((nMaxX + biHead2.biWidth) / time, nMaxY / time);
	dc.MoveTo(nMaxX / time, nMaxY / time);
	dc.LineTo(nMaxX / time, (nMaxY - biHead2.biHeight) / time);
	dc.MoveTo((nMaxX + biHead2.biWidth) / time, nMaxY / time);
	dc.LineTo((nMaxX + biHead2.biWidth) / time, (nMaxY - biHead2.biHeight) / time);
	dc.MoveTo(nMaxX / time, (nMaxY - biHead2.biHeight) / time);
	dc.LineTo((nMaxX + biHead2.biWidth) / time, (nMaxY - biHead2.biHeight) / time);
}

注意:匹配过程时间耗费过多,于是可以多跳过几个像素点,可以看到在for循环处

i=i+ biHead2.biHeight/4

结果:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值