目录
一、双目立体视觉系统的四个基本步骤
二、各步骤原理
1、相机标定
2、立体校正
3、立体匹配
一、双目立体视觉系统的四个基本步骤
- 相机标定主要包含两部分内容: 单相机的内参标定和双目相机的外参标定,前者可以获得每个相机的焦距、光心、畸变系数等参数,后者可以获得双目相机之间的相机坐标系的旋转、平移关系。
- 立体校正过程是根据相机的标定结果,对两个相机采集到的原始图像进行校正,校正后的两张图像位于同一平面且互相平行,即图像的每行像素之间共线。
- 立体匹配过程是根据立体校正后的图像,进行像素点的匹配,匹配成功的点表示真实世界中的某点在这两个图像中的不同位置。
- 深度计算过程是根据立体匹配结果得到视差图,通过视差图计算每个像素对应的深度,从而获得深度图。
二、各步骤原理
1、相机标定
- 单目相机的内参标定
基础知识,具体过程参考: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));
2、立体校正
- 为什么要立体校正呢?
首先需要从理想双目相机成像模型说起。
其中: 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)双目校正后的左右相机图像
3、立体匹配
上面讲到的对于左图的一个点,沿着它在右图中水平极线方向寻找和它最匹配的像素点,说起来简单,实际操作起来却不容易。这是因为上述都是理想情况下的假设。实际进行像素点匹配的时候会发现几个问题:
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)法 等作为匹配代价的计算方法。不同的代价计算算法都有各自的特点,对各类数据的表现也不尽相同,选择合适的匹配代价计算函数是立体匹配中不可忽视的关键步骤。
每个像素在搜索同名点之前,往往会指定一个视差搜索范围 ,视差搜索时将范围限定在内,用一个大小为 ( 为影像宽度, 为影像高度)的三维矩阵C来存储每个像素在视差范围内每个视差下的匹配代价值。矩阵 通常称为DSI(Disparity Space Image)。
图1 DSI示意图(C(x,y,d)代表像素(x,y)在视差为d时的匹配代价)
- 代价聚合的根本目的是让代价值能够准确的反映像素之间的相关性。上一步匹配代价的计算往往只会考虑局部信息,通过两个像素邻域内一定大小的窗口内的像素信息来计算代价值,这很容易受到影像噪声的影响,而且当影像处于弱纹理或重复纹理区域,这个代价值极有可能无法准确的反映像素之间的相关性。
而代价聚合则是建立邻接像素之间的联系,以一定的准则,如相邻像素应该具有连续的视差值,来对代价矩阵进行优化,这种优化往往是全局的,每个像素在某个视差下的新代价值都会根据其相邻像素在同一视差值或者附近视差值下的代价值来重新计算得到新的DSI,用矩阵 S 来表示。
实际上代价聚合类似于一种视差传播步骤,信噪比高的区域匹配效果好,初始代价能够很好的反映相关性,可以更准确的得到最优视差值,通过代价聚合传播至信噪比低、匹配效果不好的区域,最终使所有影像的代价值都能够准确反映真实相关性。常用的代价聚合方法有扫描线法、动态规划法、SGM算法中的路径聚合法等。
- 视差计算即通过代价聚合之后的代价矩阵 S 来确定每个像素的最优视差值,通常使用赢家通吃算法(WTA,Winner-Takes-All)来计算,如图所示,某个像素的所有视差下的代价值中,选择最小代价值所对应的视差作为最优视差。这一步非常简单,这意味着聚合代价矩阵S的值必须能够准确的反映像素之间的相关性,也表明上一步代价聚合步骤是立体匹配中极为关键的步骤,直接决定了算法的准确性。
- 视差优化的目的是对上一步得到的视差图进行进一步优化,改善视差图的质量,包括剔除错误视差、适当平滑以及子像素精度优化等步骤,一般采用左右一致性检查(Left-Right Check)算法剔除因为遮挡和噪声而导致的错误视差;采用剔除小连通区域算法来剔除孤立异常点;采用中值滤波(Median Filter)、双边滤波(Bilateral Filter)等平滑算法对视差图进行平滑;另外还有一些有效提高视差图质量的方法如鲁棒平面拟合(Robust Plane Fitting)、亮度一致性约束(Intensity Consistent)、局部一致性约束(Locally Consistent)等也常被使用。
由于WTA算法所得到的视差值是整像素精度,为了获得更高的子像素精度,需要对视差值进行进一步的子像素细化,常用的子像素细化方法是一元二次曲线拟合法,通过最优视差下的代价值以及左右两个视差下的代价值拟合一条一元二次曲线,取二次曲线的极小值点所代表的视差值为子像素视差值。
局部匹配算法的步骤一般包括匹配代价计算、代价聚合和视差计算三个步骤,全局算法则包括匹配代价计算,视差计算与视差优化三个步骤,半全局算法SGM则四个步骤都有。
OpenCV提供了以下四种立体匹配算法的函数,后面会详细学习BM和SGBM
- Block Matching(BM) StereoBM
- Semi-Global Block Matching(SGBM) StereoSGBM
- Graph Cut(GC)cvStereoGCState()
- Dynamic Programming(DP)cvFindStereoCorrespondence()
第一种是最简单的块匹配,速度最快,精度最差,第二种是半全局快匹配,是一种速度和精度的折中,第三,四种是基于全局的匹配。
参考:
1. https://zhuanlan.zhihu.com/p/378738199
2. https://www.cnblogs.com/zyly/p/9373991.html#_label1_2
3. https://zhuanlan.zhihu.com/p/159055657文章来源:https://www.toymoban.com/news/detail-621614.html
4. https://zhuanlan.zhihu.com/p/31243203文章来源地址https://www.toymoban.com/news/detail-621614.html
到了这里,关于双目立体视觉(一) 基本原理和步骤的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!