2. 图像基础与坐标系
做车道线感知,说白了就是解决一个问题:怎么让车看懂路。
但摄像头拍到的是一张二维图片,而车道线是三维世界里的物理标记。从二维到三维,中间隔着一整套坐标系变换。我刚开始接触这部分时,也觉得坐标系来回倒腾很烦。但后来发现,坐标系就是自动驾驶感知的“通用语言”——不懂它,你连标定数据都看不懂。
这一节,我们就把这几种坐标系和它们之间的变换关系彻底讲透。
2.1 四大坐标系:从像素到世界
先记住一句话:所有坐标变换,都是为了把图像上的一个点,映射回真实世界中的位置。
这中间要经过四个坐标系:
- 像素坐标系:图像左上角为原点,单位是像素 (u, v)
- 图像坐标系:图像中心为原点,单位是毫米 (x, y)
- 相机坐标系:相机光心为原点,单位是米 (Xc, Yc, Zc)
- 世界坐标系:自定义参考系,单位是米 (Xw, Yw, Zw)
嗯,这里要注意:像素坐标系和图像坐标系都在图像平面上,但原点不同、单位不同。很多初学者把这两个搞混,标定出来的参数全是错的。
核心关系图:
2.2 像素坐标系 → 图像坐标系
这是第一步,也是最简单的一步。
像素坐标系的原点在左上角,u轴向右,v轴向下。图像坐标系的原点在图像中心,x轴向右,y轴向上。
转换公式很简单:
x = (u - cx) * dx
y = (v - cy) * dy
其中 (cx, cy) 是图像中心在像素坐标系下的坐标,dx、dy 是每个像素的物理尺寸(单位:mm/pixel)。
我的经验: 实际项目中,dx 和 dy 通常从相机 datasheet 里查,或者通过标定得到。我遇到过有人直接用 1.0 代替,结果投影出来的车道线位置偏了半个车身——嗯,这种坑踩过一次就记住了。
2.3 图像坐标系 → 相机坐标系
这一步用到了小孔成像模型。
假设相机光心在 (0,0,0),图像平面在 Z = f 处(f 是焦距)。那么图像上的点 (x, y) 对应相机坐标系下的射线:
Xc = x * Zc / f
Yc = y * Zc / f
Zc = 深度值(未知)
这里有个关键问题:单目相机无法直接得到 Zc。所以从图像坐标到相机坐标,其实是一条射线,而不是一个点。
那车道线感知怎么解决?
我们通常假设车道线在地面平面上。结合地面方程(Zc = 某个值),就能解出具体的 3D 坐标。
注意: 地面假设在平坦路面上成立。遇到坡道或颠簸路面,这个假设会引入误差。我曾经在高速上坡路段测试,车道线投影偏差达到了 30 厘米——后来加了 IMU 数据做补偿才解决。
2.4 相机坐标系 → 世界坐标系
这一步用外参矩阵。
外参矩阵描述了相机在世界坐标系中的位置和朝向。它由旋转矩阵 R(3x3)和平移向量 t(3x1)组成:
[Xw] [R t] [Xc]
[Yw] = [ ] [Yc]
[Zw] [0 0 0 1] [Zc]
[1 ] [1 ]
说白了,就是把相机坐标系下的点,先旋转、再平移,映射到世界坐标系。
我个人习惯把外参矩阵理解为“相机在世界中的位姿”。你想想看,如果相机装在车顶,外参矩阵就描述了相机相对于车体坐标系的安装位置和角度。
2.5 内参矩阵:把三维投影到二维
内参矩阵 K 是 3x3 的矩阵:
K = [fx 0 cx]
[0 fy cy]
[0 0 1]
其中 fx、fy 是焦距在像素单位下的值,cx、cy 是图像中心坐标。
内参矩阵的作用:把相机坐标系下的 3D 点投影到像素坐标系。
u = fx * Xc / Zc + cx
v = fy * Yc / Zc + cy
这个公式在车道线感知中太常用了。比如你检测到一条车道线,想把它投影到图像上显示,就用这个公式。
避坑指南: 我曾经在标定内参时,用了错误的棋盘格尺寸,结果 fx、fy 全偏了。后来发现,标定板的格子尺寸必须精确到毫米级,差 1 毫米都不行。
2.6 畸变模型与校正
现实中的相机镜头不是完美的。光线经过镜头时会发生弯曲,导致图像边缘出现畸变。
畸变主要分两种:
- 径向畸变:光线弯曲程度与距离中心的半径有关。表现为“桶形畸变”或“枕形畸变”
- 切向畸变:镜头与成像平面不平行导致。表现为“梯形畸变”
畸变模型用多项式描述:
x_distorted = x * (1 + k1*r^2 + k2*r^4 + k3*r^6) + 2*p1*x*y + p2*(r^2 + 2*x^2)
y_distorted = y * (1 + k1*r^2 + k2*r^4 + k3*r^6) + p1*(r^2 + 2*y^2) + 2*p2*x*y
其中 k1、k2、k3 是径向畸变系数,p1、p2 是切向畸变系数,r^2 = x^2 + y^2。
校正过程就是:
- 对每个像素 (u, v),计算对应的归一化坐标 (x, y)
- 用畸变模型计算畸变后的坐标 (x_distorted, y_distorted)
- 再映射回像素坐标,得到校正后的图像
我的建议: 车道线感知中,畸变校正一定要做。尤其是鱼眼相机,边缘畸变非常严重。我见过一个项目,没做畸变校正,结果车道线在图像边缘直接弯成了弧形——这要是用来控制方向盘,车就画龙了。
2.7 完整变换流程:从像素到世界
把上面所有步骤串起来,从像素坐标到世界坐标的完整流程是:
1. 像素坐标 (u, v) → 图像坐标 (x, y) [用内参 cx, cy, dx, dy]
2. 图像坐标 (x, y) → 相机坐标 (Xc, Yc, Zc) [用小孔模型 + 深度假设]
3. 相机坐标 (Xc, Yc, Zc) → 世界坐标 (Xw, Yw, Zw) [用外参 R, t]
反过来,从世界坐标到像素坐标:
1. 世界坐标 (Xw, Yw, Zw) → 相机坐标 (Xc, Yc, Zc) [用外参的逆]
2. 相机坐标 (Xc, Yc, Zc) → 图像坐标 (x, y) [用内参的逆]
3. 图像坐标 (x, y) → 像素坐标 (u, v) [用内参 cx, cy, dx, dy]
你想想看,整个流程其实就是矩阵乘法的串联。在实际代码中,我们通常把内参和外参合并成一个 3x4 的投影矩阵 P:
P = K * [R | t]
这样一步就能把世界坐标投影到像素坐标。
总结一下:
- 四大坐标系:像素 → 图像 → 相机 → 世界
- 内参矩阵:描述相机本身的属性(焦距、中心、畸变)
- 外参矩阵:描述相机在世界中的位姿(旋转、平移)
- 畸变校正:消除镜头带来的图像变形
- 完整流程:矩阵乘法串联,一步到位
这些坐标系和矩阵,是车道线感知的数学基础。后面讲车道线检测、跟踪、融合,每一步都离不开它们。我个人建议你把这一节的内容亲手推导一遍,写代码实现一下——只有亲手做过,才能真正理解。
最后提醒: 标定参数不是一成不变的。相机受到震动、温度变化,内参可能会漂移。我建议每 3-6 个月重新标定一次,或者加入在线标定模块实时更新。
可可精品资料库