操作流程如下:
1.請配置好vs環境(此版本是vs2010+opencv2.4.3所寫,具體配置自己查吧。http://blog.csdn.net/garfielder007/article/details/50197181)
2.運作界面如下圖(很簡陋):
3.第一步點選采集棋盤圖按鈕,可以在本地電腦獲得兩個攝像頭的資料。
4.有了圖檔後,點選立體标定便開始處理,獲得标定所需的内外參數
5.點測距按鈕便可以進行實時測距(不是每次都需要點選采集棋盤格按鈕,如果圖檔了,直接就可以點選立體标定按鈕)
6.代碼裡要說明的兩點
a. opencv雙目測距Dlg.cpp 裡CvSize board_sz = cvSize( 8, 6);//此處8,6為你的棋盤格大小,我這邊是8*6的大小,你需要需要按照自己的設定
b. opencv雙目測距Dlg.cpp 裡 const float squareSize = 2.5f; //此處為你的棋盤格上一個格子的實際大小,拿個尺子量一下,我這邊是2.5cm
7.後續我再詳細介紹吧!
源碼連結:http://pan.baidu.com/s/1kVLXrzp
- 參考資料:
(1)《學習OpenCV》第11章,12章
(2)opencv官網:http://wiki.opencv.org.cn
(3)鄒宇華CSDN部落格http://blog.csdn.net/chenyusiyuan?viewmode=contents
- 流程:
- 擷取立體标定用圖像:
- 程式打開左右攝像頭,開始實時采集圖像
- 放置好棋盤格圖像于倆攝像頭之前,注意棋盤圖像盡量平行于倆攝像頭,并進行左右平移移動,或者前後移動,要保證整個棋盤在兩個攝像頭的共同視場範圍之内。
- 程式會對采集到的一對圖像進行有效性判斷,若判斷結果為有效才儲存圖像。(當左右兩幅圖像同時能檢測到全部角點視為有效)
- 程式在儲存完一定對數的圖像後會關閉攝像頭,立體标定用圖像采集完畢。
(2)立體标定:
a.讀入儲存好的立體标定圖像
b.用立體标定函數cvStereoCalibrate(const cvMat *objectPoints,
const CvMat *imagePoints1,
const CvMat *imagePoints2,
const CVMat *npoints,
CvMat *cameraMatrix1,
CvMat *distCoeffs1,
CvMat *cameraMatrix2,
CvMat *distCoeffs2,
CvMat imageSize,
CvMat R,
CvMat T,
CvMat E,
CvMat F,
CvTermCriteria termcrit
int flags=CV_CALIB_FIX_INTRINSIC
);
來擷取立體标定參數:
第一個攝像頭的内參數矩陣cameraMatrix1,畸變參數distCoeffs1
第二個攝像頭的内參數矩陣cameraMatrix2,畸變系數distCoeffs2
聯系左右錄影機的旋轉矩陣R,和平移向量T
c. 調用立體校正函數cvSteroRectify(
const CvMat *cameraMatrix1,
const CvMat *cameraMatrix2,
const CvMat *distCoeffs1,
const CvMat *distCoeffs2,
const CvMat *imageSize,
const CvMat *R
const CvMat *T
CvMat *Rl
CvMat *Rr
CvMat *pl
CvMat *pr
CvMat *Q
int flags=CV_CALIB_ZERO_DISPARITY
);
對于這個函數來說,輸入的是前面立體标定函數得到的第一個攝像頭的内參數矩陣cameraMatrix1,畸變參數distCoeffs1,第二個攝像頭的内參數矩陣cameraMatrix2,畸變系數distCoeffs2,棋盤圖像大小imageSize,聯系左右攝像頭的旋轉矩陣R和平移矩陣T,傳回的是校正後的左右錄影機旋轉矩陣Rl和Rr,3×4的左右投影方程Pl和pr,還有一個Q矩陣
- 調用校正映射函數cvInitUndistortRectifyMap(const CvMat *M,
const CvMat *distCoeffs,
const CvMat *Rrect,
const CvMat *Mrect,
CvArr* mapx,
CvArr* mapy);
這個函數被調用兩次,左右攝像頭各調用一次,具體輸入參數為上面立體校正函數所得到的參數
對于左攝像頭調用,該函數為:
cvInitUndistortRectifyMap(const CvMat *cameraMatrix1
const CvMat *distCoeffs1,
const CvMat *Rl,
const CvMat *pl,
CvArr* mapx1,
CvArr* mapy1);
輸入參數是3×3的左錄影機内參數矩陣cameraMatrix1,左錄影機畸變參數distCoeffs1,校正後的左錄影機矩陣Rl, 3×4的左右投影方程Pl,輸出為左攝像頭的x,y方向的映射關系矩陣mapx1,mapy1
對于右攝像頭調用,該函數為:
cvInitUndistortRectifyMap(const CvMat *cameraMatrix2
const CvMat *distCoeffs2,
const CvMat *Rr,
const CvMat *pr,
CvArr* mapx2,
CvArr* mapy2);
輸入參數是3×3的左錄影機内參數矩陣cameraMatrix2,左錄影機畸變參數distCoeffs2,校正後的左錄影機矩陣Rr, 3×4的左右投影方程Pr,輸出為左攝像頭的x,y方向的映射關系矩陣mapx2,mapy2
儲存好Q,mapx1,mapy1,mapx2,mapy2這5個參數矩陣,供下面的比對測距使用
(3)比對測距
a.讀入5個參數Q,mapx1,mapy1,mapx2,mapy2這5個參數矩陣
b.打開左右攝像頭
c.在雙攝像頭前放好标記物體,這裡為4×3棋盤格的圖像
d.擷取一對左右圖像
e.對左右圖像進行校正,利用cvRemp()函數,這裡需要用到讀入的mapx1,mapy1對左圖像進行校正,用讀入到的mapx2,mapy2對右圖像進行校正
f.顯示校正後的左右圖像
g.對左右圖像進行角點檢測,若能成功檢測出所有角點,這裡是12個角點,則分别計算左右圖像上對應角點所對應的實際空間坐标,獲得z值,這裡可以用下面公式進行計算:
這裡Q為讀入的Q矩陣,x,y為左圖像上角點坐标,d為左圖像上角點坐标x的值與它所對應的右圖像上的角點坐标xr值的差,那麼該對角點所對應的點的三維坐标就是(X/W,Y/W,Z/W),那麼Z/W,就是我們關心的距離
把這些點的距離值做一個平均值來作為标記物體離雙攝像頭的距離
完成後繼續擷取一幀圖像做重複處理
h.若左右圖像未能檢測到所有角點,就繼續擷取下一幀圖像,
補充:
我的程式在三個工作空間中,“c做圖像提供并判斷”,“c做立體标定”,“c做實時測距”,該三部分程式是用VS2010+opencv2.4.4來實作的
在第一個檔案夾中“c做圖像提供并判斷”,程式運作後的标定圖像儲存在”E:\立體标定圖像”檔案夾中,圖像路徑儲存在“E:\立體标定圖路徑.txt“文本中
在第二個檔案夾中,“c做立體标定“,記得結合具體棋盤标定物體設定
圖中squareSize的值,該值為棋盤圖像中一小格的大小,這裡用的一小格為2.5cm,是以squareSize的值為2.5f
該程式中的輸出參數儲存路徑為”E:\輸出參數文本.txt”
最終的實時測距效果圖如下: