4. 相机外参矩阵:旋转矩阵R与平移向量t

好,我们继续往下走。前面聊完了内参,说白了就是相机自己“肚子里的那点事”——焦距、主点、畸变。但相机是放在世界里的,它得知道“我在哪”、“我在看哪”。这就是外参要解决的问题。

外参矩阵,本质上就是一个刚体变换。它把世界坐标系里的一个点,映射到相机坐标系里。我习惯这么理解:世界坐标系是“上帝视角”,相机坐标系是“我眼里的世界”。外参就是连接这两个视角的桥梁。

4.1 刚体变换:旋转 + 平移

刚体变换,说白了就是物体只做旋转和平移,不发生形变。你想想看,你把手机从桌上拿到手里,手机本身没变形吧?这就是刚体变换。

数学上,一个刚体变换可以拆成两部分:

  • 旋转矩阵 R:描述坐标轴的朝向变化。3x3 的矩阵,正交且行列式为 +1。
  • 平移向量 t:描述坐标系原点的位置偏移。3x1 的向量。

所以,从世界坐标 Pw 到相机坐标 Pc 的映射就是:

Pc = R * Pw + t

嗯,这里要注意,这个公式是世界点转到相机坐标系。很多初学者会搞反方向,我刚开始也栽过这个坑。

核心理解:外参矩阵 [R | t] 描述的是“世界坐标系相对于相机坐标系”的位姿。换句话说,它告诉相机:“嘿,世界原点在你眼里是这么个位置和朝向。”

4.2 旋转矩阵 R 的细节

旋转矩阵 R 有 9 个元素,但自由度只有 3。为什么?因为它必须满足两个约束:

  1. 正交性:RTR = I,即矩阵的列向量两两正交。
  2. 行列式为 +1:保证是右手系,不产生镜像。

我在项目中遇到过一个问题:标定出来的 R 矩阵行列式不是 +1,而是 -1 或者 0.999。这通常是因为标定数据有噪声,或者标定板角点检测出了偏差。我的处理方式是:用 SVD 分解强制正交化。

实用技巧:强制正交化的代码很简单:

import numpy as np
U, _, Vt = np.linalg.svd(R)
R_ortho = U @ Vt
# 如果行列式为 -1,调整最后一列符号
if np.linalg.det(R_ortho) < 0:
    Vt[-1, :] *= -1
    R_ortho = U @ Vt

这样就能得到一个“干净”的旋转矩阵。

4.3 平移向量 t 的物理意义

平移向量 t 不是世界坐标系原点的位置,而是相机坐标系原点在世界坐标系中的位置的负值,再经过旋转。公式上:

t = -R * Cw

其中 Cw 是相机光心在世界坐标系中的坐标。

说白了,t 告诉你:从相机看出去,世界原点在哪。我习惯在调试时直接打印 t 的数值,看看它是不是在合理范围内。比如标定一个桌面上的相机,t 的 z 分量应该是相机到桌面的距离,单位是毫米或米。

参数 维度 自由度 物理含义
R 3x3 3 世界坐标轴在相机坐标系中的朝向
t 3x1 3 世界原点在相机坐标系中的位置
[R|t] 3x4 6 完整的刚体变换

4.4 从世界坐标系到相机坐标系的完整映射

把旋转和平移合在一起,我们通常写成齐次坐标形式:

| Xc |   | R11 R12 R13 t1 |   | Xw |
| Yc | = | R21 R22 R23 t2 | * | Yw |
| Zc |   | R31 R32 R33 t3 |   | Zw |
|  1  |   |  0    0    0    1  |   |  1  |

这个 4x4 矩阵就是外参矩阵,也叫相机位姿矩阵。它把世界坐标系下的齐次点,映射到相机坐标系下。

我曾经在做一个多相机拼接项目时,发现两个相机的拼接缝总是对不齐。排查了半天,最后发现是其中一个相机的外参矩阵里的 R 写反了——我用了 RT 而不是 R。嗯,从那以后我每次都会检查:用外参把几个已知的世界坐标点投影到图像上,看看是不是在正确位置。

避坑指南:我曾经在 OpenCV 的 solvePnP 和 calibrateCamera 之间切换时,搞混了 R 和 t 的表示方式。OpenCV 的 calibrateCamera 返回的 R 和 t 是“从世界到相机”,而某些 SLAM 库用的是“从相机到世界”。一定要看清楚文档!

4.5 外参矩阵的几何意义

外参矩阵的每一列都有几何意义:

  • R 的第一列:世界坐标系 X 轴在相机坐标系中的方向向量
  • R 的第二列:世界坐标系 Y 轴在相机坐标系中的方向向量
  • R 的第三列:世界坐标系 Z 轴在相机坐标系中的方向向量
  • t:世界坐标系原点在相机坐标系中的位置

你想想看,如果你知道了这三个轴的方向和原点的位置,你是不是就知道了相机相对于世界的完整位姿?这就是外参矩阵的直观理解。

下面我画了一张图,帮你理清整个映射流程:

世界坐标系到相机坐标系的刚体变换流程 外参矩阵:世界坐标系 → 相机坐标系 世界坐标系 Pw = (Xw, Yw, Zw) 旋转 R 旋转后 R * Pw 平移 t 相机坐标系 Pc = R*Pw + t 外参矩阵 [R | t] 的组成 R (3x3):旋转,3 个自由度(欧拉角 / 轴角 / 四元数) t (3x1):平移,3 个自由度 → 总共 6 个自由度 齐次坐标形式:Pc = [R | t] * Pw,其中 Pw = (Xw, Yw, Zw, 1)T 这样就把旋转和平移统一到一个 4x4 矩阵里了

4.6 实际项目中的注意事项

最后,我分享几个在实际项目中积累的经验:

  • 单位统一:世界坐标系和 t 的单位必须一致。我见过有人用毫米标定,但 t 的单位是米,结果投影全偏了。
  • 坐标系定义:标定板上的世界坐标系通常定义在左上角或中心,Z 轴垂直于板面。这个定义要贯穿始终。
  • 外参的物理合理性:标定出来的 t 应该和实际测量值大致吻合。如果差太多,检查标定数据或者标定板尺寸。
  • 多相机标定:如果多个相机共用一个世界坐标系,它们的外参都是相对于同一个世界坐标系的。这时候拼接就简单了——直接根据外参把点转到同一个坐标系下。

我的习惯:每次标定完,我都会做一次“重投影验证”。用标定出来的内外参,把标定板上的角点反投到图像上,看看误差有多大。如果重投影误差超过 0.5 像素,我就会重新标定。这个习惯帮我避免了很多后期调试的麻烦。

好了,外参矩阵的核心内容就这些。记住:R 和 t 加起来 6 个自由度,描述的是相机在世界中的位姿。搞懂了它,你就掌握了“从世界到相机”这一关键映射。