1. 程式人生 > >雙目測距-原理及代碼實現

雙目測距-原理及代碼實現

point ray strong .html block 顯示 情況 及其 ref

需求:使用雙目攝像頭得出物體3D坐標,本質就是利用雙目來得到深度信息。

github代碼

0 知識掃盲

  • 相機模型
  • 四大坐標關系及其關系

1 相機標定

  • Q1:用MATLAB標定還是opencv標定?
  • A1:兩種我都試了。總結來說,直接影響標定結果的好壞的因素是圖片質量,在圖片質量較好的情況下,兩者結果基本一樣。

  • Q2:是兩個相機一起標定還是單獨標定?
  • A2:MATLAB 和 OPENCV中都有單目標定和雙目標定(MATLAB版本>2014)的方式。題主采用的方案是opencv分開標, MATLAB一起標。opencv分開標的主要原因是利用opencv cv2.stereoCalibrate()

    標出的兩相機間的RT矩陣實在偏差太大,所以采用了分開標定相機。而MATLAB計算的結果就相當好,示意圖和我實際擺放的相機位置基本一樣。

使用MATLAB標定。左右照片各15張(共采集19張,MATLAB識別出有效16張,手動刪除一張Mean Erro較大的圖)。記下 內參參數及兩相機間的RT矩陣。MATLAB 標定結果如下。設置棋盤格單位長度25mm。
技術分享圖片
可以看出標定出的的結果相機及棋盤的擺放位置與實際擺放接近。
技術分享圖片
圖中標定顯示棋盤與相機大概700~800mm的距離(棋盤格單位為25mm的前提下)。

2 計算3d坐標。

題主主要利用了opencv提供的
cv2.triangulatePoints()函數

'''
參數含義:
projMatr1   3x4 projection matrix of the first camera.
projMatr2   3x4 projection matrix of the second camera.
projPoints1 2xN array of feature points in the first image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1.
projPoints2 2xN array of corresponding points in the second image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1.
points4D    4xN array of reconstructed points in homogeneous coordinates.
'''
points4D = cv.triangulatePoints(projMatr1, projMatr2, projPoints1, projPoints2[, points4D])

可見關鍵步是計算出兩個投影矩陣, 然後將待測物體在左右相機成像的像素坐標代入即可得到3d坐標。原理、方法都很簡單。
投影矩陣的計算有兩種方式:

  • 1.采用立體標定的方案(opencv)。
    主要思路是cv2.stereoCalibrate()計算出R|T,將其代入cv2.stereoRectify()得到投影矩陣P1,P2。
    此時得到的P1 P2為:
    技術分享圖片
    P1 和P2 之間只差一個平移矩陣。與我們實際擺放的位置不符。實際擺放位置和MATLAB標定的結果類似。原因不清楚,然後采用了方案2計算投影矩陣。

  • 2 自己計算投影矩陣。即內參與外參的乘積。
    用圖片/stereo512/left.bmp /stereo512/right.bmp計算相機外參。使用了cv.solvePnP()函數

3.驗證.

將棋盤格左右像素坐標代入函數cv.triangulatePoints()得到棋盤格格點3d坐標.
MATLAB標定結果:
技術分享圖片
opencv標定結果:
技術分享圖片
可以看出在3維坐標的計算上,三個軸3d坐標與實際值相差都很小,並且opencv標註產生的均方誤差在三個軸均略優於MATLAB。

繼續驗證:
左相機視圖:
技術分享圖片
實物圖:
技術分享圖片

matlab標定給出的3d結果:
技術分享圖片

opencv標定給出的3d結果:
技術分享圖片
(結果比較接近,相差6mm。結果負值是坐標系原因。)
github代碼

雙目測距-原理及代碼實現