图像匹配之最小均方误差匹配

最小均方误差匹配方法是以模板中的特征点构造矩阵X,图像子图的特征点构造矩阵Y,然后求解矩阵X到矩阵Y的变换矩阵,均方误差最小的位置为最佳匹配位置。

图像之间的仿射变换方程为:


仿射变换参数表示为:


所以,根据n对特征点的位置,矩阵X和Y定义为:


图像匹配之最小均方误差匹配_第1张图片

仿射变换参数的求解公式为:


最小均方误差的公式为:


至此,误差最小的位置,便是匹配的位置。

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;
}

图像匹配之最小均方误差匹配_第2张图片

你可能感兴趣的:(opencv,图像处理,图像匹配,最小均方误差匹配)