雙目立體匹配——歸一化互相關(NCC)


  歸一化相關性,normalization cross-correlation,因此簡稱NCC,下文中筆者將用NCC來代替這冗長的名稱。

  NCC,顧名思義,就是用於歸一化待匹配目標之間的相關程度,注意這里比較的是原始像素。通過在待匹配像素位置p(px,py)構建3*3鄰域匹配窗口,與目標像素位置p'(px+d,py)同樣構建鄰域匹配窗口的方式建立目標函數來對匹配窗口進行度量相關性,注意這里構建相關窗口的前提是兩幀圖像之間已經校正到水平位置,即光心處於同一水平線上,此時極線是水平的,否則匹配過程只能在傾斜的極線方向上完成,這將消耗更多的計算資源。相關程度的度量方式由如下式子定義:

  

  上式中的變量需要解釋一下:其中p點表示圖像I1待匹配像素坐標(px,py),d表示在圖像I2被查詢像素位置在水平方向上與px的距離。如下圖所示: 

    

  左邊為圖像I1,右邊為圖像I2。圖像I1,藍色方框表示待匹配像素坐標(px,py),圖像I2藍色方框表示坐標位置為(px,py),紅色方框表示坐標位置(px+d,py)。(由於畫圖水平有限,只能文字和圖片雙重說明來完成了~)

  Wp表示以待匹配像素坐標為中心的匹配窗口,通常為3*3匹配窗口。

  沒有上划線的I1表示匹配窗口中某個像素位置的像素值,帶上划線的I1表示匹配窗口所有像素的均值。I2同理。

  上述公式表示度量兩個匹配窗口之間的相關性,通過歸一化將匹配結果限制在 [-1,1]的范圍內,可以非常方便得到判斷匹配窗口相關程度:

  若NCC = -1,則表示兩個匹配窗口完全不相關,相反,若NCC = 1時,表示兩個匹配窗口相關程度非常高。

  我們很自然的可以想到,如果同一個相機連續拍攝兩張圖像(注意,此時相機沒有旋轉也沒有位移,此外光照沒有明顯變化,因為基於原始像素的匹配方法通常對上述條件是不具備不變性的),其中有一個位置是重復出現在兩幀圖像中的。比如桌子上的一個可樂瓶。那么我們就可以對這個可樂瓶的位置做一下匹配。直觀的看,第一幀中可樂瓶上某一個點,它所構成鄰域窗口按理說應該是與第二幀相同的,就算不完全相同,也應該是具有非常高相關性的。基於這種感性的理解,於是才有前輩提出上述的NCC匹配方法。(純屬個人理解)

  


  雙目立體匹配,這一部分是說明NCC如何用於雙目匹配。

  假設有校正過的兩幀圖像I1,I2,由上述NCC計算流程的描述可知,對圖像I1一個待匹配像素構建3*3匹配窗口,在圖像I2極線上對每一個像素構建匹配窗口與待匹配像素匹配窗口計算相關性,相關性最高的視為最優匹配。很明顯,這是一個一對多的過程。如果圖像尺寸是640*480,則每一個像素的匹配過程是是1對640,兩幀圖像完全匹配需要計算640*480*640 = 196608000,即一億九千多萬次~ 盡管計算機計算速度非常快,但也着實是非常消耗計算資源的。由於NCC匹配流程是通過在同一行中查找最優匹配,因此它可以並行處理,這大概也算是一種彌補吧~

  雙目立體匹配流程如下:

  1. 采集圖像:通過標定好的雙目相機采集圖像,當然也可以用兩個單目相機來組合成雙目相機。(標定方法下次再說)

  2. 極線校正:校正的目的是使兩幀圖像極線處於水平方向,或者說是使兩幀圖像的光心處於同一水平線上。通過校正極線可以方便后續的NCC操作。

        

      2.1 由標定得到的內參中畸變信息中可以對圖像去除畸變,在OpenCV中有函數對去畸變做了實現

       void stereoRectify(InputArray cameraMatrix1, InputArray distCoeffs1, InputArray cameraMatrix2, InputArray distCoeffs2, Size imageSize, InputArray R,  InputArray T, OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags=CALIB_ZERO_DISPARITY,  double alpha=-1, Size newImageSize=Size(), Rect* validPixROI1=0, Rect* validPixROI2=0 )
       cameraMatrix1:第一個相機矩陣(這里我們是雙目的左相機).
         cameraMatrix2: 第二個相機矩陣(雙目的右相機).
         distCoeffs1:第一個相機畸變參數.
         distCoeffs2: 第二個相機畸變參數.
         imageSize:用於校正的圖像大小.
        R:第一和第二相機坐標系之間的旋轉矩陣(左相機相對於右相機的旋轉)
        T:第一和第二相機坐標系之間的平移矩陣(左相機相對於右相機的位移)
       R1:輸出第一個相機的3x3矯正變換(旋轉矩陣) .
       R2:輸出第二個相機的3x3矯正變換(旋轉矩陣) .
       P1:在第一台相機的新的坐標系統(矯正過的)輸出 3x4 的投影矩陣
       P2:在第二台相機的新的坐標系統(矯正過的)輸出 3x4 的投影矩陣
       Q:輸出深度視差映射矩陣
       flags:操作的 flag可以是零或者是CV_CALIB_ZERO_DISPARITY。如果設置了CV_CALIB_ZERO_DISPARITY,函數的作用是使每個相機的主點在校正后的圖像上有相同的像素坐標;如果未設置標志,功能還可以改變圖像在水平或垂直方向(取決於極線的方向)來最大化有用的圖像區域。
       alpha:自由縮放參數。如果是-1或沒有,該函數執行默認縮放。否則,該參數應在0和1之間。alpha=0,校正后的圖像進行縮放和偏移,只有有效像素是可見的(校正后沒有黑色區域);alpha= 1意味着校正圖像的抽取和轉移,所有相機原始圖像素像保留在校正后的圖像(源圖像像素沒有丟失)。顯然,任何中間值產生這兩種極端情況之間的中間結果。
          newImageSize:校正后新的圖像分辨率。
       validPixROI1: 校正后的圖像可選的輸出矩形,里面所有像素都是有效的。如果alpha= 0,ROIs覆蓋整個圖像。否則,他們可能會比較小。
       validPixROI2: 校正后的圖像可選的輸出矩形,里面所有像素都是有效的。如果alpha= 0,ROIs覆蓋整個圖像。否則,他們可能會比較小。
      
      2.2 通過校正函數校正以后得到相機的矯正變換R和新的投影矩陣P,接下來是要對左右視圖進行去畸變,並得到重映射矩陣。這里,我們還是用OpenCV函數
       void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix,  Size size, int m1type, OutputArray map1, OutputArray map2 )
       cameraMatrix:輸入的攝像機內參數矩陣
       distCoeffs:輸入的攝像機畸變系數矩陣
       R:輸入的第一和第二相機坐標系之間的旋轉矩陣(我們這里是利用上述校正得到的旋轉矩陣)
       newCameraMatrix:輸入的校正后的3X3攝像機矩陣(我們這里是使用上述校正得到的投影矩陣)
       size:攝像機采集的無失真圖像尺寸
       m1type:map1的數據類型,可以是CV_32FC1或CV_16SC2
       map1:輸出的X坐標重映射參數
       map2:輸出的Y坐標重映射參數
      2.2 根據上述得到的重映射參數map1,map2,我們需要進一步對原始圖像進行重映射到新的平面中才能去除圖像畸變,同樣,實現方式仍是使用現有的OpenCV函數

                    void remap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation, intborderMode = BORDER_CONSTANT, const Scalar& borderValue = Scalar() )

      src:輸入圖像,即原圖像,需要單通道8位或者浮點類型的圖像

      dst:輸出圖像,即目標圖像,需和原圖形一樣的尺寸和類型

      map1:它有兩種可能表示的對象:(1)表示點(x,y)的第一個映射;(2)表示CV_16SC2,CV_32FC1等類型的x值矩陣

      map2:它有兩種可能表示的對象:(1)若map1表示點(x,y)時,這個參數不代表任何值;(2)表示CV_16UC1,CV_32FC1等類型y值矩陣

      interpolation:插值方式,有四中插值方式:(1)INTER_NEAREST——最近鄰插值,(2)INTER_LINEAR——雙線性插值(默認),(3)INTER_CUBIC——雙三樣條插值(默認),(4)INTER_LANCZOS4——lanczos插值(默認)

      intborderMode :邊界模式,默認BORDER_CONSTANT

      borderValue :邊界顏色,默認Scalar()黑色

      2.3 通過上述兩步操作,我們成功地對圖像去除了畸變,並且校正了圖像極線。注意,在立體校正階段需要設置alpha = 0才能完成對圖像的裁剪,否則會有黑邊。

  3. 特征匹配:這里便是我們利用NCC做匹配的步驟啦,匹配方法如上所述,右視圖中與左視圖待測像素同一水平線上相關性最高的即為最優匹配。完成匹配后,我們需要記錄其視差d,即待測像素水平方向xl與匹配像素水平方向xr之間的差值d = x- xl,最終我們可以得到一個與原始圖像尺寸相同的視差圖D。

  4. 深度恢復:通過上述匹配結果得到的視差圖D,我們可以很簡單的利用相似三角形反推出以左視圖為參考系的深度圖。計算原理如下圖所示:
        

        如圖,Tx為雙目相機基線,f為相機焦距,這些可以通過相機標定步驟得到。而x- xl就是視差d。

        通過公式 z = f * Tx / d可以很簡單地得到以左視圖為參考系的深度圖了。

  至此,我們便完成了雙目立體匹配。倘若只是用於圖像識別,那么到步驟3時已經可以結束了。


  OK,最后一部分就是代碼實現部分了,哎~ 寫太累了,下次再補上。

  未完待續。。。

  

      

 

 

        

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM