2. 相机成像模型:四大坐标系的关系
做3D视觉定位,第一个绕不开的就是相机成像模型。说白了,就是搞明白「世界上的一个点,是怎么变成照片上那个像素的」。我刚开始接触这个的时候,也觉得坐标系转换很绕,后来在产线上调一个抓取项目,被标定折腾了两天,才真正把这些关系刻进脑子里。
今天咱们就把针孔相机模型和四个坐标系的关系彻底理清楚。你想想看,机器人要抓一个零件,它得知道零件在它自己坐标系下的位置,而相机只能给出一张二维图片。这中间差了整整一个维度,怎么补上?答案就在坐标系转换里。
2.1 针孔相机模型——最朴素的成像原理
针孔相机模型,其实就是一个暗箱。光线从物体上反射过来,穿过一个小孔,在后面的成像平面上形成倒立的像。嗯,这里要注意,实际相机用的是透镜,但数学模型上我们把它简化成针孔,这样计算起来方便得多。
核心思想: 三维世界中的点,通过光心投影到二维成像平面上。这个投影过程可以用一个 3×4 的投影矩阵来描述。
我在项目中遇到过一个问题:用广角镜头时,针孔模型就不太准了,边缘畸变很大。那时候我才意识到,针孔模型是理想情况,实际还要加畸变校正。不过别急,那是后面章节的事,今天先把理想模型吃透。
2.2 四大坐标系——从世界到像素的完整链路
一个三维点要变成像素坐标,中间要经过四次变换。我习惯把这四个坐标系串成一条链:
- 世界坐标系 (World) —— 你定的全局参考系,单位是米或毫米
- 相机坐标系 (Camera) —— 以相机光心为原点,Z轴朝前
- 图像坐标系 (Image) —— 在成像平面上,单位是毫米
- 像素坐标系 (Pixel) —— 最终图片上的行列号,单位是像素
说白了,就是从「真实世界的米」变成「照片上的像素」的过程。每一步都有对应的数学变换。
2.2.1 世界坐标系 → 相机坐标系(刚体变换)
这一步是刚体变换,包含旋转和平移。世界坐标系下的点 Pw = (Xw, Yw, Zw)T,要转到相机坐标系下:
P_c = R * P_w + t
其中 R 是 3×3 旋转矩阵,t 是 3×1 平移向量。这 6 个参数(3个旋转角 + 3个平移量)就是相机的外参。我建议你记住:外参描述的是相机在世界坐标系下的位姿。
我的习惯: 标定时,我会把标定板放在世界坐标系 Z=0 的平面上,这样能简化计算。很多开源库也是这么做的。
2.2.2 相机坐标系 → 图像坐标系(透视投影)
这一步是针孔模型的核心。相机坐标系下的点 Pc = (Xc, Yc, Zc)T,投影到成像平面上:
x = f * X_c / Z_c
y = f * Y_c / Z_c
这里 f 是焦距。你看,Zc 被除掉了,深度信息在这一步丢失了。这就是为什么单张图片无法直接得到深度——你想想看,一个近的小物体和一个远的大物体,可能在图片上看起来一模一样。
我曾经犯过一个错:直接用图像坐标去算物体的实际尺寸,结果怎么都对不上。后来才反应过来,没有深度信息,二维坐标对应的是无数个三维点。
2.2.3 图像坐标系 → 像素坐标系(离散化)
图像坐标 (x, y) 是连续的毫米值,而像素坐标 (u, v) 是离散的整数。转换关系:
u = x / dx + u0
v = y / dy + v0
其中 dx、dy 是每个像素的物理尺寸(毫米/像素),(u0, v0) 是图像中心(主点)的像素坐标。这 4 个参数(f, dx, dy, u0, v0)加上畸变参数,就是相机的内参。
注意: 很多相机标定结果里,fx = f/dx,fy = f/dy,它们直接就是像素单位的焦距。别看到 fx 和 fy 不一样就以为标定错了——那只是因为像素不是正方形。
2.3 四大坐标系关系总览
我把整个链路整理成了一张图,方便你对照着看:
2.4 齐次坐标与投影矩阵
上面那张图底部的公式,就是整个成像模型的数学精华。用齐次坐标可以把非线性投影写成线性形式:
s * [u] = [fx 0 u0 0] * [R11 R12 R13 t1] * [Xw]
[v] [ 0 fy v0 0] [R21 R22 R23 t2] [Yw]
[1] [ 0 0 1 0] [R31 R32 R33 t3] [Zw]
[1 ]
这个 3×4 矩阵就是投影矩阵 P = K · [R | t]。我建议你把这个公式存下来,后面手眼标定、3D重建全都要用到它。
一个小技巧: 实际编程时,我们通常用 OpenCV 的 projectPoints() 函数来做这个投影。但理解背后的矩阵运算,能帮你更快地排查标定结果的问题。
2.5 常见问题与避坑
| 问题 | 原因 | 解决办法 |
|---|---|---|
| 标定后重投影误差很大 | 标定板不平整或图片数量不够 | 至少拍 15-20 张不同角度的图片 |
| 外参结果不稳定 | 标定板在视野中占比太小 | 让标定板占画面 1/3 以上 |
| 像素坐标转世界坐标不准 | 缺少深度信息,单张图无法反算 | 用双目或结构光获取深度 |
| fx 和 fy 差异过大 | 像素不是正方形,或镜头有畸变 | 检查标定结果,必要时做畸变校正 |
我曾经在一个项目里,标定结果看起来挺好,重投影误差才 0.3 像素,但实际抓取就是偏。查了两天才发现,是标定板贴在了亚克力板上,光线折射导致标定板平面和实际平面不重合。嗯,从那以后,我标定都用陶瓷或玻璃基板的标定板。
2.6 小结
今天的内容,说白了就是一条线:世界坐标 → 相机坐标 → 图像坐标 → 像素坐标。每一步都有明确的数学变换,外参描述相机在哪,内参描述相机怎么看。理解了这个链路,后面讲手眼标定、3D重建、抓取点计算,你就能知道每一步在干什么。
我建议你找个标定板,用 OpenCV 跑一遍标定流程,把内参外参打印出来,对照着今天讲的公式看一遍。纸上得来终觉浅,亲手跑一遍,印象深得多。