雙目測距-原理及代碼實現
需求:使用雙目攝像頭得出物體3D坐標,本質就是利用雙目來得到深度信息。
github代碼
0 知識掃盲
- 相機模型
- 四大坐標關系及其關系
1 相機標定
- Q1:用MATLAB標定還是opencv標定?
A1:兩種我都試了。總結來說,直接影響標定結果的好壞的因素是圖片質量,在圖片質量較好的情況下,兩者結果基本一樣。
- Q2:是兩個相機一起標定還是單獨標定?
A2:MATLAB 和 OPENCV中都有單目標定和雙目標定(MATLAB版本>2014)的方式。題主采用的方案是opencv分開標, MATLAB一起標。opencv分開標的主要原因是利用opencv cv2.stereoCalibrate()
使用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代碼
雙目測距-原理及代碼實現