首页
登录 | 注册

Opencv sample单目、双目标定(opencv 学习笔记)——转发

  1. 为什么要标定

     首先我们要对摄像头做标定,具体的公式推导在《learning opencv3.0》中有详细的解释。

    标定的原因:

    1. 标定的目的是为了消除畸变以及得到内外参数矩阵,内参数矩阵可以理解为焦距相关,它是一个从平面到像素的转换,焦距不变它就不变,所以确定以后就可以重复使用,而外参数矩阵反映的是摄像机坐标系与世界坐标系的转换,至于畸变参数,一般也包含在内参数矩阵中。从作用上来看,内参数矩阵是为了得到镜头的信息,并消除畸变,使得到的图像更为准确,外参数矩阵是为了得到相机相对于世界坐标的联系,是为了最终的测距。
    2. 我们知道双目测距的时候两个相机需要平行放置,但事实上这个是很难做到的,所以就需要立体校正得到两个相机之间的旋转平移矩阵,也就是外参数矩阵。

      (校准前) (校准后)

  2. sample单目标定

    直接用opencv里面的sample,在opencv/sources/sample/cpp里面,有个calibration.cpp的文件,这是单目的标定,是可以直接编译使用的,这里要注意几点:

    1. 棋盘也就是标定板是要预先打印好的,你打印的棋盘的样式决定了后面参数的填写,具体要求也不是很严谨,清晰能用就行。之所用棋盘是因为他检测角点很方便。
    2. 一般设置为这个样子:-w 6 -h 8 -s 2 -n 10 -o camera.yml -op -oe [<list_of_views.txt>] ,这是几个重要参数的含义:
    3. -w <board_width> # 图片某一维方向上的交点个数
    4. -h <board_height> # 图片另一维上的交点个数
    5. [-n <number_of_frames>] # 标定用的图片帧数

      最终得到的yml文件,就是单目标定的参数矩阵,之后使用它就可以得到校正后的图像啦。

然后就是双目标定了,同样的地方,找到stereo_calib.cpp,这个参数比较简单,只要确定长、宽和输入的一个xml文件(在之前的文件夹里面),这个文件是为了读取图片用的,你需要自己用固定好的双目摄像头13对棋盘图片,命名为 left01,right01......这样 一系列的名字,另外,最简单的方法就是把自己拍的照片放到相应的工程下,以及stereo开头的那个xml文件也复制过去这个程序代码 并不复杂,可以稍微研究一下,工程向的代码确实严谨,各种情况都考虑到了。

注意事项:

  1. 长宽一定要写对
  2. 核心函数 static void StereoCalib(const vector<string>& imagelist, Size boardSize, bool useCalibrated=true, bool showRectified=true),注意搞清楚参数的意义,因为我是用的单目标定好的摄像头拍摄的图片,不需要再校正了,所以第三个参数要用false,这样最后的结果才能看。
  3. 另外注意到计算rms误差的时候,结束条件的几个参数是可以调整的。

double rms = stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1],cameraMatrix[0], distCoeffs[0],cameraMatrix[1],distCoeffs[1],imageSize,R,T,E, ,TermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,100,1e-5),CV_CALIB_FIX_ASPECT_RATIO+CV_CALIB_ZERO_TANGENT_DIST+CV_CALIB_SAME_FOCAL_LENGTH+CV_CALIB_RATIONAL_MODEL+CV_CALIB_FIX_K3 + CV_CALIB_FIX_K4 + CV_CALIB_FIX_K5)。

这个函数计算了两个摄像头进行立体像对之间的转换关系。如果你有一个立体相机的相对位置,并且两个摄像头的方向是固定的,以及你计算了物体相对于第一照相机和第二照相机的姿态,(R1,T1)和(R2,T2),各自(这个可以通过solvepnp()做到)通过这些姿态确定。你只需要知道第二相机相对于第一相机的位置和方向。

除了立体的相关信息,该函数也可以两个相机的每一个做一个完整的校准。然而,由于在输入数据中的高维的参数空间和噪声的,可能偏离正确值。如果每个单独的相机内参数可以被精确估计(例如,使用calibratecamera()),建议这样做,然后在本征参数计算之中使CV_CALIB_FIX_INTRINSIC的功能。否则,如果一旦计算出所有的参数,它将会合理的限制某些参数,例如,传CV_CALIB_SAME_FOCAL_LENGTH and CV_CALIB_ZERO_TANGENT_DIST,这通常是一个合理的假设。

3、标定之后就是对图像的校正:

void loadCameraParams(Mat &cameraMatrix, Mat &distCoeffs)

{

FileStorage fs("camera.yml", FileStorage::READ);//这个名字就是你之前校正得到的yml文件

 

fs["camera_matrix"] >> cameraMatrix;

fs["distortion_coefficients"] >> distCoeffs;

}

 

Mat calibrator(Mat &view)//需要校正处理的图片

{

vector<string> imageList;

static bool bLoadCameraParams = false;

static Mat cameraMatrix, distCoeffs, map1, map2;

Mat rview;

Size imageSize, newImageSize;

 

if (!view.data)

return Mat();

 

imageSize.width = view.cols;

imageSize.height = view.rows;

 

newImageSize.width = imageSize.width;

newImageSize.height = imageSize.height;

 

if (bLoadCameraParams == false)

{

loadCameraParams(cameraMatrix, distCoeffs);

bLoadCameraParams = true;

initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),

getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, newImageSize, 0), newImageSize, CV_16SC2, map1, map2);

}

 

//undistort( view, rview, cameraMatrix, distCoeffs, cameraMatrix );

remap(view, rview, map1, map2, INTER_LINEAR);

 

imshow("左图", rview);

//int c = 0xff & waitKey();

 

rview.copyTo(view);

 

return view;

}

这样最后就可以得到校正后消除畸变的图片。

  1. sample 双目匹配

    opencv中提供了很多的立体匹配算法,类似于局部的BM,全局的SGBM等等,这些算法的比较大概是,速度越快的效果越差,如果不是很追究时效性,并且你的校正做的不是很好的话..推荐使用SGBM,算法的具体原理大家可以去百度,不难。这里我想提一下的是为什么做立体匹配有用,原因就是极线约束,这也是个很重要的概念,理解起来并不难,左摄像机上的一个点,对应三维空间上的一个点,当我们要找这个点在右边的投影点时,有必要把这个图像都遍历一边么,当然不用啦!

     

    最后,怎么在opencv里面实现呢?sample..找到stereo_match.cpp这个文件,命令行设置为:left01.jpg right02.jpg --algorithm=hh --blocksize=5 --max-disparity=256 --scale=1.0 --no-display -i intrinsics.yml -e extrinsics.yml -o disparity.jpg同意给几个建议:

1.参数的意义:

-max-disparity 是最大视差,可以理解为对比度,越大整个视差的range也就越大,这个要求是16的倍数

--blocksize 一般设置为5-29之间的奇数,应该是局部算法的窗口大小。

另,注意带上参数-i intrinsics.yml -e extrinsics.yml,毕竟咱有校正参数.

2.后面有两行代码:

reprojectImageTo3D(disp, xyz, Q, true);

saveXYZ(point_cloud_filename, xyz);

这个就是得到图片的三维坐标,Z也就是我们最终要求的深度啦。

行和行是对应的么? 之前我们说过,双目校正的目的就是为了得到两个平行的摄像头,所以当程序运行完毕以后,它会把两幅图像显示出来,并作出一系列的平行线,这样你会看到线上的点大致是呈对应关系,左边的角点对应右边的交点,所以,经过匹配和校正后,是对应的。

本文网址:http://www.bnee.net/article/4197.html

相关文章

  • opencv  双目标定操作完整版
    一.首先说明几个情况:    1.完成双目标定必须是自个拿棋盘图摆拍,网上涉及用opencv自带的标定图完成双目标定仅仅是提供个参考流程.我原来还以为用自带的图标定就行,但想不通的是咱们实际摆放的双目摄像头和人家当时摆放的肯定不一样,那用人 ...
  •  http://blog.csdn.net/bcj296050240/article/details/52778741
  • opencv-3.0.0-alpha\samples\cpp中编译stereo_calib.cpp 执行 cpp-example-stereo_calib -w 9 -h 6 stereo_calib.xml stereo_calib.xm ...
  • 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析
    本系列文章由zhmxy555(毛星云)编写,转载请注明出处.   文章链接: http://blog.csdn.net/poem_qianmo/article/details/19925819 作者:毛星云(浅墨)    邮箱: happy ...
  • 基于OpenCV的双目摄像机标定
    原文来自:http://xilinx.eetrend.com/blog/998 阅读本文之前请先阅读以下三篇博文: 机器视觉学习笔记(4)--单目摄像机标定参数说明 机器视觉学习笔记(5)--基于OpenCV的单目摄像机标定 机器视觉学习笔 ...
  • opencv 双目摄像头标定
    我用的是opencv官方的例程,花了一天把代码大致注释了下,但是双目感觉好难,很多地方都不懂,都是在大佬们的博客找的资料 下面是对例程使用的说明 http://blog.csdn.net/t247555529/article/details ...
  • 双目视觉标定,矫正,深度图(Vs  +OpenCV  C++ Python实现)
    代码是最为耐心.最能忍耐和最令人愉快的伙伴,在任何艰难困苦的时刻,它都不会抛弃你(开场白) 长时间不写博客,我总感觉自己没有做事情,最近一直在做目标检测,想结合一下双目视觉,做立体检测,于是就研究了一下双目视觉,参考了很多人的相关博客,在这 ...