3、坐标系入门:世界坐标系、相机坐标系、图像坐标系、像素坐标系
做传感器融合,绕不开坐标系。我见过不少新手,算法写得挺溜,结果一上手标定,数据全飞到天上去——十有八九是坐标系搞混了。今天咱们就把这四个坐标系彻底捋清楚。
3.1 为什么需要四个坐标系?
你想想看,激光雷达扫出来的是三维点云,相机拍出来的是二维图像。要让它们对齐,中间得经过好几层变换。说白了,就是从“真实世界”到“照片上的像素”这条流水线。
我个人习惯把这四个坐标系想象成一条流水线:
- 世界坐标系:真实世界的“绝对位置”。比如我站在经纬度(116.4, 39.9)这个点,这就是世界坐标。
- 相机坐标系:以相机光心为原点。相机往哪看,坐标系就跟着转。
- 图像坐标系:成像平面上的物理位置。单位是毫米,告诉你光斑落在感光元件的哪个物理位置。
- 像素坐标系:最终照片上的行列号。单位是像素,左上角是(0,0)。
嗯,这里要注意:这四个坐标系之间,每一步变换都有明确的数学公式。搞错一步,融合出来的数据就是废的。
3.2 世界坐标系 → 相机坐标系
这一步叫刚体变换。说白了就是旋转加平移。
我在项目中遇到过一个问题:激光雷达装在车顶,相机装在挡风玻璃后面。两个传感器看到的“前方”根本不是同一个方向。这时候就需要用外参矩阵把激光雷达的点云从它自己的坐标系,转到相机坐标系下。
数学表达很简单:
X_cam = R * X_world + T
其中R是3x3旋转矩阵,T是3x1平移向量。合在一起就是4x4的外参矩阵。
核心要点:外参矩阵描述的是两个传感器之间的相对位置和姿态。标定的本质,就是求解这个矩阵。
3.3 相机坐标系 → 图像坐标系
这一步是透视投影。从三维到二维,信息丢失了深度。
公式长这样:
x = f * X_cam / Z_cam
y = f * Y_cam / Z_cam
f是焦距。你看,Z_cam跑到分母上了。这就是为什么远处的物体看起来小。
我曾经踩过一个坑:用针孔模型算投影,结果图像边缘畸变得厉害。后来才意识到,普通摄像头都有镜头畸变,得先做畸变校正。嗯,这个后面会专门讲。
小技巧:实际项目中,我们通常用齐次坐标来写这个变换。把除法和乘法统一成矩阵乘法,代码写起来清爽很多。
3.4 图像坐标系 → 像素坐标系
这一步是离散化。把连续的物理坐标,映射到离散的像素网格上。
公式:
u = x / dx + u0
v = y / dy + v0
dx和dy是每个像素的物理尺寸(毫米/像素),u0和v0是图像中心点的像素坐标。
说白了,就是告诉你:成像平面上的那个光斑,对应照片上的第几行第几列。
| 坐标系 | 原点 | 单位 | 维度 |
|---|---|---|---|
| 世界坐标系 | 自定义(如GPS原点) | 米 | 3D |
| 相机坐标系 | 相机光心 | 米 | 3D |
| 图像坐标系 | 光轴与成像平面交点 | 毫米 | 2D |
| 像素坐标系 | 图像左上角 | 像素 | 2D |
3.5 完整变换链
把上面三步串起来,就是:
世界坐标 → (外参) → 相机坐标 → (内参) → 图像坐标 → (离散化) → 像素坐标
内参矩阵K把相机坐标直接映射到像素坐标,一步到位:
[u] [fx 0 cx] [X_cam]
[v] = [ 0 fy cy] [Y_cam]
[1] [ 0 0 1] [Z_cam]
fx、fy是焦距的像素表示,cx、cy是主点偏移。这些参数出厂时就有,但实际安装后会有偏差,所以需要标定。
注意:内参矩阵假设图像没有畸变。实际摄像头都有畸变,尤其是广角镜头。标定时一定要同时求解畸变系数,否则投影误差会很大。
3.6 知识体系总览
下面这张图,把四个坐标系的关系画清楚了。我建议你把它存下来,每次做标定前看一眼。
3.7 实战中的常见坑
我做了这么多年融合,总结出几个坐标系相关的常见问题:
- 坐标系方向搞反:有些相机定义Z轴向前,有些定义Z轴向上。标定前一定要确认传感器的坐标系定义文档。
- 单位不统一:激光雷达给的是米,标定板尺寸给的是毫米。忘了换算,投影直接偏到天边去。
- 像素坐标原点:OpenCV里原点在左上角,有些工业相机SDK原点在左下角。这个坑我至少踩过两次。
我的建议:写代码时,每一步变换都单独写一个函数,加详细的注释。调试时把中间结果打印出来,看一眼就知道哪一步出了问题。
坐标系这东西,刚开始觉得绕,用多了就习惯了。关键是理解每一步变换的物理意义,而不是死记公式。下次咱们聊标定板的设计和检测,那才是真正动手的开始。