本文采用MATLAB标定工具箱和OpenCV3.10来实现双目测距,设备为两个CMOS工业相机和相应的双目云台。
首先感谢CSDN上两位大神前辈邹宇华和scyscyao,虽然是六年前的博客,OpenCV也从1.0的版本更新到了3.1版本,但博客对机器视觉初学者来说仍然提供了巨大的帮助。本文主要参考了 OpenCV学习笔记(17)双目测距与三维重建的OpenCV实现问题集锦(二)双目定标与双目校正、OpenCV学习笔记(18)双目测距与三维重建的OpenCV实现问题集锦(三)立体匹配与视差计算、分享一些OpenCV实现立体视觉的经验、双摄像头测距的OpenCV实现、学习笔记:使用opencv做双目测距(相机标定+立体匹配+测距).、OPENCV3.0 双目立体标定等文章,并摘录了部分内容。
由于初学机器视觉,有些问题尚不是很清楚,文中不免存在错误,还请观者指正。
一、双目标定
双目摄像头标定不仅要得出每个摄像头的内部参数,还需要通过标定来测量两个摄像头之间的相对位置(即右摄像头相对于左摄像头的平移向量 t和旋转矩阵R)。
由于OpenCV中StereoCalibrate标定的结果极其不稳定,甚至会得到很夸张的结果,所以最后还是决定Matlab标定工具箱立体标定,再将标定的结果读入OpenCV,来进行后续图像校准和匹配。
首先对左右摄像头分别进行标定,得到两个摄像头各自的内参矩阵和畸变参数向量。下图是单目标定的结果示意图和反投影误差分析图。
左右摄像头都标定完成之后,就可以利用单目标定得到的两个摄像头的参数进行立体标定。下图是双目标定的结果示意图。
注意事项:
1. 采集棋盘图的时候要注意,尽量让棋盘占据尽可能多的画面,这样可以得到更多有关摄像头畸变方面的信息。
2. 在标定工具箱中,可以通过reproject on images,得到根据当前标定结果得到的反投影误差,从点云的聚集情况和分散的最大范围可以看出反投影误差的大小。Recomp. corners选项,主要完成根据反向投影得到的角点坐标重作为对角点的估计,重新计算角点的功能。针对第一次标定结果误差太大的情况,可以通过此方法重新计算焦点。计算完成后,点击Calibration根据新的焦点进行标定。此时,得到的标定信息,比第一次得到的反投影误差分布更集中,直径也小。(该步骤在标定过程中需谨慎使用,因为往往首次得到的三维坐标精确度并不高,如果参考误差较大的话,有可能使结果与正解偏差更大。)
3. 两个摄像头的焦距应该保持一致,因为在后续的视差图转换为三维图时的Q矩阵只有一个f值。所以必须要求至少焦距相近。而且立体成像的三角测量(Learning OpenCV书中提到)的前提假设就是fl=fr。(调整两个摄像头的焦距相同的方法:离两个相机相同远处放置标定板,分别调节两个相机的焦距,使得两个画面的清晰度相似。)
二、双目校正
要计算目标点在左右两个视图上形成的视差,首先要把该点在左右视图上两个对应的像点匹配起来。然而,在二维空间上匹配对应点是非常耗时的,为了减少匹配搜索范围,我们可以利用极线约束使得对应点的匹配由二维搜索降为一维搜索。而双目校正的作用就是要把消除畸变后的两幅图像严格地行对应,使得两幅图像的对极线恰好在同一水平线上,这样一幅图像上任意一点与其在另一幅图像上的对应点就必然具有相同的行号,只需在该行进行一维搜索即可匹配到对应点。
经过双目标定得到摄像头的各项参数后,采用OpenCV中的stereoRectify得到校正旋转矩阵R、投影矩阵P、重投影矩阵Q,再采用initUndistortRectifyMap函数得出校准映射参数,然后用remap来校准输入的左右图像。其中remap的图像剪裁系数alpha,取值范围是-1、0~1。当取值为 0 时,OpenCV会对校正后的图像进行缩放和平移,使得remap图像只显示有效像素(即去除不规则的边角区域),适用于机器人避障导航等应用;当alpha取值为1时,remap图像将显示所有原图像中包含的像素,该取值适用于畸变系数极少的高端摄像头;alpha取值在0-1之间时,OpenCV按对应比例保留原图像的边角区域像素。Alpha取值为-1时,OpenCV自动进行缩放和平移。
二、立体匹配
采用Block Matching算法进行立体匹配,Block Matching用的是SAD方法,速度比较快,但效果一般。
参数设置:
MinDisparity设置为0,因为两个摄像头是前向平行放置,相同的物体在左图中一定比在右图中偏右。如果为了追求更大的双目重合区域而将两个摄像头向内偏转的话,这个参数是需要考虑的。
UniquenessRatio主要可以防止误匹配,此参数对于最后的匹配结果是有很大的影响。立体匹配中,宁愿区域无法匹配