在过去的一段时间内,我也实现了几篇关于立体匹配的学术论文,程序最终的显示效果却远不如论文中呈现的效果,可是自己编写的程序是严格按照论文中的步骤和参数设置的,为什么?经过上网查找资料和阅读论文,发现了其中一个原因。如果程序真没问题,可能是论文中没有介绍额外的处理步骤,即一些后续处理步骤(post-processing),比如左右一致性检测(left-right consistency,LRC)。
遮挡介绍:顾名思义是指一些点只出现在一幅图像中,而在另一幅图像中看不到。在立体匹配算法中如果不针对遮挡区域做一些特殊处理是不可能通过单幅图像提供的有限信息得到遮挡点的正确视差的。遮挡点通常是一块连续的区域。
LRC:作用是实现遮挡检测,得到左图对应的遮挡图像。具体做法:根据左右两幅输入图像,分别得到左右两幅视差图。对于左图中的一个点p,求得的视差值是d1,那么p在右图中的对应点应该是(p-d1),其视差值记作d2.若|d1-d2|>threshold,p标记为遮挡点。
遮挡过滤:得到二值遮挡图像,就要为所有黑色的遮挡点赋予合理的视差值。对于左图而言,遮挡点一般存在于背景区域和前景区域接触的地方。遮挡的产生正是因为前景比背景的偏移量更大,从而将背景遮盖。具体赋值方法:对于一个遮挡点p,分别水平往左和往右找到第一个非遮挡点,记作pl、pr。点p的视差值赋成pl和pr视差值中较小的那一个值。d(p)=min(d(pl),d(pr))。
中值滤波:这种简单的遮挡过滤在遮挡区域赋值方面效果显著,但是对初始视差的合理性和精度依赖较高。而且会出现类似于动态规划算法的水平条纹,所以其后常常跟着一个中值滤波步骤以消除条纹。
代码如下(有问题可以问我):
#include <math.h> #include "highgui.h" #include "cv.h" #include "time.h" #include <iostream> #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) int main() { clock_t start,finish; unsigned long seconds; printf("LRC"); start=clock(); IplImage* leftImg; IplImage* rightImg; int scale; int w,h,nchs,step,depth; leftImg=cvLoadImage("LLAW.png",-1); rightImg=cvLoadImage("RRAW.png",-1); scale=16; depth=leftImg->depth; w=leftImg->width; h=leftImg->height; nchs=leftImg->nChannels; step=leftImg->widthStep/sizeof(uchar); // 最终图像 IplImage * result=cvCreateImage(cvSize(w,h),8,1); int x,y,zeroNUm; int p_d_1,p_d_2; for(y=0;y<h;y++) //y: row for(x=0;x<w;x++) //x: column { p_d_1 = (uchar)leftImg->imageData[y*step+x*nchs]; p_d_1 = p_d_1/16; if(x-p_d_1<0) { result->imageData[y*step+x*nchs]=0; break; } p_d_2 = (uchar)rightImg->imageData[y*step+(x-p_d_1)*nchs]; p_d_2 = p_d_2/16; if (abs(p_d_1-p_d_2)>1) { result->imageData[y*step+x*nchs]=0; } else result->imageData[y*step+x*nchs]=p_d_1; } zeroNUm = 0; for(y=0;y<h;y++) for(x=0;x<w;x++) { int t = (uchar)result->imageData[y*step+x*nchs]; if (t==0) zeroNUm++; } printf("\nzeroNum:%d",zeroNUm); for(int y=0;y<h;y++) for(int x=0;x<w;x++) { int tem = (uchar)result->imageData[y*step+x*nchs]; if(tem==0) { int lp,rp; lp = rp = 0; int lx,rx; lx = x; rx = x; if(lx-1<0) lp= (uchar)result->imageData[y*step+lx*nchs]; while((lp==0)&&( lx-1 >= 0 )) lp = (uchar)result->imageData[y*step+(--lx)*nchs]; if(rx+1>=w) rp = (uchar)result->imageData[y*step+rx*nchs]; while((rp==0)&&(rx+1<w)) rp = (uchar)result->imageData[y*step+(++rx)*nchs]; //result->imageData[y*step+x*nchs]=max(lp,rp); result->imageData[y*step+x*nchs]=(lp+rp)/2; } } zeroNUm = 0; for(int y=0;y<h;y++) for(int x=0;x<w;x++) { result->imageData[y*step+x*nchs] *=16; int t = (uchar)result->imageData[y*step+x*nchs]; if (t==0) { zeroNUm++; } } cvSmooth(result,result,CV_MEDIAN,3,0,0); // 花费的计算时间 finish=clock(); seconds = (finish-start)/CLOCKS_PER_SEC; printf("\n\nAdaptWeight Finished! \nTime: %d分%d秒\n",seconds/60,seconds%60); printf("\nzeroNum:%d",zeroNUm); cvSaveImage("G:\\AW.png",result); cvNamedWindow("AW",1); cvShowImage("AW",result); cvNamedWindow("LAW",1); cvShowImage("LAW",leftImg); cvNamedWindow("RAW",1); cvShowImage("RAW",rightImg); cvWaitKey(0); cvReleaseImage(&leftImg); cvReleaseImage(&rightImg); cvReleaseImage(&result); return 0; }
我的测试结果: