2、坐标系与传感器基础:相机坐标系、激光雷达坐标系、IMU坐标系、外参标定基础、内参基础
说实话,做BEV感知这几年,我踩过最大的坑就是坐标系搞混了。你想想看,一辆车上装了相机、激光雷达、IMU,每个传感器都有自己的"小脾气"——它们各自定义自己的原点在哪、哪个方向是正。如果不把这些坐标系对齐,后面做融合、做感知,全是白搭。
这一章,我们就来把这些坐标系彻底捋清楚。我保证,看完之后你至少能少走三个月弯路。
2.1 相机坐标系:从像素到世界的桥梁
相机坐标系,说白了就是描述"相机看到了什么"的坐标系。它分三层:像素坐标系、图像坐标系、相机坐标系。
像素坐标系:就是图像上每个像素的位置,原点在左上角,u轴向右,v轴向下。单位是像素。
图像坐标系:把像素坐标转换成物理尺寸,原点在图像中心(主点),x轴向右,y轴向下。单位是毫米。
相机坐标系:以相机光心为原点,Z轴指向相机前方,X轴向右,Y轴向下。这才是真正的三维坐标系。
这三者之间的转换,靠的就是内参矩阵K。我习惯把内参理解成"相机自己的尺子"——它告诉你一个像素点对应真实世界中的多大角度。
核心公式:
// 像素坐标 -> 归一化坐标
[x_norm, y_norm, 1]^T = K^{-1} * [u, v, 1]^T
// 归一化坐标 -> 相机坐标
X_cam = z * x_norm
Y_cam = z * y_norm
Z_cam = z
我的经验:实际项目中,内参矩阵一定要自己做标定,别用厂家给的默认值。我曾经在某个量产项目里,直接用厂家标定文件,结果测距误差差了15%。后来自己用棋盘格重新标了一遍,问题就解决了。
2.2 激光雷达坐标系:点云的"老家"
激光雷达坐标系相对简单。通常以激光雷达的旋转中心为原点,X轴指向车辆前方,Y轴指向左侧,Z轴指向上方。单位是米。
每个激光点包含(x, y, z, intensity)四个信息。其中intensity是反射强度,在BEV感知中可以用来区分车道线和路面。
嗯,这里要注意:不同厂家的激光雷达坐标系定义可能不一样。比如Velodyne和Hesai的坐标系就有差异。我建议你拿到点云数据后,先可视化一下,确认坐标轴方向对不对。
避坑指南:我曾经在融合相机和激光雷达时,发现投影后的点云总是偏了30度。查了两天才发现——激光雷达的Y轴是朝左的,而我代码里默认朝右。这种低级错误,一旦犯过就再也不会忘了。
2.3 IMU坐标系:车身姿态的"裁判"
IMU(惯性测量单元)测量的是加速度和角速度。它的坐标系通常定义为:X轴指向车辆前方,Y轴指向右侧,Z轴指向下方(符合右手定则)。
IMU坐标系和车身坐标系基本重合,但安装时会有小偏差。这个偏差需要通过外参标定来补偿。
IMU的数据频率很高(100Hz以上),但存在漂移。所以在BEV感知中,我们通常用IMU做短时间内的姿态预测,用相机或激光雷达做长时间修正。
| 传感器 | 坐标系原点 | X轴方向 | Y轴方向 | Z轴方向 |
|---|---|---|---|---|
| 相机 | 光心 | 向右 | 向下 | 向前 |
| 激光雷达 | 旋转中心 | 向前 | 向左 | 向上 |
| IMU | IMU芯片中心 | 向前 | 向右 | 向下 |
2.4 内参基础:相机自己的"基因"
内参描述了相机内部的几何特性。主要包括:
- 焦距:fx, fy,单位是像素。决定了图像的缩放程度。
- 主点:cx, cy,单位是像素。通常是图像中心,但实际会有偏移。
- 畸变系数:k1, k2, p1, p2, k3。径向畸变和切向畸变。
内参标定常用的方法是张正友标定法。你只需要打印一张棋盘格,从不同角度拍20张照片,然后用OpenCV的calibrateCamera函数就能算出来。
代码示例:
import cv2
import numpy as np
# 准备棋盘格角点
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
objp = np.zeros((6*9, 3), np.float32)
objp[:,:2] = np.mgrid[0:9, 0:6].T.reshape(-1,2)
# 遍历所有图片
objpoints = [] # 世界坐标系中的点
imgpoints = [] # 图像坐标系中的点
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, (9,6), None)
if ret:
objpoints.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
imgpoints.append(corners2)
# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
objpoints, imgpoints, gray.shape[::-1], None, None
)
我的建议:标定完成后,一定要做重投影误差检查。如果误差超过0.5个像素,说明标定质量不行,需要重新拍图。我一般要求重投影误差在0.1像素以内才放心使用。
2.5 外参标定基础:让传感器"说同一种语言"
外参描述的是不同传感器之间的相对位置和姿态。比如激光雷达坐标系到相机坐标系的旋转矩阵R和平移向量t。
外参标定常用的方法有:
- 目标物法:在场景中放置标定板,同时被相机和激光雷达看到,然后求解R和t。
- 自然场景法:利用场景中的特征点(如角点、边缘)进行匹配,然后优化求解。
- 在线标定:车辆行驶过程中,利用SLAM或结构光方法实时估计外参。
我个人最推荐目标物法,精度高、鲁棒性好。你只需要一个棋盘格或者特制的标定板,采集几组数据就能搞定。
避坑指南:我曾经在标定激光雷达到相机的外参时,发现投影误差总是很大。后来发现是标定板太小,激光雷达点云在板子上只有几十个点,根本拟合不出平面。换了大标定板后,问题就解决了。标定板的尺寸至少要在1米×1米以上。
外参标定的数学本质是求解一个刚体变换:
P_cam = R * P_lidar + t
其中P_cam是相机坐标系下的点,P_lidar是激光雷达坐标系下的点。R是3x3的旋转矩阵,t是3x1的平移向量。
求解这个方程,至少需要3对不共线的对应点。实际中我们会用几十对点,然后用最小二乘法或RANSAC来求解,提高鲁棒性。
2.6 坐标系统一:BEV感知的"地基"
在BEV感知中,所有传感器的数据最终都要转换到同一个坐标系下——通常是自车坐标系(车身坐标系)。
转换流程如下:
- 将相机像素坐标转换到相机坐标系(利用内参)
- 将相机坐标系下的点转换到自车坐标系(利用相机外参)
- 将激光雷达坐标系下的点转换到自车坐标系(利用激光雷达外参)
- 将IMU数据转换到自车坐标系(利用IMU外参)
这样,所有传感器数据都在同一个"世界"里了。后续的BEV特征提取、目标检测、轨迹预测,都基于这个统一坐标系。
核心要点:坐标系转换的精度,直接决定了BEV感知的上限。如果外参标定误差1度,在50米处的目标就会偏移0.87米。这个误差在高速场景下是致命的。
好了,这一章的内容就到这里。坐标系和传感器基础是BEV感知的"地基",地基不牢,地动山摇。下一章我们会讲如何把相机图像转换成BEV视角,也就是IPM(逆透视变换)和LSS(Lift-Splat-Shoot)方法。到时候你会发现,坐标系转换的功底有多重要。