4. 外参矩阵:旋转矩阵R与平移向量t,刚体变换的SE(3)表示

好,我们继续往下走。前面几章我们把内参、畸变、像素坐标系这些理清楚了。现在要聊的,是异构摄像头融合里最核心、也最容易出bug的一环——外参矩阵。

说白了,外参就是回答一个问题:这个摄像头在三维空间里到底在哪儿?脸朝哪边?

你想想看,两个摄像头拍同一个场景,如果不知道它们之间的相对位置和朝向,你怎么把像素点对应起来?没法对应。所以外参矩阵,就是描述这种“刚体变换”的数学工具。

核心概念:外参矩阵 = 旋转矩阵 R + 平移向量 t,合起来就是 SE(3) 变换。

4.1 刚体变换:不改变物体形状的移动

什么叫刚体变换?我举个生活中的例子。你手里拿个手机,从桌上拿到耳边——手机本身没变形、没摔碎,只是位置和朝向变了。这就是刚体变换。

在三维空间里,刚体变换只有两种运动:

  • 旋转——绕某个轴转个角度
  • 平移——沿着某个方向挪一段距离

没有缩放,没有剪切,没有扭曲。这一点非常重要。我在项目里见过有人把外参矩阵里的旋转部分写错了,结果点云直接扭曲成一团麻花……嗯,那画面太美我不敢看。

4.2 旋转矩阵 R:3×3 的正交矩阵

旋转矩阵 R 是一个 3×3 的方阵。它有几个硬性约束:

  • 每一列都是单位向量
  • 列与列之间互相垂直
  • 行列式等于 +1(右手系)

用数学语言说,R 是 特殊正交群 SO(3) 的元素。说白了就是:R^T R = I,且 det(R) = 1。

绕 X、Y、Z 三个轴的旋转矩阵长这样:

// 绕 X 轴旋转 θ 角
R_x(θ) = [1,      0,       0;
          0,  cosθ,  -sinθ;
          0,  sinθ,   cosθ]

// 绕 Y 轴旋转 θ 角
R_y(θ) = [ cosθ,  0,  sinθ;
              0,  1,      0;
          -sinθ,  0,  cosθ]

// 绕 Z 轴旋转 θ 角
R_z(θ) = [cosθ, -sinθ,  0;
          sinθ,  cosθ,  0;
             0,      0,  1]
我的习惯:在实际代码里,我从来不用这三个矩阵直接乘。因为欧拉角有万向锁问题。我建议用四元数或者轴角表示法,最后再转成矩阵。省心。

4.3 平移向量 t:3×1 的位移

平移向量 t 就简单多了。它就是三个数:[t_x, t_y, t_z]^T,表示从世界坐标系原点到摄像头坐标系原点的位移。

注意:这个平移是在世界坐标系下度量的,还是在摄像头坐标系下?

答案是:平移向量 t 是世界坐标系原点在摄像头坐标系下的坐标。这个方向别搞反了。我曾经在调试双目融合时,因为 t 的符号搞反,结果两个摄像头的点云一个在东一个在西……排查了整整两天。

避坑指南:外参矩阵的平移部分,一定要确认你的坐标系定义。OpenCV、ROS、Pytorch3D 的坐标系习惯都不一样。我建议你在项目一开始就写一个坐标系检查函数,打印几个已知点的投影结果,肉眼验证。

4.4 SE(3):把旋转和平移打包

旋转矩阵 R 和平移向量 t 单独用着不方便。我们通常把它们组合成一个 4×4 的齐次变换矩阵:

T = [R  t;
     0  1]

// 展开就是:
T = [r11, r12, r13, t_x;
     r21, r22, r23, t_y;
     r31, r32, r33, t_z;
       0,   0,   0,   1]

这个 T 就是 特殊欧氏群 SE(3) 的表示。它把旋转和平移统一成一个矩阵,方便做连续变换。

为什么用齐次坐标?因为你可以把多个变换串起来:

// 从世界坐标到摄像头1,再到摄像头2
T_cam2_world = T_cam2_cam1 * T_cam1_world

用 4×4 矩阵乘法,一次搞定。不用先旋转再平移,省事。

4.5 外参矩阵的几何意义

我们来看一个完整的坐标映射流程:

  1. 世界坐标系下有一个点 P_w = [X, Y, Z, 1]^T(齐次坐标)
  2. 左乘外参矩阵 T:P_c = T * P_w
  3. 得到摄像头坐标系下的坐标 P_c = [X', Y', Z', 1]^T
  4. 再左乘内参矩阵 K,得到像素坐标

所以外参矩阵的本质,就是把世界坐标系“搬”到摄像头坐标系。

一句话总结:外参矩阵描述的是“摄像头怎么看世界”,而不是“世界怎么看摄像头”。

4.6 知识结构图:外参矩阵的组成与作用

下面这张图把外参矩阵的层级关系画清楚了:

外参矩阵知识结构图 外参矩阵:SE(3) 刚体变换 外参矩阵 T (4×4) 旋转矩阵 R (3×3) 平移向量 t (3×1) 绕 X 轴 绕 Y 轴 绕 Z 轴 X 方向 Y 方向 Z 方向 约束条件 R^T R = I, det(R) = 1 | t 无约束,自由平移

4.7 外参矩阵的获取方式

在实际工程里,外参矩阵怎么来?我总结了几种常见方式:

方法 精度 适用场景 我的评价
标定板 + 张正友法 高 实验室、产线 最可靠,我首选
手眼标定 (Hand-Eye) 中高 机械臂 + 摄像头 注意坐标系对齐
CAD 模型 + 安装尺寸 低 固定安装、粗略估计 只能做初值
SFM / 视觉SLAM 中 无标定板、大场景 需要足够特征点
我的建议:如果你做异构摄像头融合(比如RGB + 红外 + 深度),一定要用同一个标定板同时标定所有摄像头的外参。分开标定再拼,误差会累积。我吃过这个亏。

4.8 逆变换:从摄像头坐标系回到世界坐标系

有时候我们需要反过来——已知摄像头坐标系下的点,求它在世界坐标系下的坐标。这时候就用外参矩阵的逆:

T_inv = [R^T,  -R^T * t;
          0,       1]

注意:不是简单的取逆矩阵,而是利用 R 的正交性 R^{-1} = R^T 来简化计算。这样算起来快,而且数值稳定。

注意:千万不要直接用 np.linalg.inv(T) 去求逆。虽然数学上等价,但数值误差更大。用上面那个公式,又快又准。

4.9 小结

外参矩阵,说白了就是四个字:旋转 + 平移。但就是这看似简单的组合,在实际项目中坑最多。

  • 坐标系定义不一致——坑
  • 旋转矩阵不满足正交性——坑
  • 平移方向搞反——坑
  • 齐次坐标忘加最后一维 1——坑

我建议你每次写完外参相关的代码,都做一个闭环验证:取一个世界坐标点,投影到像素,再反投影回来,看误差有多大。这个习惯救了我很多次。