3. 坐标系与空间变换

多摄像头系统里,最绕不开的一个基础问题就是——坐标统一。

说白了,每个摄像头都有自己的“小世界”,它们各自看到的东西,位置、角度都不一样。你要把这些信息拼在一起,就必须先搞清楚:一个点,在哪个坐标系里?怎么从一个坐标系变到另一个?

我个人习惯把这一整套东西叫做“坐标系的六脉神剑”。你掌握了它,后面做标定、做融合,心里就有底了。

3.1 四个核心坐标系

我们先从最熟悉的开始,一步步往像素走。

坐标系 单位 原点 维度 典型坐标
世界坐标系 米 / 毫米 人为定义(如地面一角) 3D (Xw, Yw, Zw) 物体在真实世界的位置
相机坐标系 米 / 毫米 相机光心 3D (Xc, Yc, Zc) 以相机为原点的3D坐标
图像坐标系 毫米 图像平面中心(主点) 2D (x, y) 物理成像平面上的位置
像素坐标系 像素 图像左上角 2D (u, v) 你在图像上看到的行列号

核心记忆点:世界→相机是刚体变换(旋转+平移),相机→图像是投影变换(小孔成像),图像→像素是离散化(缩放+平移)。

3.2 刚体变换:世界坐标系 → 相机坐标系

刚体变换,就是只改变物体的位置和朝向,不改变它的形状和大小。你想想看,你把一个杯子从桌上拿到手里,杯子本身没变形,这就是刚体变换。

数学上,它由一个旋转矩阵 R 和一个平移向量 t 组成。

// 刚体变换公式
// Pc = R * Pw + t

// 其中:
// Pw = [Xw, Yw, Zw]^T   —— 世界坐标系下的点
// Pc = [Xc, Yc, Zc]^T   —— 相机坐标系下的点
// R  = 3x3 旋转矩阵
// t  = 3x1 平移向量

我在项目中遇到过一个问题:两个摄像头安装角度差了不到1度,但融合出来的点云就是有重影。后来发现,就是旋转矩阵 R 的精度不够。所以,刚体变换的精度,直接决定了多摄像头融合的成败。

避坑指南:我曾经在标定的时候,把旋转矩阵和平移向量的顺序搞反了。记住,是先旋转,再平移。顺序错了,结果就是天差地别。

3.3 投影变换:相机坐标系 → 图像坐标系

这一步,就是小孔成像模型。相机坐标系下的3D点,通过光心投影到成像平面上。

// 投影变换公式(理想针孔模型)
// x = f * Xc / Zc
// y = f * Yc / Zc

// 其中:
// f —— 焦距(单位:毫米)
// (Xc, Yc, Zc) —— 相机坐标系下的3D点
// (x, y) —— 图像坐标系下的2D点

这里有个关键点:Zc 不能为0。你想想看,如果物体正好在相机光心所在的平面上,那它在图像上就成一个点了,这在实际中几乎不可能,但数学上要小心。

3.4 离散化:图像坐标系 → 像素坐标系

图像坐标系是连续的物理坐标(毫米),而像素坐标系是离散的整数坐标(像素)。这一步就是把物理尺寸映射到像素网格上。

// 离散化公式
// u = x / dx + u0
// v = y / dy + v0

// 其中:
// dx, dy —— 每个像素在x和y方向上的物理尺寸(毫米/像素)
// (u0, v0) —— 主点(图像坐标系原点)在像素坐标系中的位置

嗯,这里要注意:dx 和 dy 不一定相等。如果摄像头传感器的像素不是正方形,那就会导致图像在横纵方向上的缩放比例不同。我在做鱼眼摄像头标定时,就遇到过这种非正方形像素的情况,处理起来要格外小心。

3.5 完整变换链路

把上面三步串起来,就是一个点从世界坐标到像素坐标的完整旅程。

// 完整变换(齐次坐标形式)
// s * [u, v, 1]^T = K * [R | t] * [Xw, Yw, Zw, 1]^T

// 其中:
// K —— 相机内参矩阵(包含fx, fy, u0, v0)
// [R | t] —— 相机外参矩阵(刚体变换)
// s —— 尺度因子(其实就是 Zc)

我的习惯:在实际代码中,我通常会用齐次坐标来写,这样可以把旋转和平移合并成一个4x4的矩阵,计算起来非常方便。OpenCV 和 Eigen 库都支持这种操作。

3.6 知识体系结构图

下面这张图,把整个坐标系变换的流程和关系画清楚了。你可以把它当作一张“地图”,随时回来查阅。

坐标系变换流程结构图 坐标系变换流程结构图 世界坐标系 (Xw, Yw, Zw) 相机坐标系 (Xc, Yc, Zc) 图像坐标系 (x, y) 像素坐标系 (u, v) 刚体变换 R, t 投影变换 小孔成像 离散化 dx, dy, u0, v0 说明: 1. 世界→相机:刚体变换,不改变物体形状,只改变位置和朝向。 2. 相机→图像:投影变换,3D到2D的降维,丢失深度信息。 3. 图像→像素:离散化,从连续物理坐标到离散像素坐标。

3.7 多摄像头场景下的坐标系统一

在多摄像头系统中,每个摄像头都有自己的相机坐标系。你要做融合,就必须把所有摄像头的数据都统一到同一个世界坐标系下。

我常用的做法是:

  1. 选择一个主摄像头,把它作为世界坐标系的原点。
  2. 标定其他摄像头相对于主摄像头的刚体变换(R, t)。
  3. 所有数据都先变换到主摄像头的坐标系下,再统一处理。

实战经验:我在做自动驾驶的多摄像头环视系统时,就是用的这个方法。先把四个鱼眼摄像头都标定到车身坐标系(世界坐标系)下,然后做鸟瞰图变换。这样,不管哪个摄像头看到障碍物,最终都能在车身坐标系下找到它的准确位置。

3.8 常见问题与避坑

  • 坐标系方向搞反:旋转矩阵有正负之分,平移向量也有方向。我曾经因为一个符号错误,导致融合后的点云全部跑到车底下去。所以,标定完一定要做可视化验证。
  • 内参不准:相机内参 K 矩阵如果标定不准,后面的所有变换都会出错。我建议每半年重新标定一次,特别是摄像头有震动或温度变化大的场景。
  • 尺度因子 s 忽略:在齐次坐标变换中,s 就是 Zc。如果你忘了除以 s,那得到的像素坐标就是错的。这个坑,我踩过不止一次。

重要提醒:坐标系变换是数学,但更是工程。不要只背公式,一定要动手写代码、画图、验证。我见过太多人,公式背得滚瓜烂熟,一上手就出错。