坐标系基础:世界坐标系、相机坐标系、图像坐标系、像素坐标系及其转换关系
做标定这么多年,我见过太多人一上来就调参数、跑优化,结果精度死活上不去。为什么?说白了,坐标系都没搞明白。你连点在哪儿、怎么转的都没理清,标定结果能好才怪。
今天咱们就把这四个坐标系彻底讲透。我保证,看完这一节,你再看标定公式会顺眼很多。
1. 四个坐标系,一张图说清楚
先别急着看公式。咱们先建立直觉。
核心逻辑:真实世界的一个点,要变成图像上的一个像素,中间经历了四次坐标变换。
嗯,这张图你多看两眼。整个标定的本质,就是把这四步变换的参数给求出来。每一步都有对应的物理意义和数学表达。
2. 世界坐标系 → 相机坐标系(刚体变换)
世界坐标系是咱们自己定的。你可以把原点放在标定板的角点上,也可以放在机器人基座上。相机坐标系呢?原点在相机光心,Z轴沿着光轴方向。
从一个坐标系到另一个坐标系,说白了就是旋转加平移。我习惯用齐次坐标来写,这样能把旋转和平移合并成一个矩阵乘法:
| Xc | | R11 R12 R13 tx | | Xw |
| Yc | = | R21 R22 R23 ty | * | Yw |
| Zc | | R31 R32 R33 tz | | Zw |
| 1 | | 0 0 0 1 | | 1 |
这里的R是3x3的旋转矩阵,t是3x1的平移向量。这6个参数(3个旋转角+3个平移量)就是外参的核心。
我的经验:实际项目中,旋转矩阵用欧拉角表示容易出万向锁问题。我个人更推荐用四元数或者旋转向量来做优化。有一次我在一个机械臂视觉引导项目里,用欧拉角做优化,结果在某个姿态下雅可比矩阵奇异了,折腾了两天才发现是万向锁。从那以后,我优化外参一律用四元数。
3. 相机坐标系 → 图像坐标系(透视投影)
这一步是三维到二维的降维打击。相机坐标系下的点(Xc, Yc, Zc),通过小孔成像模型,投影到成像平面上。
公式其实很简单,就是相似三角形:
x = f * Xc / Zc
y = f * Yc / Zc
写成矩阵形式:
| x | | f 0 0 0 | | Xc |
| y | = | 0 f 0 0 | * | Yc |
| 1 | | 0 0 1 0 | | Zc |
| 1 |
这里f是焦距。注意,这里的(x, y)还是物理单位(毫米),不是像素。
避坑指南:我曾经在标定一个广角相机时,发现投影误差总是很大。查了半天,发现是镜头畸变太严重,小孔模型根本不够用。所以实际标定时,一定要考虑畸变模型。对于鱼眼相机,甚至要用到等距投影或者等立体角投影模型。别傻乎乎地只用针孔模型去标广角镜头,那是在浪费时间。
4. 图像坐标系 → 像素坐标系(离散化)
图像坐标系是连续的物理坐标,像素坐标系是离散的整数坐标。这一步就是把毫米变成像素。
公式:
u = x / dx + u0
v = y / dy + v0
其中dx、dy是每个像素在x和y方向上的物理尺寸,u0、v0是主点(光轴与成像平面的交点)的像素坐标。
写成齐次形式:
| u | | 1/dx 0 u0 | | x |
| v | = | 0 1/dy v0 | * | y |
| 1 | | 0 0 1 | | 1 |
关键点:把前三步合并,就得到了从世界坐标到像素坐标的完整投影方程:
| u | | fx 0 u0 0 | | R11 R12 R13 tx | | Xw |
| v | = | 0 fy v0 0 | * | R21 R22 R23 ty | * | Yw |
| 1 | | 0 0 1 0 | | R31 R32 R33 tz | | Zw |
| 0 0 0 1 | | 1 |
这就是大名鼎鼎的投影矩阵P = K * [R|t]。标定的本质,就是求解K、R、t。
5. 完整变换流程总结
咱们把整个流程串起来,你感受一下:
- 世界坐标系:你放标定板的地方,原点自己定。比如我习惯把原点放在标定板的左上角角点上。
- 相机坐标系:以相机光心为原点,Z轴朝前。这一步通过外参[R|t]完成。
- 图像坐标系:在成像平面上,原点在光轴与平面的交点(主点),单位是毫米。这一步通过内参K中的fx、fy完成透视投影。
- 像素坐标系:原点在图像左上角,单位是像素。这一步通过内参中的u0、v0和dx、dy完成离散化。
| 坐标系 | 原点 | 单位 | 变换到下一步 | 涉及参数 |
|---|---|---|---|---|
| 世界坐标系 | 自定义 | 真实物理单位(m/mm) | 刚体变换 | 外参R, t |
| 相机坐标系 | 相机光心 | 真实物理单位(m/mm) | 透视投影 | 内参fx, fy |
| 图像坐标系 | 主点(光轴交点) | 物理单位(mm) | 离散化 | 内参u0, v0, dx, dy |
| 像素坐标系 | 图像左上角 | 像素(pixel) | - | - |
6. 实际标定中的坐标系陷阱
说几个我踩过的坑,你遇到了能少走弯路:
- 坐标系方向搞反:OpenCV的像素坐标系原点在左上角,u轴向右,v轴向下。但有些数据集或者自己写的代码,可能用了不同的约定。我见过有人把v轴方向搞反,结果标定出来的外参旋转矩阵怎么都不对。
- 单位不统一:标定板的格子尺寸是毫米,但代码里默认用米。这种错误特别隐蔽,因为标定结果看起来好像没问题,但投影误差会偏大。我建议你从一开始就统一单位,我习惯全部用毫米。
- 主点位置搞错:图像坐标系的原点在主点,像素坐标系的原点在左上角。这两个原点差了(u0, v0)。如果你直接用像素坐标去做投影计算,忘了减掉主点偏移,结果会差很多。
我的小技巧:每次标定完,我都会做一个验证:把标定板上的角点通过投影方程重投影到图像上,看看重投影误差。如果误差在0.5像素以内,说明坐标系变换没问题。如果误差很大,先别急着调优化参数,回头检查一下坐标系定义和变换公式。
好了,坐标系基础就讲到这里。这四个坐标系的关系,是标定理论的基石。你把它吃透了,后面的内容学起来会轻松很多。记住一句话:标定就是求一个从世界坐标到像素坐标的映射,而这个映射由外参和内参共同决定。