最小均方误差匹配方法是以模板中的特征点构造矩阵X,图像子图的特征点构造矩阵Y,然后求解矩阵X到矩阵Y的变换矩阵,均方误差最小的位置为最佳匹配位置。
图像之间的仿射变换方程为:
仿射变换参数表示为:
所以,根据n对特征点的位置,矩阵X和Y定义为:
仿射变换参数的求解公式为:
最小均方误差的公式为:
至此,误差最小的位置,便是匹配的位置。
opencv实现的程序如下:
#include "stdafx.h" #include <opencv2/opencv.hpp> #include "highgui.h" #include <math.h> 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; i<I->height; i++ ) { uint8* ptr = (uint8*)( I->imageData + i*I->widthStep ); for ( j=0; j<I->width; 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; i<X->rows; i++ ) //给矩阵X赋值 { //uint8* ptr = (uint8*)( X->data.ptr + i*X->step ); for ( j=0; j<X->cols; 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; i<X->rows; i++) //给XT赋值 { for(j=0; j<X->cols; 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; m<temp_img->height; m++ ) { for( n=0; n<temp_img->width; 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; }