天天看点

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双目测距