在文章68. 三维重建3-两视图几何中,我们看到通过三角测量,可以确定一个像点在三维空间中的位置,其前提是我们提前获取了这个像点在另外一个图像中的对应点,并且知道了两个相机的相机矩阵。
获取在两个图像中的成对匹配点,也就是同一个3D点在两个图像上的投影点非常重要。我在上述文章中为你展示了两视角几何模型中的对角几何约束关系,这样当需要搜索像点x的对应匹配点x'时,我们可以将搜索范围控制到第二幅图像的极线l'上。
然而,l'通常不是水平的,因此我们需要在第二幅图像的一条倾斜线段上进行搜索。这样的算法是很低效的,尤其是当我们需要用到图像块的特征去做点匹配的判断时。在之后的文章中,我会介绍”立体匹配“,这个过程需要对图像中的所有点寻找匹配点,如果每个点都还按照这种倾斜线段搜索的方法去操作,就会特别特别慢。因此,我们必须引入立体校正(Rectification)操作,它对两幅图像做变换,最终使得两幅图像的极线平行,且在水平方向对齐。这样,当我们需要搜索对应的匹配点时,就只需要在水平方向上进行一维搜索,大大加快了速度。
这个过程,就好像是我们创造了两个内参相同的虚拟相机,它们指向同一个方向进行拍摄原来的场景,得到两幅新的图像,如下图所示:
下面展示了在同一个场景用双摄手机的两个摄像头拍摄的一对图像,两个摄像头具有不同的内参数,因此拍摄出的图像视角间有明显的空间变换和尺度差异。
这个手机的摄像头是纵向排列的,拍出的图像如下图所示
所以当我们画出部分极线时,会发现这些极线是倾斜的,没有对齐。
即便我们根据内参数对图像进行一定比例的缩放,使得两幅图像尺寸一致,我们发现极线依然不能对齐,而且是倾斜的:
当执行我上面提到的立体校正步骤后,两个图像的所有极线将变为水平,且在纵向对齐,此时两个图像的尺度也校正到一致状态。注意这两个摄像头在手机上是纵向排布的,为了让极线在水平方向,我把图像进行了90度旋转。如果不做这样的旋转,极线就是在纵向对齐的,这不利用后续立体匹配这类算法的处理。
仅为了查看方便,我们可以将图像极线重新调整为纵向,观察和比较一下:
正式来说,图像立体校正是指对两幅图像分别进行一次平面投影变换,使两幅图像的对应极线在同一条水平向上,而对极点被映射到无穷远处, 这样可以使两幅图像只存在水平方向上的视差,立体匹配问题从二维 降到一维,从而提高了匹配的速度。
虽然有各种各样的立体校正算法,今天我只会介绍一种非常容易理解的方法,而且也是广泛应用的一种方法:
作者给出了一种简单的图像校正方法,只需要知道两个相机的相机矩阵,且要求两个相机视角相差不大——这种假设在我面临的项目里面都是成立的,所以我比较喜欢这种算法。
现在来进行一点点简单的推导,请抓稳扶好
由文章66. 三维重建1——相机几何模型和投影矩阵我们知道
又由于
且从Xw到投影成像点的直线一定会过光心,如下图所示
因此,我们可以把三维空间点坐标表示为下面的式子(上横线表示齐次坐标),c是指光心的坐标,\lambda是比例因子,用来调节Xw的位置在这条线上的位置。
接下来,我们看看两个相机在校正前和校正后的几何模型:
可见,在校正前和校正后,相机的投影矩阵发生了变化,所以同一个3D点的投影点也发生了变化。校正后,我们看到两个光心所在的主平面是平行的,它们都看向同一个方向。我们用下标o代表origin,用下标n代表new,那么,上面的公式就变成了:
在进行立体校正时,我们是已知两个相机的相机矩阵的,因而也就知道了两个相机的光心坐标。同时,在立体校正前后,现在讲的Fusiello等的算法假设光心是不变的,因此我们可以联立上面两个式子,得到投影点的关系:
其中:
因此,为了做两个相机的校正,我们只需要确定好新的虚拟相机的内参数及旋转矩阵即可。
先说内参数:在校正之后,我们需要两个内参数完全一致的虚拟相机,因此在Fusiello等的算法中,直接用下面的式子得到新相机的内参数:
再看看旋转矩阵:校正之后,两个相机的方向是一致的,它们的旋转矩阵可以展开如下:
其中,旋转矩阵的三行代表着新相机矩阵的X/Y/Z轴,它们分别具有如下的特点:
到此为止,我们就确定了虚拟相机的方向(旋转矩阵),光心(c1和c2),内参,这样就很容易利用刚提到的公式来对图像进行变换了:
在具体实施中,我们假设已经通过相机的几何参数标定(见文章67. 三维重建2——相机几何参数标定)获得了两个相机的内参和外参,并且已经对图像进行了畸变校正。那么,整个校正过程可以总结如下:
在作者的论文中,列出了22行Matlab代码完成这个过程,你可以查阅看看。作者还把相关的代码、数据放到了sci.univr.it/∼fusiello/rect.html供我们学习,很赞!
这个算法的使用要点如下:
这里我展示用同样一个手机拍出的更多图像,你可以清晰的看到图像在校正前后极线的变化:
校正前:
校正后:
校正前:
校正后:
今天我给你介绍了一个非常简单,容易复现的立体校正算法。事实上,我这边的实际项目中也是在这个算法的基础上进行扩展,进而进行实际应用的。所以我觉得这个算法非常实用,好用,推荐给你学习,希望能给你带来启发。
如果你在实际使用中发现了对极线无法水平对齐,就要考虑到标定的精度了。比如标定时的状态和你实际使用相机时的状态发生了轻微的改变——这种情况很常见——你就需要考虑如何对相关参数进行进一步的调优,才能更好的使用这个算法。