4、外参一致性:四相机间旋转矩阵与平移向量闭环验证

外参标定完了,拿到四组旋转矩阵和平移向量,是不是就完事了?

我告诉你,还早着呢。标定结果好不好,得看它能不能「闭环」。

什么叫闭环?说白了,就是我从相机1走到相机2,再从相机2走到相机3,最后从相机3走回相机1,转了一圈,应该回到原点。如果回不来,那中间肯定有误差。

4.1 为什么需要闭环验证?

四相机联合标定,我们通常以其中一个相机为参考系(比如相机1),然后标出相机2→1、相机3→1、相机4→1的外参。但这里有个隐含假设——这些变换关系是自洽的。

实际项目中,我遇到过好几次这样的情况:单独看每对相机的重投影误差都挺小,0.1个像素以内,但把四台相机的位姿放到同一个全局坐标系里一看,完全对不上。为什么?因为每对标定都有独立误差,累积起来就大了。

核心思想: 外参一致性要求任意两个相机之间的变换,无论通过直接标定还是间接推导,结果必须一致。

举个例子。相机1到相机2的变换是 T₁₂,相机2到相机3是 T₂₃,相机3到相机1是 T₃₁。理论上,T₁₂ · T₂₃ · T₃₁ 应该等于单位矩阵 I。如果不等于,误差就出来了。

4.2 闭环误差的数学表达

我们定义闭环误差为:

E_loop = T₁₂ · T₂₃ · T₃₄ · T₄₁ - I

其中 T₄₁ 是相机4到相机1的变换矩阵。理想情况下,E_loop 应该是零矩阵。

但实际中,E_loop 不会为零。我们需要把它分解成旋转误差和平移误差两部分来看。

误差类型 数学表达 物理含义
旋转闭环误差 R_loop = R₁₂ · R₂₃ · R₃₄ · R₄₁ 绕一圈后,角度偏差有多大
平移闭环误差 t_loop = R₁₂·(R₂₃·(R₃₄·t₄₁ + t₃₄) + t₂₃) + t₁₂ 绕一圈后,位置偏差有多大

旋转闭环误差可以用轴角表示,提取出等效旋转角度 θ_loop。如果 θ_loop 超过 0.5°,我建议你重新检查标定数据。平移闭环误差则看向量模长,一般要求小于 5mm,具体看你的应用场景。

我的经验: 平移误差比旋转误差更敏感。有时候旋转误差看起来还行,但平移已经偏出去好几厘米了。所以两个都要看,别只看一个。

4.3 闭环验证的实操步骤

嗯,这里我直接给出一套我常用的验证流程:

  1. 构建闭环链:确定相机之间的连接顺序。四相机系统通常有多个闭环,比如 1→2→3→1、1→2→4→1、1→3→4→1。每个闭环都要验证。
  2. 计算累积变换:从起始相机出发,依次乘上相邻相机的变换矩阵,直到回到起始相机。
  3. 提取误差:从累积变换中提取旋转矩阵和平移向量,与单位矩阵比较。
  4. 评估阈值:判断误差是否在可接受范围内。
  5. 定位问题:如果某个闭环误差特别大,说明该闭环中的某对相机标定有问题。

下面这张图展示了四相机系统的闭环验证逻辑:

四相机闭环验证结构图 相机 1 (参考系) 相机 2 相机 3 相机 4 T₁₂ T₂₃ T₃₁ T₁₄ T₄₃ T₂₄ (可选) 闭环 1: 1→2→3→1   |   闭环 2: 1→2→4→1   |   闭环 3: 1→3→4→1

4.4 代码实现:闭环误差计算

我习惯用 Python + NumPy 来做这件事。下面是一个完整的闭环验证函数:

import numpy as np

def compute_loop_error(T_list):
    """
    计算闭环误差
    T_list: 按顺序排列的变换矩阵列表,[T₁₂, T₂₃, T₃₄, T₄₁]
    返回: 旋转误差(度), 平移误差(mm)
    """
    # 累积变换
    T_accum = np.eye(4)
    for T in T_list:
        T_accum = T_accum @ T
    
    # 提取旋转部分
    R_loop = T_accum[:3, :3]
    t_loop = T_accum[:3, 3]
    
    # 旋转误差:转为轴角
    theta = np.arccos((np.trace(R_loop) - 1) / 2)
    rot_error = np.degrees(theta)
    
    # 平移误差:向量模长
    trans_error = np.linalg.norm(t_loop)
    
    return rot_error, trans_error

# 使用示例
T12 = np.array([[...]])  # 你的标定结果
T23 = np.array([[...]])
T34 = np.array([[...]])
T41 = np.array([[...]])

rot_err, trans_err = compute_loop_error([T12, T23, T34, T41])
print(f"旋转闭环误差: {rot_err:.3f}°")
print(f"平移闭环误差: {trans_err:.3f} mm")
注意: 变换矩阵的乘法顺序不能搞反。T₁₂ 表示从相机2坐标系变换到相机1坐标系。如果你用的定义相反,记得调整。

4.5 误差溯源与调整策略

闭环误差超标了怎么办?别急着重新标定所有相机。先定位问题出在哪一对。

我常用的方法是「逐段排除法」:

  • 先看每个闭环的误差大小,找出误差最大的那个闭环。
  • 在这个闭环里,依次去掉某对相机的变换,用其他变换推导它,然后和直接标定结果对比。
  • 如果推导结果和直接标定结果差异很大,那这对相机大概率有问题。

举个例子。闭环 1→2→3→1 误差很大。我可以用 T₁₃(直接标定)和 T₁₂·T₂₃(间接推导)做对比。如果两者差异明显,说明 T₁₂ 或 T₂₃ 有问题。再用 T₁₂ 和 T₁₃·T₃₂ 对比,就能锁定具体是哪一对。

对比方式 直接标定 间接推导 差异阈值
相机1→3 T₁₃(直接标) T₁₂ · T₂₃ 旋转 < 0.3°,平移 < 3mm
相机2→4 T₂₄(直接标) T₂₁ · T₁₄ 旋转 < 0.3°,平移 < 3mm
相机3→1 T₃₁(直接标) T₃₄ · T₄₁ 旋转 < 0.3°,平移 < 3mm
避坑指南: 我曾经遇到过一个情况,所有闭环误差都在阈值内,但实际拼接出来的点云就是有裂缝。后来发现是标定板的精度不够,导致所有外参都有系统性偏差。闭环验证只能发现相对误差,精度还得靠其他方法验证。

4.6 一致性指标与验收标准

最后,我给出一个我常用的验收标准表。你可以根据项目精度要求适当调整:

指标 优秀 合格 需调整
旋转闭环误差 < 0.1° 0.1° ~ 0.5° > 0.5°
平移闭环误差 < 1 mm 1 ~ 5 mm > 5 mm
直接/间接对比差异 < 0.05° / < 0.5 mm 0.05°~0.3° / 0.5~3 mm > 0.3° / > 3 mm

记住,闭环验证只是外参一致性检查的第一步。它保证的是「相对关系」没错,但「位姿」准不准,还得靠后续的全局优化和实际测量来确认。不过,先把这一步做好,能省掉后面很多麻烦。