1. 程式人生 > >立體匹配中常用的後處理-左右一致性處理

立體匹配中常用的後處理-左右一致性處理

在過去的一段時間內,我也實現了幾篇關於立體匹配的學術論文,程式最終的顯示效果卻遠不如論文中呈現的效果,可是自己編寫的程式是嚴格按照論文中的步驟和引數設定的,為什麼?經過上網查詢資料和閱讀論文,發現了其中一個原因。如果程式真沒問題,可能是論文中沒有介紹額外的處理步驟,即一些後續處理步驟(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;
}


我的測試結果: