立体匹配中ZNCC的积分图加速方法

来源:互联网 发布:濮阳市智慧网络 编辑:程序博客网 时间:2024/04/29 10:27

本文主要讲三点:

1、ZNCC的原理;

2、ZNCC的积分图实现方法;

3、ZNCC编程中出现的一个小问题;

1.ZNCC的基本原理

立体匹配中最常用的一个相似性测度就是ZNCC(Zero-based Normalized Cross Correlation),ZNCC的数学公式为:

(公式1)

直接由公式1计算ZNCC存在大量冗余计算(比如重复求取平均值)。继续化简,得到:

(公式2)

公式2把ZNCC的冗余计算表现的非常直观了,显然,SI,SJ,SII,SJJ这四项是无需重复计算的。

那么,如何把SI,SII,SJ,SJJ保存起来呢?答案就是积分图。

2. ZNCC的积分图实现

积分图是由普通数字图像生成的一种属性图像,尺寸等于原始图像,而每个像素点保存由原始图像左上角和当前像素点确定的矩形范围的灰度值(也可以为图像的其他属性值)总和。下图是一个形象的表示,左图表示原始影像,右图表示相应的积分图像。

  

积分图的数学表达式为:

(公式3)

离散的实现公式为:


计算了积分图之后,ZNCC中的SI,SII,SJ,SJJ的计算公式为:


其中,l为半个窗口的尺寸。

生成积分图的代码如下:

void CalInteg(unsigned char *buf, unsigned long *DJ, unsigned long *DJJ){unsigned char *I = buf;*DJ=*I;*DJJ=(*I) * (*I);for (int j=1; j<width; j++)//第一行{*(DJ+j)=*(DJ+j-1)+*(I+j);*(DJJ+j)=*(DJJ+j-1)+*(I+j)* *(I+j);}int WH = width*height;for (int i=width; i<WH; i+=width)//第一列{*(DJ+i)=*(I+i)+ *(DJ+(i-width));*(DJJ+i)=*(I+i)* *(I+i)+ *(DJJ+(i-width));}for (int i=width; i<WH; i+=width){for(int j_index=1+i; j_index<width+i; j_index++){*(DJ+j_index)=*(I+j_index)+ *(DJ+j_index-width)+*(DJ+j_index-1)-*(DJ+j_index-width-1);*(DJJ+j_index)=*(I+j_index)* *(I+j_index)+ *(DJJ+j_index-width)+*(DJJ+j_index-1)-*(DJJ+j_index-width-1);}}}

用积分图计算ZNCC的代码如下:

sij = 0;int jd = j + d + disparity_begin;for (int m=-hwin;m<=hwin;m++){for(int n=-hwin;n<=hwin;n++){sij += bufl[(i+m)*width+jd+n]*bufr[(i+m)*width+j+n];}}si = bufl_i_integ[(i+hwin)*width+jd+hwin]-bufl_i_integ[(i+hwin)*width+jd-hwin-1]    -bufl_i_integ[(i-hwin-1)*width+jd+hwin]+bufl_i_integ[(i-hwin-1)*width+jd-hwin-1];sii = bufl_ii_integ[(i+hwin)*width+jd+hwin]-bufl_ii_integ[(i+hwin)*width+jd-hwin-1]    -bufl_ii_integ[(i-hwin-1)*width+jd+hwin]+bufl_ii_integ[(i-hwin-1)*width+jd-hwin-1];sj = bufr_i_integ[(i+hwin)*width+j+hwin]-bufr_i_integ[(i+hwin)*width+j-hwin-1]    -bufr_i_integ[(i-hwin-1)*width+j+hwin]+bufr_i_integ[(i-hwin-1)*width+j-hwin-1];sjj = bufr_ii_integ[(i+hwin)*width+j+hwin]-bufr_ii_integ[(i+hwin)*width+j-hwin-1]    -bufr_ii_integ[(i-hwin-1)*width+j+hwin]+bufr_ii_integ[(i-hwin-1)*width+j-hwin-1];float zncc = sqrt((float)(NUM*sii-si*si)*(NUM*sjj-sj*sj));if (zncc){cost = (NUM*sij-si*sj)/zncc;}else{cost = 0;}
3. ZNCC积分图实现中出现的一个小问题

由于积分图需要保存很大的数值,而且都是正数,我们很容易想到使用unsigned long来保存积分图像,这是合理且正确的,然而用积分图计算ZNCC时就要非常注意了,不能沿用原来的数据类型unsigned long了。比如上面的代码中我就继续使用了这样的定义方法

unsigned long sij,si,sii,sj,sjj;
结果最后的cost出现很多远远大于1的情况,我以为是积分图代码有问题导致的计算错误,找了很久没有找到错误所在。然后怀疑公式2是不是没有归一化,经过推导也没有问题。

最后,发现原来是NUM*sij-si*sj为负导致的!

所以,因此在采用积分图计算ZNCC时要注意用有符号的数据类型,因为ZNCC有可能取负值!

0 0
原创粉丝点击