赞
踩
目录
基础知识,具体过程参考:opencv相机内参标定
内参矩阵:
畸变参数:k1,k2,k3径向畸变,p1,p2是切向畸变系数。
主要为了计算两个相机坐标系之间的旋转和平移关系,以OpenCV为例,最终可以得到旋转矩阵R,平移向量T,本质矩阵E和基础矩阵F。
- double err = cv::stereoCalibrate(object_points,
- imagepointL, imagepointR,
- intrinsic_left, distCoeffs_left,
- intrinsic_right, distCoeffs_right,
- srcImgSize,
- R, T, E, F,
- CALIB_USE_INTRINSIC_GUESS,
- cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 30, 1e-6));
首先需要从理想双目相机成像模型说起。
其中: b 为基线,即两个相机原点之间的距离 ;
fl和fr 分别为左右相机的焦距,理想的双目相机fl=fr=f ;
cl和cr 分别为左右相机的光心,理想的双目相机cl=cr ;
xl和xr 分别为空间中的一点P投影在左右相机的图像中的横坐标 ;
则根据几何关系,可以得到:
整理得:
这里的(xr-xl)就是视差disparity 。
可以发现如果要计算深度z,必须要知道:
1、相机焦距f,左右相机基线b。这些参数可以通过先验信息或者相机标定得到。
2、视差d。需要知道左相机的每个像素点(xl, yl)和右相机中对应点(xr, yr)的对应关系。这是双目视觉的核心问题。视差是指在两个摄像机图像之间的像素位置的差异。假设立体视觉相机中的左图像在位置(1,30)具有像素,并且相同的像素在右图像中的位置(4,30)存在,视差值或差值为(4-1)=3。视差值与上述公式的深度成反比。
那么问题来了,对于左图中的一个像素点,如何确定该点在右图中的位置?是不是需要我们在整 个图像中地毯式搜索一个个匹配?
答案是:不需要。因为有极线约束。极线约束对于求解图像对中像素点的对应关系非常重要。
如下图所示。C1,C2是两个相机,P是空间中的一个点,P和两个相机中心点C1、C2形成了三维空间中的一个平面PC1C2,称为极平面(Epipolar plane)。极平面和两幅图像相交于两条直线,这两条直线称为极线(Epipolar line)。P在相机C1中的成像点是P1,在相机C2中的成像点是P2,但是P的位置事先是未知的。
我们的目标是:对于左图的P1点,寻找它在右图中的对应点P2,这样就能确定P点的空间位置,也就是我们想要的空间物体和相机的距离(深度)。
所谓极线约束(Epipolar Constraint)就是指当同一个空间点在两幅图像上分别成像时,已知左图投影点p1,那么对应右图投影点p2一定在相对于p1的极线上,这样可以极大的缩小匹配范围。
根据极线约束的定义,我们可以在下图中直观的看到P2一定在对极线上,所以我们只需要沿着极线搜索一定可以找到和P1的对应点P2。
但是,上述过程考虑的情况是(两相机共面且光轴平行,参数相同)非常理想状态的,即认为两个相机成像面是完全平行对齐的。这种假设在现实世界中是基本难以成立的,因为有些场景下两个相机需要独立固定,很难保证光心C1,C2完全水平,即使是固定在同一个基板上也会因为装配的原因导致光心不完全水平。如下图所示。我们看到两个相机的极线不仅不平行,还不共面,之前的理想模型不再适用。
我们先来看看这种情况下拍摄的两张左右图片,如下所示。左图中三个十字标志的点,在右图中对应的极线是右图中的三条白色直线,也就是对应的搜索区域。我们看到这三条直线并不是水平的,如果进行逐点搜索效率非常低。
左图中三个点(十字标志)在右图中对应的极线是右图中的三条白色直线
针对现实中这种非理想情况,我们需要通过立体校正,对左右相机拍摄的图像像素做重新排列,以达到理想状态下的成像面平行对齐状态。具体来说就是,通过分别对两张图片用单应(homography)矩阵变换(可以通过标定获得),把两个不同方向的图像平面(下图中灰色平面)重新投影到同一个平面且光轴互相平行(下图中黄色平面),这样就可以用前面理想情况下的模型了,两个相机的极线也变成水平的了。
但是让两个相机光轴平行的方法有很多,可以:
1)左相机不动,右相机动。
2)也可以两部相机旋转到中间等等。
最常见的校正方法就是Bouguet极线校正方法。
Bouguet极线校正方法:左右相机成像平面各旋转一半,使得左右图像重投影造成的误差最小,左右视图的共同面积最大。
- CV_EXPORTS_W void stereoRectify( InputArray cameraMatrix1, InputArray distCoeffs1,
- InputArray cameraMatrix2, InputArray distCoeffs2,
- Size imageSize, InputArray R, InputArray T,
- OutputArray R1, OutputArray R2,
- OutputArray P1, OutputArray P2,
- OutputArray Q, int flags = CALIB_ZERO_DISPARITY,
- double alpha = -1, Size newImageSize = Size(),
- CV_OUT Rect* validPixROI1 = 0, CV_OUT Rect* validPixROI2 = 0 );
经过图像矫正后,左图中的像素点只需要沿着水平的极线方向搜索对应点就可以了。从下图中可以看到三个点对应的视差(红色双箭头线段)是不同的,越远的物体视差越小,越近的物体视差越大,这和我们的常识是一致的。
图像校正后的结果。红色双箭头线段是对应点的视差
(1)双目校正前的左右相机图像
(2)双目校正后的左右相机图像
上面讲到的对于左图的一个点,沿着它在右图中水平极线方向寻找和它最匹配的像素点,说起来简单,实际操作起来却不容易。这是因为上述都是理想情况下的假设。实际进行像素点匹配的时候会发现几个问题:
1、实际上要保证两个相机完全共面且参数一致是非常困难的,而且计算过程中也会产生误差累积,因此对于左图的一个点,其在右图的对应点不一定恰好在极线上。但是应该是在极线附近,所以搜索范围需要适当放宽。
2、单个像素点进行比较鲁棒性很差,很容易受到光照变化和视角不同的影响。
双目立体匹配可划分为四个步骤:匹配代价计算、代价聚合、视差计算和视差优化。
匹配代价计算的方法有很多,传统的摄影测量中,使用灰度绝对值差(AD,Absolute Differences)、灰度绝对值差之和(SAD,Sum of Absolute Differences)、归一化相关系数(NCC,Normalized Cross-correlation)等方法来计算两个像素的匹配代价;计算机视觉中,多使用互信息(MI,Mutual Information)法、Census变换(CT,Census Transform)法、Rank变换(RT, Rank Transform)法、BT(Birchfield and Tomasi)法 等作为匹配代价的计算方法。不同的代价计算算法都有各自的特点,对各类数据的表现也不尽相同,选择合适的匹配代价计算函数是立体匹配中不可忽视的关键步骤。
每个像素在搜索同名点之前,往往会指定一个视差搜索范围 ,视差搜索时将范围限定在
图1 DSI示意图(C(x,y,d)代表像素(x,y)在视差为d时的匹配代价)
而代价聚合则是建立邻接像素之间的联系,以一定的准则,如相邻像素应该具有连续的视差值,来对代价矩阵进行优化,这种优化往往是全局的,每个像素在某个视差下的新代价值都会根据其相邻像素在同一视差值或者附近视差值下的代价值来重新计算得到新的DSI,用矩阵 S 来表示。
实际上代价聚合类似于一种视差传播步骤,信噪比高的区域匹配效果好,初始代价能够很好的反映相关性,可以更准确的得到最优视差值,通过代价聚合传播至信噪比低、匹配效果不好的区域,最终使所有影像的代价值都能够准确反映真实相关性。常用的代价聚合方法有扫描线法、动态规划法、SGM算法中的路径聚合法等。
由于WTA算法所得到的视差值是整像素精度,为了获得更高的子像素精度,需要对视差值进行进一步的子像素细化,常用的子像素细化方法是一元二次曲线拟合法,通过最优视差下的代价值以及左右两个视差下的代价值拟合一条一元二次曲线,取二次曲线的极小值点所代表的视差值为子像素视差值。
局部匹配算法的步骤一般包括匹配代价计算、代价聚合和视差计算三个步骤,全局算法则包括匹配代价计算,视差计算与视差优化三个步骤,半全局算法SGM则四个步骤都有。
OpenCV提供了以下四种立体匹配算法的函数,后面会详细学习BM和SGBM
第一种是最简单的块匹配,速度最快,精度最差,第二种是半全局快匹配,是一种速度和精度的折中,第三,四种是基于全局的匹配。
参考:
1. https://zhuanlan.zhihu.com/p/378738199
2. https://www.cnblogs.com/zyly/p/9373991.html#_label1_2
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。