距离变换是一种常见的二值图像处理算法,用来计算图像中任意位置到最近边缘点的距离,常见的距离测度函数有切削距离,街区距离和欧式距。切削距离和街区距离是欧式距离的一种近似。
基于距离变换的匹配的原理是计算模板图覆盖下的那块子图与模板图之间的距离,也就是计算子图中的边缘点到模板图中最近的边缘点的距离,这里采用欧式距离,并对欧式距离进行近似,认为与边缘4邻域相邻的点的距离为0.3,8邻域相邻的点的距离为0.7,不相邻的点的距离都为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_gray1, *src_gray2, *src_gray3; IplImage *temp_gray1, *temp_gray2, *temp_gray3; IplImage *Dist; uint8 TemplatePixelm10 = 0; uint8 TemplatePixelm01 = 0; uint8 TemplatePixeln01 = 0; uint8 TemplatePixeln10 = 0; uint8 TemplatePixelm1n1 = 0; uint8 TemplatePixelm1n0 = 0; uint8 TemplatePixelm0n1 = 0; uint8 TemplatePixelm0n0 = 0; 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); Dist = cvCreateImage(sz_T,IPL_DEPTH_8U,1); } void CalTemplateDist(IplImage* I,IplImage* Dist, long* Nb) //计算在模板图对应位置上的距离 { int i,j; float dis; 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==0) { dis = 0; (*Nb)++; } else { if( i==0 && j==0 ) //第一行第一个点 { TemplatePixelm10 = ptr[j+1]; TemplatePixeln10 = *( I->imageData + (i+1)*I->widthStep + j ); TemplatePixelm1n1 = *( I->imageData + (i+1)*I->widthStep + j+1 ); if( TemplatePixelm10==0 || TemplatePixeln10==0 ) dis = 0.3; else if( TemplatePixelm1n1==0 ) dis = 0.7; else dis = 1; } else if( i==0 && j>0 && j<(I->width-1) ) //第一行 { TemplatePixelm10 = ptr[j+1]; TemplatePixelm01 = ptr[j-1]; TemplatePixeln10 = *( I->imageData + (i+1)*I->widthStep + j ); TemplatePixelm1n1 = *( I->imageData + (i+1)*I->widthStep + j+1 ); TemplatePixelm0n1 = *( I->imageData + (i+1)*I->widthStep + j-1 ); if( TemplatePixelm10==0 || TemplatePixeln10==0 || TemplatePixelm01==0 ) dis = 0.3; else if( TemplatePixelm1n1==0 || TemplatePixelm0n1==0 ) dis = 0.7; else dis = 1; } else if( i==0 && j==(I->width-1) ) //第一行最后一个点 { TemplatePixelm01 = ptr[j-1]; TemplatePixeln10 = *( I->imageData + (i+1)*I->widthStep + j ); TemplatePixelm0n1 = *( I->imageData + (i+1)*I->widthStep + j-1 ); if( TemplatePixeln10==0 || TemplatePixelm01==0 ) dis = 0.3; else if( TemplatePixelm0n1==0 ) dis = 0.7; else dis = 1; } else if( j==0 && i>0 && i<(I->height-1) ) //第一列 { TemplatePixelm10 = ptr[j+1]; TemplatePixeln01 = *( I->imageData + (i-1)*I->widthStep + j ); TemplatePixeln10 = *( I->imageData + (i+1)*I->widthStep + j ); TemplatePixelm1n1 = *( I->imageData + (i+1)*I->widthStep + j+1 ); TemplatePixelm1n0 = *( I->imageData + (i-1)*I->widthStep + j+1 ); if( TemplatePixelm10==0 || TemplatePixeln10==0 || TemplatePixeln01==0 ) dis = 0.3; else if( TemplatePixelm1n1==0 || TemplatePixelm1n0==0 ) dis = 0.7; else dis = 1; } else if( i>0 && i<(I->height-1) && j==(I->width-1) ) //最后一列 { TemplatePixelm01 = ptr[j-1]; TemplatePixeln01 = *( I->imageData + (i-1)*I->widthStep + j ); TemplatePixeln10 = *( I->imageData + (i+1)*I->widthStep + j ); TemplatePixelm0n1 = *( I->imageData + (i+1)*I->widthStep + j-1 ); TemplatePixelm0n0 = *( I->imageData + (i-1)*I->widthStep + j-1 ); if( TemplatePixeln10==0 || TemplatePixelm01==0 || TemplatePixeln01==0 ) dis = 0.3; else if( TemplatePixelm0n1==0 || TemplatePixelm0n0==0 ) dis = 0.7; else dis = 1; } else if( j==0 && i==(I->height-1) ) //最后一行最后一个点 { TemplatePixelm10 = ptr[j+1]; TemplatePixeln01 = *( I->imageData + (i-1)*I->widthStep + j ); TemplatePixelm1n0 = *( I->imageData + (i-1)*I->widthStep + j+1 ); if( TemplatePixelm10==0 || TemplatePixeln01==0 ) dis = 0.3; else if( TemplatePixelm1n0==0 ) dis = 0.7; else dis = 1; } else if( j>0 && j<(I->width-1) && i==(I->height-1) ) //最后一行 { TemplatePixelm10 = ptr[j+1]; TemplatePixelm01 = ptr[j-1]; TemplatePixeln01 = *( I->imageData + (i-1)*I->widthStep + j ); TemplatePixelm1n0 = *( I->imageData + (i-1)*I->widthStep + j+1 ); TemplatePixelm0n0 = *( I->imageData + (i-1)*I->widthStep + j-1 ); if( TemplatePixelm10==0 || TemplatePixeln01==0 || TemplatePixelm01==0 ) dis = 0.3; else if( TemplatePixelm1n0==0 || TemplatePixelm0n0==0 ) dis = 0.7; else dis = 1; } else if( j==(I->width-1) && i==(I->height-1) ) //最后一行最后一个点 { TemplatePixelm01 = ptr[j-1]; TemplatePixeln01 = *( I->imageData + (i-1)*I->widthStep + j ); TemplatePixelm0n0 = *( I->imageData + (i-1)*I->widthStep + j-1 ); if( TemplatePixeln01==0 || TemplatePixelm01==0 ) dis = 0.3; else if( TemplatePixelm0n0==0 ) dis = 0.7; else dis = 1; } else { TemplatePixelm10 = ptr[j+1]; TemplatePixelm01 = ptr[j-1]; TemplatePixeln01 = *( I->imageData + (i-1)*I->widthStep + j ); TemplatePixeln10 = *( I->imageData + (i+1)*I->widthStep + j ); TemplatePixelm1n0 = *( I->imageData + (i-1)*I->widthStep + j+1 ); TemplatePixelm0n0 = *( I->imageData + (i-1)*I->widthStep + j-1 ); TemplatePixelm1n1 = *( I->imageData + (i+1)*I->widthStep + j+1 ); TemplatePixelm0n1 = *( I->imageData + (i+1)*I->widthStep + j-1 ); if( TemplatePixeln01==0 || TemplatePixelm01==0 || TemplatePixelm10==0 || TemplatePixeln10==0 ) dis = 0.3; else if( TemplatePixelm0n0==0 || TemplatePixelm1n0==0 || TemplatePixelm0n1==0 || TemplatePixelm1n1==0 ) dis = 0.7; else dis = 1; } } *(Dist->imageData + i*Dist->widthStep + j) = (uint8)(dis*255); } } } void dist_match(IplImage* src_img, IplImage* Dist,double MinMatch, CvPoint* pt, long* Na, long* Nb) //距离匹配 { int i,j,m,n; double SigmaGT; uint8 SrcValue; double DistValue; double Match; for ( i=0; i<(src_img->height - Dist->height); i++ ) { for ( j=0; j<( src_img->width - Dist->width ); j++ ) { SigmaGT = 0; *Na = 0; for( m=0; m<Dist->height; m++ ) { for( n=0; n<Dist->width; n++ ) { SrcValue = *( src_img->imageData + (i+m)*src_img->widthStep +j+n ); if(SrcValue==0) { DistValue = (double)*( Dist->imageData +m*Dist->widthStep + n )/255; SigmaGT += DistValue; (*Na)++; } } } if( (*Na) > (*Nb) ) { Match = ( SigmaGT + (*Na) - (*Nb) )/( (*Na) + (*Nb) ); } else { Match = ( SigmaGT + (*Nb) - (*Na) )/( (*Na) + (*Nb) ); } if( Match < MinMatch ) { MinMatch = Match; //距离匹配的最小值就是匹配的位置 pt->x = j; pt->y = i; } } } } int _tmain(int argc, _TCHAR* argv[]) { IplImage* src_img, *temp_img; //定义变量 double MinMatch = 1000; CvPoint MatchPoint = cvPoint(1,1); long Na=0,Nb=0; //像素0的个数 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); CalTemplateDist(temp_gray1, Dist, &Nb); dist_match(src_gray1, Dist, MinMatch, &MatchPoint, &Na, &Nb); cvRectangle(src_img, MatchPoint, cvPoint(MatchPoint.x+49, MatchPoint.y+39), cvScalar(0, 0, 255, 0), 1,8,0); cvNamedWindow("my picture",CV_WINDOW_AUTOSIZE); cvNamedWindow("my template",CV_WINDOW_AUTOSIZE); cvNamedWindow("my Dist",CV_WINDOW_AUTOSIZE); cvShowImage("my picture",src_img); cvShowImage("my template",temp_gray1); cvShowImage("my Dist",Dist); cvWaitKey(0); cvReleaseImage(&src_img); cvReleaseImage(&temp_img); cvReleaseImage(&src_gray1); cvReleaseImage(&src_gray2); cvReleaseImage(&src_gray3); cvReleaseImage(&temp_gray1); cvReleaseImage(&temp_gray2); cvReleaseImage(&temp_gray3); cvDestroyWindow("my picture"); cvDestroyWindow("my template"); return 0; }