3. 坐标系与变换

做视觉标定,说白了就是在玩坐标系。你想想看,一个三维空间里的点,要变成照片上的一个像素,中间要经历多少层“翻译”?我刚开始接触这行时,总觉得这些坐标系很抽象,直到有一次在现场调一个机械臂抓取项目,标定参数算错了,机器人直接抓了个空。嗯,从那以后,我对坐标系变换再也不敢马虎了。

这一章,我们就来把这四个坐标系之间的变换关系彻底理清楚。你掌握了这个,标定的底层逻辑就通了。

3.1 四个坐标系,各司其职

先认识一下这四位“主角”。它们各自负责一个环节,缺一不可。

坐标系 英文简称 维度 作用
世界坐标系 World 3D (Xw, Yw, Zw) 描述物体在真实世界中的位置,是全局基准
相机坐标系 Camera 3D (Xc, Yc, Zc) 以相机光心为原点,描述物体相对于相机的位置
图像坐标系 Image 2D (x, y) 在成像平面上,以物理单位(毫米)表示投影位置
像素坐标系 Pixel 2D (u, v) 在图像上,以像素为单位,描述行列位置

我个人习惯把整个变换过程想象成一条流水线:世界上的一个点,先通过刚体变换转到相机坐标系下,再通过投影变换落到成像平面上,最后通过仿射变换变成像素坐标。

核心逻辑: 整个标定过程,就是求解这条流水线上所有未知参数的过程。

3.2 刚体变换:从世界到相机

刚体变换,说白了就是旋转加平移。物体本身不会变形,只是换个角度看它。从世界坐标系到相机坐标系,就是这个关系。

数学表达式很简单:

|Xc|   | R11 R12 R13 | |Xw|   |Tx|
|Yc| = | R21 R22 R23 | |Yw| + |Ty|
|Zc|   | R31 R32 R33 | |Zw|   |Tz|

写成齐次坐标形式,更简洁:

|Xc|   | R   T | |Xw|
|Yc| = |       | |Yw|
|Zc|   | 0   1 | |Zw|
|1 |            |1 |

这里的 R 是 3x3 旋转矩阵,T 是 3x1 平移向量。它们合起来就是相机的外参。

我的经验: 旋转矩阵虽然有9个元素,但自由度只有3(绕X、Y、Z轴的旋转角)。实际标定时,我们通常用旋转向量或欧拉角来优化,避免矩阵的正交约束问题。

3.3 投影变换:从相机到图像

这一步是“从3D到2D”的关键。相机坐标系下的点,通过小孔成像模型,投影到成像平面上。

公式很直观:

x = f * Xc / Zc
y = f * Yc / Zc

其中 f 是焦距。你看,Zc 被除掉了,深度信息在这一步丢失了。这也是为什么单张图片无法直接恢复三维深度——你想想看,一个近处的小物体和一个远处的大物体,可能在图像上投影成同样大小。

用齐次坐标写:

|x|   | f 0 0 0 | |Xc|
|y| = | 0 f 0 0 | |Yc|
|1|   | 0 0 1 0 | |Zc|
                   |1 |
注意: 这里用的是理想针孔模型。实际镜头会有畸变,投影关系会更复杂。我曾经在一个项目中忽略了镜头畸变,结果标定出来的外参偏差了2个毫米,导致抓取精度完全不合格。所以,畸变校正一定要做。

3.4 仿射变换:从图像到像素

成像平面上的物理坐标 (x, y) 最终要变成我们看到的像素 (u, v)。这一步涉及两个因素:

  • 缩放: 像素的物理尺寸 (dx, dy),单位是 mm/pixel
  • 偏移: 主点 (u0, v0),即光轴与成像平面的交点

公式:

u = x / dx + u0
v = y / dy + v0

齐次坐标形式:

|u|   | 1/dx  0    u0 | |x|
|v| = |  0   1/dy  v0 | |y|
|1|   |  0    0    1  | |1|

这部分参数,加上焦距 f,统称为相机的内参。

3.5 完整变换链:一张图看懂

把上面三步串起来,就是完整的变换过程。我画了一张图,帮你把整个逻辑串起来。

坐标系变换流程 坐标系变换全流程 世界坐标系 (Xw, Yw, Zw) 刚体变换 相机坐标系 (Xc, Yc, Zc) 投影变换 图像坐标系 (x, y) 仿射变换 像素坐标系 (u, v) 外参(Extrinsics) R(旋转) + T(平移) 描述相机在世界中的位姿 内参(Intrinsics) f, dx, dy, u0, v0 描述相机本身的成像特性 标定的本质:求解外参 + 内参 世界点 → 刚体变换 → 投影变换 → 仿射变换 → 像素点 已知 3D-2D 对应点,反向求解变换参数

3.6 综合变换公式

把上面三步合并,就得到了从世界坐标到像素坐标的完整公式:

|u|   | fx  0   u0  0 | | R   T | |Xw|
|v| = | 0   fy  v0  0 | |       | |Yw|
|1|   | 0   0   1   0 | | 0   1 | |Zw|
                         |       | |1 |

其中 fx = f/dx,fy = f/dy。这个 3x4 的矩阵,就是相机的投影矩阵 P。

一句话总结: P = K [R | T],其中 K 是内参矩阵,[R | T] 是外参矩阵。标定就是求 P,或者分别求 K 和 [R | T]。

3.7 避坑指南:我踩过的几个坑

  • 坐标系方向搞反: 我曾经在定义世界坐标系时,把Z轴方向搞反了,结果标定出来的外参旋转矩阵全是错的。后来我养成了一个习惯:标定前先用一张棋盘格,手动验证一下坐标轴方向。
  • 齐次坐标忘记加1: 写代码时容易把世界坐标写成 (Xw, Yw, Zw) 而不是 (Xw, Yw, Zw, 1)。这个低级错误会导致矩阵乘法维度不匹配,结果全乱套。
  • 忽略畸变模型: 很多初学者只标定内参外参,不做畸变校正。结果投影误差很大。记住,畸变参数也是内参的一部分,必须一起标定。
我的建议: 刚开始做标定时,先用仿真数据验证你的变换公式。在仿真环境里,所有参数都是已知的,你可以精确地验证每一步变换是否正确。等仿真通过了,再上真实相机。这样能省去大量调试时间。

好了,坐标系变换这块内容,说白了就是“世界→相机→图像→像素”这条链。你把这个链条刻在脑子里,后面的标定算法就很好理解了。