2. 坐标系与变换:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换关系,齐次坐标与刚体变换

做外参标定,说白了就是在玩坐标系之间的“翻译”游戏。

你想想看,相机看到的是一堆像素点,而机器人或者自动驾驶车需要知道这些点在世界里的真实位置。这中间差了四层坐标系要打通。我刚开始接触这块时,总觉得公式太多、绕得头晕。后来发现,只要把每个坐标系当成一个“视角”,问题就简单多了。

2.1 四个坐标系,一个故事

我们先捋清楚这四个坐标系分别长什么样:

  • 世界坐标系 (World Coordinate System):你选的一个固定参考系。比如房间的墙角、路边的电线杆。单位是米。
  • 相机坐标系 (Camera Coordinate System):以相机光心为原点,Z轴指向镜头前方。单位也是米。
  • 图像坐标系 (Image Coordinate System):在成像平面上,原点在光轴与平面的交点(主点)。单位是毫米。
  • 像素坐标系 (Pixel Coordinate System):就是图像数组的行列索引。原点在左上角,单位是像素。

嗯,这里要注意:世界坐标系到相机坐标系,是刚体变换(旋转+平移)。相机坐标系到图像坐标系,是透视投影(针孔模型)。图像坐标系到像素坐标系,是离散化缩放加平移。

核心一句话:外参标定要解的,就是世界坐标系到相机坐标系的那个旋转矩阵R和平移向量t。

2.2 齐次坐标:为什么我们需要它?

你可能会问:为什么非要用齐次坐标?直接用三维坐标不行吗?

我举个例子。假设你要把世界点P_w先旋转再平移,得到相机坐标P_c。用普通三维坐标写出来是:

P_c = R * P_w + t

这看起来还行。但如果连续做多次变换,比如从世界到相机、相机到图像、图像到像素,每次都要写一个加法一个乘法,公式会变得又臭又长。

齐次坐标的妙处在于:把平移也塞进矩阵里。这样所有变换都统一成矩阵乘法。

三维点的齐次坐标是 (x, y, z, 1)。平移向量t变成矩阵的第四列。于是上面的变换变成:

| P_c_x |   | R11 R12 R13 t1 |   | P_w_x |
| P_c_y | = | R21 R22 R23 t2 | * | P_w_y |
| P_c_z |   | R31 R32 R33 t3 |   | P_w_z |
|   1   |   |  0   0   0   1  |   |   1   |

你看,一个矩阵搞定旋转和平移。我个人习惯把所有变换都写成4x4矩阵,这样代码里就是一连串的矩阵乘法,清晰又好调试。

小技巧:齐次坐标的最后一维是1表示点,是0表示方向向量。方向向量不会被平移影响——这个细节在计算光心方向时特别有用。

2.3 刚体变换:旋转矩阵与平移向量

刚体变换,说白了就是“拿着一个物体,不捏变形,只转一转、挪一挪”。

旋转矩阵R有三个自由度(绕X、Y、Z轴旋转),但9个元素之间必须满足正交约束(R^T * R = I,行列式为+1)。我刚开始写代码时,直接优化9个元素,结果出来的矩阵根本不是旋转矩阵。后来改用李代数(so3)表示旋转,才彻底解决了这个问题。

平移向量t就是三个方向的位移,简单直接。

完整的刚体变换矩阵T(4x4)长这样:

T = | R   t |
    | 0   1 |

逆变换也很常用:

T_inv = | R^T  -R^T * t |
        |  0      1     |

避坑指南:我曾经在项目中直接用R的转置当逆矩阵用,结果算出来的坐标全反了。记住:旋转矩阵的逆才是转置,但平移部分必须跟着转回去。别偷懒,老老实实算T_inv。

2.4 从世界到像素:完整的投影管线

把上面所有步骤串起来,一个世界点P_w变成像素坐标(u, v)的完整流程是:

  1. 世界 → 相机:P_c = T_wc * P_w(刚体变换)
  2. 相机 → 图像:x = f * P_c_x / P_c_z, y = f * P_c_y / P_c_z(针孔投影)
  3. 图像 → 像素:u = x / dx + u0, v = y / dy + v0(离散化)

写成矩阵形式,就是内参矩阵K和外参矩阵[R|t]的乘积:

| u |   | fx  0  u0  0 |   | R11 R12 R13 t1 |   | P_w_x |
| v | = | 0  fy  v0  0 | * | R21 R22 R23 t2 | * | P_w_y |
| 1 |   | 0   0   1   0 |   | R31 R32 R33 t3 |   | P_w_z |
                                |  0   0   0   1 |   |   1   |

这个公式,就是整个视觉SLAM和3D重建的基石。你想想看,所有标定、跟踪、建图,最终都在解这个方程里的未知数。

2.5 本章知识体系

下面这张图,是我自己画的一个结构图,帮你把四个坐标系和变换关系串起来:

世界坐标系 相机坐标系 图像坐标系 像素坐标系 刚体变换 R, t (外参) 透视投影 针孔模型 离散化 缩放+平移 💡 核心逻辑: 外参标定 = 求解世界→相机的刚体变换 (R, t) 齐次坐标 = 把平移塞进矩阵,统一成乘法

2.6 避坑与经验

最后分享几个我踩过的坑:

  • 坐标系方向别搞反:相机坐标系Z轴朝前,Y轴朝下(图像行方向)。我见过有人把Y轴朝上,结果投影出来的点全反了。
  • 齐次坐标归一化:做完矩阵乘法后,记得把最后一维归一化成1。否则你拿到的坐标是缩放过的。
  • 内参和外参别混用:内参是相机自己的属性(焦距、主点),外参是相机在世界里的位姿。标定时要分开优化。

我的习惯:在代码里,我会把世界坐标系原点选在标定板的第一个角点上。这样外参的物理意义特别清晰——相机相对于标定板的位姿。调试时一眼就能看出旋转和平移是否合理。

好了,坐标系和变换这部分就聊到这儿。记住:四个坐标系、一个齐次坐标、一个刚体变换矩阵。把这些吃透了,后面的标定和跟踪就是水到渠成的事。