天天看點

MFC+opencv雙目測距

  操作流程如下:

1.請配置好vs環境(此版本是vs2010+opencv2.4.3所寫,具體配置自己查吧。http://blog.csdn.net/garfielder007/article/details/50197181)

2.運作界面如下圖(很簡陋):

MFC+opencv雙目測距

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. 參考資料:

(1)《學習OpenCV》第11章,12章

(2)opencv官網:http://wiki.opencv.org.cn

(3)鄒宇華CSDN部落格http://blog.csdn.net/chenyusiyuan?viewmode=contents

  1. 流程:
  1. 擷取立體标定用圖像:
  1. 程式打開左右攝像頭,開始實時采集圖像
  2. 放置好棋盤格圖像于倆攝像頭之前,注意棋盤圖像盡量平行于倆攝像頭,并進行左右平移移動,或者前後移動,要保證整個棋盤在兩個攝像頭的共同視場範圍之内。
  3. 程式會對采集到的一對圖像進行有效性判斷,若判斷結果為有效才儲存圖像。(當左右兩幅圖像同時能檢測到全部角點視為有效)
  4. 程式在儲存完一定對數的圖像後會關閉攝像頭,立體标定用圖像采集完畢。

(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矩陣

  1. 調用校正映射函數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值,這裡可以用下面公式進行計算:

MFC+opencv雙目測距

這裡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做立體标定“,記得結合具體棋盤标定物體設定  

MFC+opencv雙目測距

圖中squareSize的值,該值為棋盤圖像中一小格的大小,這裡用的一小格為2.5cm,是以squareSize的值為2.5f

該程式中的輸出參數儲存路徑為”E:\輸出參數文本.txt”

最終的實時測距效果圖如下: 

MFC+opencv雙目測距