立体校正

立体校正对经过标定的双目图像对进行变形处理,使它们看起来像是来自两个理想的、平行的相机:图像平面共面,光轴平行,行对齐。校正之后,左图像中任意像素的外极线在右图像中就是简单的同一行

为什么这样有效:对于任意一对相机位姿,外极几何将左图像中一点的匹配约束到右图像中的一条一维曲线(对于针孔相机是一条直线)上。校正是应用于图像的一对单应变换 HL,HRH_L, H_R,它们将两个极点沿水平轴映射到无穷远处,使所有外极线都变为水平且垂直对齐。

校正变换如何计算

给定标定好的内参 KL,KRK_L, K_R、镜头畸变,以及两相机之间的外参变换 (R,t)(R, t),OpenCV 的 stereoRectify 所使用的经典(Bouguet)构造方法过程如下:

  1. 拆分相对旋转。 将每个相机旋转 RR 的”一半”,使两个光轴变得平行,同时尽量减少对每幅图像的扰动。
  2. 与基线对齐。 应用一个共同的旋转,使新的 xx 轴指向基线向量 tt 的方向。此时两个极点都位于无穷远处,因此外极线是水平的。
  3. 选择共同的虚拟内参。 为两个视图选择一个新的相机矩阵 KnewK_{\text{new}}(相同的 ff,相同的主点所在行),使校正后的图像对拥有同一个焦距和同一个基线,用于 Z=fB/dZ = fB/d
  4. 预烘焙重映射表。 每个相机的变形 H=KnewRrectKold1H = K_{\text{new}} R_{\text{rect}} K_{\text{old}}^{-1} 与镜头去畸变模型相结合,预先计算成查找表,因此校正每一帧的成本只是一次图像重映射。
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)

返回的 QQ 矩阵可以将校正后的像素加视差 (u,v,d)(u, v, d) 直接重投影到三维空间——这是矩阵形式的视差到深度转换。

它带来的好处

检查校正质量

一个快速的合理性检验:在校正后的图像之间匹配特征,并检查垂直视差 vLvRv_L - v_R。在一个校正良好的图像对上,它应该只是一个像素的极小一部分;系统性的偏移或图像上的梯度变化意味着外参标定已经漂移。随着机器人使用时间增长而不断上升的垂直视差,是相机装置被碰撞或热变形的典型症状。

实践注意事项

对SLAM的意义

几乎每一个双目 SLAM 前端——ORB-SLAM2 的逐关键点双目匹配、S-PTAM,以及 Kimera 中基于 SGM 的稠密建图——都假定输入已经过校正,因为扫描线搜索是以实时速率获得逐帧深度的唯一方法。理解校正原理也能告诉你双目流程会在哪里出问题:标定不良、快门不同步或鱼眼光学系统,都会在任何 SLAM 代码运行之前就违反了校正模型。

相关条目