解决模板图和基准图之间存在任意角度旋转的景象匹配问题的关键是找到一个旋转不变量, 圆投影匹配算法就是利用“圆”的各向同性和投影特征提出来的。传统的图像匹配算法,如归一化交叉互相关算法,主要利用像素点与像素点之间的相关性计算匹配图像与模板之间的相关度。这种方法在匹配图像与模板之间存在一定选择角度的时候,正确率会随着旋转角度的增加而迅速下降。当旋转角度大于5度的时候就会完全失效。于是圆投影算法被提出。
应用到实际中基于圆投影矢量和的旋转不变量检测(点击进入查看文献)
上面基于圆投影矢量和的模板匹配文献算法实现代码如下:
//圆投影
void CircularProjection(int rectW, int rectH)
{
//模板大小为TW*TW,TW为奇数
// 用于存放模板中每个像素点距离模板中心的距离
int *r=new int[TW*TW];
#define r(ROW,COL) r[TW*(ROW)+(COL)]
//相关变量
int y,x;
double dis;
//离散数字圆
for (y=0; y<TW; y++)
{
for (x=0; x<TW; x++)
{
dis=(x-TW/2)*(x-TW/2)+(y-TW/2)*(y-TW/2);
r(y,x)=(int)(sqrt(dis)+0.5);
}
}
//统计半径为r的圆上有多少个点
int i,j;
int R=(TW-1)/2;
int *Sr=new int[R+1];
memset(Sr,0,(R+1)*sizeof(int));
//存放实部模板
double *tepReal=new double[TW*TW];
//存放虚部模板
double *tepVirtual=new double[TW*TW];
#define PI 3.1415926
#define tepReal(ROW,COL) tepReal[TW*(ROW)+(COL)]
#define tepVirtual(ROW,COL) tepVirtual[TW*(ROW)+(COL)]
//统计半径为r的圆上有多少个点
for(i=0; i<TW; i++)
{
for (j=0; j<TW; j++)
{
if (r(i,j)<=R)
{
Sr[r(i,j)]++;
}
}
}
//创建模板
for(i=0; i<TW; i++)
{
for (j=0; j<TW; j++)
{
if (r(i,j)>R)
{
tepReal(i,j)=0;
tepVirtual(i,j)=0;
}
else
{
tepReal(i,j)=cos(-2*PI*r(i,j)/(R+1))/Sr[r(i,j)];
tepVirtual(i,j)=sin(-2*PI*r(i,j)/(R+1))/Sr[r(i,j)];
}
}
}
//模板圆投影向量和
unsigned char *lpSrc;
// 计算灰度图像每行的字节数
long LineBytes = (m_imgWidth*m_nBitCount/8+3)/4*4;
double *It=new double[TW*TW];
double *Itreal=new double[TW*TW];
double *Itvirtual=new double[TW*TW];
#define It(ROW,COL) It[TW*(ROW)+(COL)]
#define Itreal(ROW,COL) Itreal[TW*(ROW)+(COL)]
#define Itvirtual(ROW,COL) Itvirtual[TW*(ROW)+(COL)]
//将模板图像copy至It存储
for (i=0; i<TW; i++)
{
for (j=0; j<TW; j++)
{
//pTop为模板左上角坐标
int y=pTop.y+i;
int x=pTop.x+j;
lpSrc=m_pImgData+LineBytes*(m_imgHeight-1-y)+x;
It(i,j)=double(*lpSrc);
}
}
Itreal=Template(It,TW,TW,tepReal,TW,TW);
Itvirtual=Template(It,TW,TW,tepVirtual,TW,TW);
//原目标图像含有多个目标,先图像分割,然后匹配子图,imgNum为目标个数
for (int n=0; n<imgNum; n++)
{
//子图宽
imgW=seg.Vrect[n].right-seg.Vrect[n].left;
//子图高
imgH=seg.Vrect[n].bottom-seg.Vrect[n].top;
//储存子图灰度值
double *I=new double[imgW*imgH];
double *Ireal=new double[imgW*imgH];
double *Ivirtual=new double[imgW*imgH];
#define I(ROW,COL) I[imgW*(ROW)+(COL)]
#define Ireal(ROW,COL) Ireal[imgW*(ROW)+(COL)]
#define Ivirtual(ROW,COL) Ivirtual[imgW*(ROW)+(COL)]
POINT ptcenter;
//将图像灰度值复制到I中
for(i = 0; i <imgH; i++)
{
for(j = 0; j <imgW; j++)
{
int ptY=seg.Vrect[n].top+i;
int ptX=seg.Vrect[n].left+j;
lpSrc=m_pImgData+LineBytes*(m_imgHeight-1-ptY)+ptX;
//将256级灰度图像转化为double型
I(i,j)=double(*lpSrc);
}
}
Ireal=Template(I,imgW, imgH, tepReal, TW, TW);
Ivirtual=Template(I, imgW, imgH, tepVirtual, TW, TW);
double distance=0;
double Mindis=9000000;
for (i=TW/2; i<imgH-TW/2; i++)
{
for (j=TW/2; j<imgW-TW/2; j++)
{
//圆投影矢量和
distance=pow((Ireal(i,j)-Itreal(TW/2,TW/2)),2)
+pow((Ivirtual(i,j)-Itvirtual(TW/2,TW/2)),2);
if (distance<Mindis)
{
Mindis=distance;
ptcenter.y=seg.Vrect[n].top+i;
ptcenter.x=seg.Vrect[n].left+j;
}
}
}
//粗定位中心
roughcenter.push_back(ptcenter);
}
}
转载请注明出处!http://blog.csdn.net/lsh_2013/article/details/44627817
原文:http://blog.csdn.net/lsh_2013/article/details/44627817