立体校正
立体校正对经过标定的双目图像对进行变形处理,使它们看起来像是来自两个理想的、平行的相机:图像平面共面,光轴平行,行对齐。校正之后,左图像中任意像素的外极线在右图像中就是简单的同一行。
为什么这样有效:对于任意一对相机位姿,外极几何将左图像中一点的匹配约束到右图像中的一条一维曲线(对于针孔相机是一条直线)上。校正是应用于图像的一对单应变换 ,它们将两个极点沿水平轴映射到无穷远处,使所有外极线都变为水平且垂直对齐。
校正变换如何计算
给定标定好的内参 、镜头畸变,以及两相机之间的外参变换 ,OpenCV 的 stereoRectify 所使用的经典(Bouguet)构造方法过程如下:
- 拆分相对旋转。 将每个相机旋转 的”一半”,使两个光轴变得平行,同时尽量减少对每幅图像的扰动。
- 与基线对齐。 应用一个共同的旋转,使新的 轴指向基线向量 的方向。此时两个极点都位于无穷远处,因此外极线是水平的。
- 选择共同的虚拟内参。 为两个视图选择一个新的相机矩阵 (相同的 ,相同的主点所在行),使校正后的图像对拥有同一个焦距和同一个基线,用于 。
- 预烘焙重映射表。 每个相机的变形 与镜头去畸变模型相结合,预先计算成查找表,因此校正每一帧的成本只是一次图像重映射。
R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(K1, D1, K2, D2, size, R, T)
mapLx, mapLy = cv2.initUndistortRectifyMap(K1, D1, R1, P1, size, cv2.CV_32FC1)
mapRx, mapRy = cv2.initUndistortRectifyMap(K2, D2, R2, P2, size, cv2.CV_32FC1)
rectL = cv2.remap(imgL, mapLx, mapLy, cv2.INTER_LINEAR)
rectR = cv2.remap(imgR, mapRx, mapRy, cv2.INTER_LINEAR)
返回的 矩阵可以将校正后的像素加视差 直接重投影到三维空间——这是矩阵形式的视差到深度转换。
它带来的好处
- 一维对应搜索。 匹配从二维搜索简化为沿单行扫描,这正是使稠密视差算法(块匹配、半全局匹配)和快速稀疏立体匹配能够实时运行的原因。
- 简单的视差几何。 在校正后的帧中,对应关系纯粹是水平方向的,因此 和 精确成立,虚拟相机对拥有单一的公共焦距 和基线 。
- 免费的异常值剔除。 偏离所在扫描线(超出小容差)的候选匹配违反了外极几何约束,可以立即被丢弃。
检查校正质量
一个快速的合理性检验:在校正后的图像之间匹配特征,并检查垂直视差 。在一个校正良好的图像对上,它应该只是一个像素的极小一部分;系统性的偏移或图像上的梯度变化意味着外参标定已经漂移。随着机器人使用时间增长而不断上升的垂直视差,是相机装置被碰撞或热变形的典型症状。
实践注意事项
- 校正的好坏取决于标定的好坏。 中的误差会表现为垂直方向的错位,从而悄无声息地降低匹配质量——匹配器会在错误的行中搜索,导致失败或返回有偏的视差。
- 广角和鱼眼镜头受影响较大。 变形为针孔校正图像对会在边缘区域损失大量图像面积(或需要特殊的校正模型);较大的裁剪系数恰恰浪费了选择该镜头所看重的宽视场角。
- 基线必须保持刚性。 校正假定 固定不变;机械或热变形导致挠曲的相机装置需要定期重新标定或在线外参优化。
- 快门必须同步。 如果两个相机在不同的时刻曝光,运动平台会有效地导致每帧的基线发生变化——任何静态校正都无法修复这一点。
对SLAM的意义
几乎每一个双目 SLAM 前端——ORB-SLAM2 的逐关键点双目匹配、S-PTAM,以及 Kimera 中基于 SGM 的稠密建图——都假定输入已经过校正,因为扫描线搜索是以实时速率获得逐帧深度的唯一方法。理解校正原理也能告诉你双目流程会在哪里出问题:标定不良、快门不同步或鱼眼光学系统,都会在任何 SLAM 代码运行之前就违反了校正模型。