opencv Matchtemplate遍历原理以及有哪些优化?

时间:2022-06-09 23:12:15
opencv模板匹配函数的滑动窗口遍历是怎么个过程?看它源代码用了很多傅里叶变换,有点蒙了。有谁知道在优化过程中opencv模板匹配做了那些优化?
我自己写了个匹配函数,注释掉其他部分单纯保留窗口遍历部分耗时是上千秒。
图像是5000*3000规模,模板大小是256*256.
如果直接采用opencv模板匹配函数滑动窗口遍历图片到找到最匹配点也才十几秒。
主要遍历过程见下面(蓝色字体部分):
bool Cacluatesimilarity()
{
int i,j;
if (CircleR>0)
{
int y,step=CircleImage->widthStep;
if (expR==NULL)
{
SetExpR();
}
int inputNum=1;
double *ExpRdata,*TemplateFData,*TemplateData,*TemplateConjugateData,*srcExpRdata,*srcFData,*srcData;
while(inputNum<CircleR)
{
inputNum=inputNum*2;
}
ExpRdata=new double[inputNum*2];
TemplateFData =new double[inputNum*2];
TemplateData =new double[inputNum*2];
TemplateConjugateData =new double[inputNum*2];
srcExpRdata =new double[inputNum*2];
srcFData =new double[inputNum*2];
srcData =new double[inputNum*2];

//计算模板上部分卷积结果
for(i=0;i<CircleR;i++)
{
ExpRdata[2*i]=expR[i].re;
ExpRdata[2*i+1]=expR[i].im;
}
for(i=CircleR;i<inputNum;i++)
{
ExpRdata[2*i]=0.;
ExpRdata[2*i+1]=0.;
}

SetCgRT(Templatehighpoint); 
int cheight=CircleImage->height-CircleR*2-1,cwidth=CircleImage->width-CircleR*2-1;
for(i=0;i<cheight;i=i+StepDistance)
{
step=CircleImage->widthStep*i;
for (j=0;j<cwidth;j=j+StepDistance)
{
SetCgR(cvPoint(j,i));//之后进行匹配代码已删除。目的是实现快速圆投影匹配。这边是滑动窗口。具体见下面。 }
}
}
return true;
}



bool SetCgR(CvPoint center)
{
if (CircleR>0)
{
int i,j,r=CircleR*2,y,imagewidth=CircleImage->widthStep;
…………
for (i=0;i<r;i++)
{
y=(center.y+i)*imagewidth;
for (j=0;j<r;j++)
{
CgR[CircleProjection[i][j]] +=(uchar)CircleImage->imageData[y+center.x+j];//CircleProjection是一个存储窗口内各点相对于窗口中心点的半径坐标值。 }
}
}
return true;
}



bool SetCircleProjection()//窗口中的笛卡尔坐标坐标到极坐标映射(只算半径,角度无关所以没计算。)
{
if (CircleR>0)
{
int i,j;
int r=CircleR*2+1,y;
if(CircleProjection!=NULL)
{
for( i=0;i<r;i++)
{
delete[] CircleProjection[i];
}
delete[] CircleProjection;
}
CircleProjection=new int*[r];
for (i=0;i<r;i++)
{
CircleProjection[i]=new int[r];
}
CircleRNumer=0;
for(i=0;i<r;i++)
{
y=(i-CircleR)*(i-CircleR);
for(j=0;j<r;j++)
{
CircleProjection[i][j]=(int)(sqrt(y+(j-CircleR)*(j-CircleR)*1.0)+0.5);
if (CircleProjection[i][j]<=CircleR)
{
CircleRNumer++;
}
}
}
}
return true;
}

8 个解决方案

#1


不懂,帮顶

#2


看下啊!

#3


看了opencv书籍书中说了一个integral函数,用这个可以加快可变窗口相关计算。

#4


opencv 一般依靠tbb、ipp之类的加速。要是你机器上没有这些,那就是汇编代码级的优化。
opencv的算法都是大牛写的,会比一般的快。

#5


光靠ipp应该不会有100倍的提升吧。

#6


谁有关于图像处理专业的书籍。
有代码的最好是C那类代码。
没代码的最好是能有冈萨雷斯那本书差不多的水平或者行业应用相关书籍。

#7


引用 3 楼 yh880 的回复:
看了opencv书籍书中说了一个integral函数,用这个可以加快可变窗口相关计算。

跟这个无关,这个只是后续归一化时加速用。核心的是使用卷积原理:
cvDFT( _dft_img, _dft_img, CV_DXT_FORWARD, isz.height );
cvGetSubRect( dft_templ, dst,
cvRect(0,(templ_cn>1?yofs:0),dftsize.width,dftsize.height) );

cvMulSpectrums( _dft_img, dst, _dft_img, CV_DXT_MUL_CONJ );
cvDFT( _dft_img, _dft_img, CV_DXT_INVERSE, csz.height );

步骤如下:
1.将模板图像填补到和待匹配图像一样大小,补充的部分填0.进行傅里叶变换,下面称作傅里叶模板。(模板原始图像放在左上角,对应后面取值矩阵起始点也是左上角。)
2.将待匹配图像进行傅里叶变换。下面称为傅里叶图像。
3.将傅里叶模板与傅里叶图像进行傅里叶乘法。之后进行反变换。
4.在上述变换结果取相关矩阵大小(起始点参照1。)即为结果(使用cvMatchTemplate方法选取为CV_TM_CCORR,此时即为结果。其他方法则在此基础上增加了其他操作。)
因为 有补零影响,所以使用cvMatchTemplate得到的位置可能有偏差,建议得到这个结果后,自己再写for循环在附近点进行匹配计算结果。
欢迎大家继续来讨论。

#8


傅里叶变换成频域,用了卷积定理的特性,时域中得卷积等于频域中得乘积,再傅里叶反变换;得到的值就是时域中得卷积运算的值,该值就是相识值

#1


不懂,帮顶

#2


看下啊!

#3


看了opencv书籍书中说了一个integral函数,用这个可以加快可变窗口相关计算。

#4


opencv 一般依靠tbb、ipp之类的加速。要是你机器上没有这些,那就是汇编代码级的优化。
opencv的算法都是大牛写的,会比一般的快。

#5


光靠ipp应该不会有100倍的提升吧。

#6


谁有关于图像处理专业的书籍。
有代码的最好是C那类代码。
没代码的最好是能有冈萨雷斯那本书差不多的水平或者行业应用相关书籍。

#7


引用 3 楼 yh880 的回复:
看了opencv书籍书中说了一个integral函数,用这个可以加快可变窗口相关计算。

跟这个无关,这个只是后续归一化时加速用。核心的是使用卷积原理:
cvDFT( _dft_img, _dft_img, CV_DXT_FORWARD, isz.height );
cvGetSubRect( dft_templ, dst,
cvRect(0,(templ_cn>1?yofs:0),dftsize.width,dftsize.height) );

cvMulSpectrums( _dft_img, dst, _dft_img, CV_DXT_MUL_CONJ );
cvDFT( _dft_img, _dft_img, CV_DXT_INVERSE, csz.height );

步骤如下:
1.将模板图像填补到和待匹配图像一样大小,补充的部分填0.进行傅里叶变换,下面称作傅里叶模板。(模板原始图像放在左上角,对应后面取值矩阵起始点也是左上角。)
2.将待匹配图像进行傅里叶变换。下面称为傅里叶图像。
3.将傅里叶模板与傅里叶图像进行傅里叶乘法。之后进行反变换。
4.在上述变换结果取相关矩阵大小(起始点参照1。)即为结果(使用cvMatchTemplate方法选取为CV_TM_CCORR,此时即为结果。其他方法则在此基础上增加了其他操作。)
因为 有补零影响,所以使用cvMatchTemplate得到的位置可能有偏差,建议得到这个结果后,自己再写for循环在附近点进行匹配计算结果。
欢迎大家继续来讨论。

#8


傅里叶变换成频域,用了卷积定理的特性,时域中得卷积等于频域中得乘积,再傅里叶反变换;得到的值就是时域中得卷积运算的值,该值就是相识值