轉載請說明出處:http://blog.csdn.net/zhubaohua_bupt/article/details/51866567算法
這段時間對opencvSGBM半全局立體匹配算法進行了比較細緻的研究,現總結一下。函數
本文先描述一下opencvSGBM算法流程,接着給出調用opencvSGBM須要設置參數的含義、數值選取以及運行效果,最後貼出opencvSGBM源碼。測試
第一部分:SGBM算法研究總結:ui
整個算法實現分爲spa
1預處理.net
2代價計算blog
3動態規劃(默認4條路徑)源碼
4後處理it
這四個步驟。下面分別說明一下各個步驟:io
Step1:SGBM採用水平Sobel算子,把圖像作處理,公式爲:
Sobel(x,y)=2[P(x+1,y)-P(x-1,y)]+ P(x+1,y-1)-P(x-1,y-1)+ P(x+1,y+1)-P(x-1,y+1)
Step2:用一個函數將通過水平Sobel算子處理後的圖像上每一個像素點(P表示其像素值
)映射成一個新的圖像:PNEW表示新圖像上的像素值。
映射函數:
preFilterCap 爲一個常數參數,opencv缺省狀況下取15,例程中取63。
預處理其實是獲得圖像的梯度信息。
經預處理的圖像保存起來,將會用於計算代價
代價有兩部分組成:
1通過預處理獲得的圖像的梯度信息通過基於採樣的方法獲得的梯度代價
2原圖像通過基於採樣的方法獲得的SAD代價
上述兩個代價都會在SAD窗口內進行計算。
關於什麼是基於採樣的方法,參考論文:DepthDiscontinuities by Pixel-to-Pixel Stereo 在計算代價的時候,用基於採樣的方法效果會好一些。
規劃公式:
默認4條路徑,其中動態規劃很重要兩個參數P1,P2是這樣設定的:
P1 =8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
cn是圖像的通道數, SADWindowSize是SAD窗口大小,數值爲奇數。
能夠看出,當圖像通道和SAD窗口肯定下來,SGBM的規劃參數P1和P2是常數。
opencvSGBM的後處理包含如下幾個步驟:
Step1:惟一性檢測:視差窗口範圍內最低代價是次低代價的(1 + uniquenessRatio/100)倍時,最低代價對應的視差值纔是該像素點的視差,不然該像素點的視差爲0。其中uniquenessRatio是一個常數參數。
Step2:亞像素插值:
插值公式:
Step3:左右一致性檢測:偏差閾值disp12MaxDiff默認爲1,能夠本身設置。
OpencvSGBM計算右視差圖的方式:
經過獲得的左視察圖計算右視差圖
圖1經過獲得的左視察圖計算右視差圖
這個時候dispR[X-d]是d仍是d+n?
實際上,dispR[X-d]的肯定方式是比較dispL中X和X+n出的最小代價,選代價最小的對應的視差做爲最優視差。
肯定右圖視差後,經過這樣一個措施來肯定左視察圖中的像素視差是否有效:
| dispR[X-d]-dispL[X]|<disp12MaxDiff&&| dispR[X-d-1]- dispL[X]-1|<disp12MaxDiff (條件1)
若是這個條件成立,就是誤匹配點。
這個條件成立,爲何就是誤匹配點呢?
實際上這個條件(LRcheck)檢測的大都是遮擋點,好比圖1中,左視差圖X和X+n處按照圖一規則都會映射到右視差圖的X-d處,若在左視差圖中,X位置是遮擋點,那麼左視差圖X位置的最小代價必定會比X+n處大(由於X處根本找不到匹配,所謂最小代價也是很大的),這樣dispR[X-d]=d+n。
如今開始用條件1來檢測左視差圖的誤匹配點。
先解釋一下條件1左側的條件:檢測到X處(遮擋誤匹配點),發現dispR[x-d]=d+n,並非d。所以就會符合條件1中的dispR[X-d]-dispL[X]|<disp12MaxDiff,
親測把條件1變成dispR[X-d]-dispL[X]|<disp12MaxDiff檢測效果和條件1幾乎無差異。
再解釋一下條件1右側的條件:
條件1的另外一部分(| dispR[X-d-1]-dispL[X]-1|<disp12MaxDiff)是用來檢測右視差圖在X-d處的視差值是否連續,若是左視差圖X處是遮擋誤匹配點,那麼dispL[X]中的d是不許確的,所以dispR[X-d]=d也是不許確的,即不能保證dispR[X-d-1]處視差值和d很相近,故右視差圖在X-d處的視差值是不連續的。
綜上,在左視察圖中,若是一個像素點是遮擋誤匹配點,那麼就會符合條件1。於是就會被檢測出來。
Step4:連通區域的檢測:簡述:對左右一致性檢測後的視差圖再一次檢測誤匹配點,根據與當前處理的視差點知足連通條件的像素點個數來判斷當前處理的視差點是不是誤匹配點,個數小於一個閾值就認爲是誤匹配點。
方法:循環遍歷每個像素點,對每個視差像素點d而言,檢測其周圍(上下左右)的視差是否知足這樣的條件(稱爲視差連通條件):
1, 首先是LRcheck後,視差有效的點
2, 和中心視差值的(變化)絕對值不超過speckleRange。注:speckleRange是一個常數參數,能夠本身設定。Opencv例程中speckleRange=10.
對於一個視差點:
Step1:當上下左右(如下簡稱周圍)點至少有一個視差點知足視差連通條件後,再分別以它們爲起點(稱爲傳播),檢測其周圍(前向傳播的點不算,好比,Pixel2是經過Pixel1傳播過來的,即Pixel2確定是Pixel1周圍的點。再以Pixel2爲起點檢測周圍的視差點是否知足視差連通條件時,Pixel1雖然也是Pixel2周圍的視差點,但不算知足視差連通條件)的視差點是否知足視差連通條件。
Step2:每檢測到一個新的連通點,其相應點的標誌位置1,,計數器加一,直到對於每個新的連通點,其周圍的點(標誌位置1的點也不算知足視差連通條件)都不知足視差連通條件。中止計數。
Step3:判斷計數值(即和當前處理的視差點的連通區域的像素點個數)>speckleWindowSize?(注:speckleWindowSize是一個常數參數,能夠本身設定。Opencv例程中speckleRange=100。)若大於,視差值認爲有效,不然認爲當前視差值是噪點。
連通區域檢測有助於去除經LR和惟一性檢測後殘餘的噪點,效果比較理想。
第二部分:opencvSGBM算法的參數含義及數值選取
一 預處理參數
1:preFilterCap:水平sobel預處理後,映射濾波器大小。默認爲15
int ftzero =max(params.preFilterCap, 15) | 1;
opencv測試例程test_stereomatching.cpp中取63。
二 代價參數
2:SADWindowSize:計算代價步驟中SAD窗口的大小。由源碼得,此窗口默認大小爲5。
SADWindowSize.width= SADWindowSize.height = params.SADWindowSize > 0 ?params.SADWindowSize : 5;
注:窗口大小應爲奇數,通常應在3x3到21x21之間。
3:minDisparity:最小視差,默認爲0。此參數決定左圖中的像素點在右圖匹配搜索的起點。int 類型
4:numberOfDisparities:視差搜索範圍,其值必須爲16的整數倍(CV_Assert( D % 16 == 0 );)。最大搜索邊界= numberOfDisparities+ minDisparity。int 類型
三 動態規劃參數
動態規劃有兩個參數,分別是P一、P2,它們控制視差變化平滑性的參數。P一、P2的值越大,視差越平滑。P1是相鄰像素點視差增/減 1 時的懲罰係數;P2是相鄰像素點視差變化值大於1時的懲罰係數。P2必須大於P1。須要指出,在動態規劃時,P1和P2都是常數。
5:opencv測試例程test_stereomatching.cpp中,P1 = 8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
6:opencv測試例程test_stereomatching.cpp中,P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
四:後處理參數
7:uniquenessRatio:惟一性檢測參數。對於左圖匹配像素點來講,先定義在numberOfDisparities搜索區間內的最低代價爲mincost,次低代價爲secdmincost。若是知足
即說明最低代價和次第代價相差過小,也就是匹配的區分度不夠,就認爲當前匹配像素點是誤匹配的。
opencv測試例程test_stereomatching.cpp中,uniquenessRatio=10。int 類型
8:disp12MaxDiff:左右一致性檢測最大允許偏差閾值。int 類型
opencv測試例程test_stereomatching.cpp中,disp12MaxDiff =1。
9:speckleWindowSize:視差連通區域像素點個數的大小。對於每個視差點,當其連通區域的像素點個數小於speckleWindowSize時,認爲該視差值無效,是噪點。
opencv測試例程test_stereomatching.cpp中,speckleWindowSize=100。
10:speckleRange:視差連通條件,在計算一個視差點的連通區域時,當下一個像素點視差變化絕對值大於speckleRange就認爲下一個視差像素點和當前視差像素點是不連通的。
opencv測試例程test_stereomatching.cpp中,speckleWindowSize=10。
運行效果:
源碼見opencvSGBM半全局立體匹配算法的研究(2)