最小均方误差匹配方法是以模板中的特征点构造矩阵X,图像子图的特征点构造矩阵Y,然后求解矩阵X到矩阵Y的变换矩阵,均方误差最小的位置为最佳匹配位置。
图像之间的仿射变换方程为:
仿射变换参数表示为:
所以,根据n对特征点的位置,矩阵X和Y定义为:
仿射变换参数的求解公式为:
最小均方误差的公式为:
至此,误差最小的位置,便是匹配的位置。
opencv实现的程序如下:
#include "stdafx.h"
#include
#include "highgui.h"
#include
typedef unsigned long uint32;
typedef unsigned int uint16;
typedef unsigned char uint8;
IplImage *src_img, *temp_img; //定义变量
IplImage *src_gray1, *src_gray2, *src_gray3;
IplImage *temp_gray1, *temp_gray2, *temp_gray3;
CvMat *X, *XT, *XTX, *_XTX, *_XTXXT, *Y, *Alpha, *XAlpha, *Y_XAlpha; //定义矩阵
int mt[16][2];
double MinE2 = 10000;
CvPoint MatchPoint = cvPoint(1,1);
void AllocateImage(IplImage* I,IplImage* T) //给图像分配大小
{
CvSize sz = cvGetSize(I);
CvSize sz_T = cvGetSize(T);
src_gray1 = cvCreateImage( sz, IPL_DEPTH_8U, 1); //原图的三个通道
src_gray2 = cvCreateImage( sz, IPL_DEPTH_8U, 1);
src_gray3 = cvCreateImage( sz, IPL_DEPTH_8U, 1);
temp_gray1 = cvCreateImage( sz_T, IPL_DEPTH_8U, 1); //模板的三个通道
temp_gray2 = cvCreateImage( sz_T, IPL_DEPTH_8U, 1);
temp_gray3 = cvCreateImage( sz_T, IPL_DEPTH_8U, 1);
}
void AllocateMatrix(int dim)
{
X = cvCreateMat( 2*dim, 4, CV_64FC1 );
XT = cvCreateMat( 4, 2*dim, CV_64FC1 );
XTX = cvCreateMat( 4, 4, CV_64FC1 );
_XTX = cvCreateMat( 4, 4, CV_64FC1 );
_XTXXT = cvCreateMat( 4, 2*dim, CV_64FC1 );
Y = cvCreateMat( 2*dim, 1, CV_64FC1 );
Alpha = cvCreateMat( 4, 1, CV_64FC1 );
XAlpha = cvCreateMat( 2*dim, 1, CV_64FC1 );
Y_XAlpha = cvCreateMat( 2*dim, 1, CV_64FC1 );
}
void DeallocateImage()
{
cvReleaseImage(&src_img);
cvReleaseImage(&temp_img);
cvReleaseImage(&src_gray1);
cvReleaseImage(&src_gray2);
cvReleaseImage(&src_gray3);
cvReleaseImage(&temp_gray1);
cvReleaseImage(&temp_gray2);
cvReleaseImage(&temp_gray3);
cvReleaseMat(&X);
cvReleaseMat(&XT);
cvReleaseMat(&XTX);
cvReleaseMat(&_XTX);
cvReleaseMat(&_XTXXT);
cvReleaseMat(&Y);
cvReleaseMat(&Alpha);
cvReleaseMat(&XAlpha);
cvReleaseMat(&Y_XAlpha);
}
int CalTemplateFeature(IplImage* I)
{
int i,j,k=0;
for ( i=0; iheight; i++ )
{
uint8* ptr = (uint8*)( I->imageData + i*I->widthStep );
for ( j=0; jwidth; j++ )
{
uint8 Pixel = ptr[j];
if(Pixel == 255)
{
mt[k][0] = j;
mt[k][1] = i;
k++;
if(k>16) return k;
}
}
}
return k;
}
void GenerateMatrix()
{
int i,j;
for ( i=0; irows; i++ ) //给矩阵X赋值
{
//uint8* ptr = (uint8*)( X->data.ptr + i*X->step );
for ( j=0; jcols; j++ )
{
switch(j)
{
case 0:
if(i%2 == 0) //奇数行
cvSetReal2D(X,i,j,mt[i/2][0]);
else //偶数行
cvSetReal2D(X,i,j,mt[i/2][1]);
break;
case 1:
if(i%2 == 0)
cvSetReal2D(X,i,j,mt[i/2][1]);
else
cvSetReal2D(X,i,j,-mt[i/2][0]);
break;
case 2:
if(i%2 == 0)
cvSetReal2D(X,i,j,1);
else
cvSetReal2D(X,i,j,0);
break;
case 3:
if(i%2 == 0)
cvSetReal2D(X,i,j,0);
else
cvSetReal2D(X,i,j,1);
break;
default:
break;
}
}
} //X
for(i=0; irows; i++) //给XT赋值
{
for(j=0; jcols; j++)
{
cvSetReal2D(XT,j,i,cvGetReal2D(X,i,j));
}
} //XT
cvMatMul(XT,X,XTX); //计算XTX
cvInvert(XTX, _XTX, CV_SVD); //计算XTX的逆矩阵
cvMatMul(_XTX,XT,_XTXXT); //计算XTX逆矩阵与XT的乘积
}
void MMSE_Match(IplImage* src_img, IplImage* temp_img, int dim)
{
int i,j,num,m,n,u;
double temp,value,E2,a,b,c,d,e,f,g,h;
for ( i=0; i<(src_img->height - temp_img->height); i++ )
{
for ( j=0; j<( src_img->width - temp_img->width ); j++ )
{
num=0;
for( m=0; mheight; m++ )
{
for( n=0; nwidth; n++ )
{
uint8 SrcValue = *( src_img->imageData + (i+m)*src_img->widthStep +j+n );
if(SrcValue == 255)
{
if(num == dim*2)
{
num++;
break;
}
cvSetReal1D(Y, num, n);
num++;
cvSetReal1D(Y, num, m);
num++;
}
}
if(num > dim*2) break;
}
//特征点个数一致进行匹配
if(num == dim*2)
{
cvMatMul( _XTXXT, Y, Alpha ); //计算Alpha
cvMatMul( X, Alpha, XAlpha );
cvSub( Y, XAlpha, Y_XAlpha, NULL );
temp = 0;
for( u=0; u<(2*dim); u++ )
{
value = cvGetReal1D( Y_XAlpha, u );
temp += value*value;
}
E2 = temp;
if( E2 < MinE2)
{
MinE2 = E2;
MatchPoint.x = j+cvGetReal1D(Alpha, 2) ;
MatchPoint.y = i+cvGetReal1D(Alpha, 3) ;
}
}
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int dim;
src_img = cvLoadImage("Images/最小均方误差.bmp"); //读入两幅图
temp_img = cvLoadImage("Images/最小均方误差模板.bmp");
AllocateImage( src_img, temp_img );
cvSplit( src_img, src_gray1, src_gray2, src_gray3, 0); //将两幅三通道图像分解为3幅单通道图像
cvSplit( temp_img, temp_gray1, temp_gray2, temp_gray3, 0);
dim = CalTemplateFeature(temp_gray1); //获取模板图中的特征点个数和位置
AllocateMatrix(dim); //矩阵大小初始化
GenerateMatrix(); //生成一些矩阵
MMSE_Match(src_gray1, temp_gray1, dim); //最小均方误差匹配
cvRectangle(src_img, MatchPoint, cvPoint(MatchPoint.x+68, MatchPoint.y+68), cvScalar(0, 0, 255, 0), 1,8,0);
cvNamedWindow("my picture",CV_WINDOW_AUTOSIZE);
cvNamedWindow("my template",CV_WINDOW_AUTOSIZE);
cvShowImage("my picture",src_img);
cvShowImage("my template",temp_gray1);
cvWaitKey(0);
DeallocateImage();
cvDestroyWindow("my picture");
cvDestroyWindow("my template");
return 0;
}