第二章 坐标系与空间变换:车辆坐标系、相机坐标系、图像坐标系、世界坐标系定义及相互转换,外参内参标定基础
各位同学,欢迎来到第二章。
做BEV感知,说白了就是在做一件事:把不同传感器看到的东西,统一到一个“上帝视角”下。你想想看,摄像头看到的是2D图像,激光雷达看到的是3D点云,它们各自为政,怎么融合?
答案就是坐标系变换。这一章,我们就把这几个坐标系的关系彻底捋清楚。我当年刚入行时,被这四个坐标系绕得晕头转向,后来踩了不少坑才真正搞明白。今天咱们一次搞定。
2.1 四大坐标系定义
先给个直观印象。我们做自动驾驶,天天打交道的就这四个坐标系:
- 世界坐标系:真实世界的绝对位置。比如经纬度+海拔,或者某个固定原点的笛卡尔坐标。它是“万物之锚”。
- 车辆坐标系:以车为中心。通常原点在后轴中心,x轴朝前,y轴朝左,z轴朝上。这是车辆的“身体坐标系”。
- 相机坐标系:以相机光心为原点。z轴沿着光轴朝前,x轴朝右,y轴朝下(注意,这里y轴方向跟车辆坐标系不同)。
- 图像坐标系:就是像素坐标。原点在图像左上角,u轴向右,v轴向下。单位是像素。
核心要点:所有变换的终极目标,就是把世界坐标系下的一个3D点,映射到图像坐标系下的一个2D像素点。反过来,从2D像素反推3D位置,则需要深度信息。
2.2 坐标系之间的变换关系
咱们一步步来。先从最简单的开始。
2.2.1 世界坐标系 → 车辆坐标系
这其实就是一个刚体变换:旋转 + 平移。车辆在世界中运动,它的位姿由外参决定。
公式很简单:
P_vehicle = R * P_world + T
其中R是3x3旋转矩阵,T是3x1平移向量。R和T合起来就是车辆的外参。我在项目中遇到过,很多人把旋转矩阵和平移向量的顺序搞反,结果点云全飞了。记住:先旋转,再平移。
2.2.2 车辆坐标系 → 相机坐标系
这也是刚体变换。相机安装在车上,它相对于车辆的位置是固定的。这个变换矩阵,就是相机的外参(相对于车辆)。
P_camera = R_cam_vehicle * P_vehicle + T_cam_vehicle
嗯,这里要注意:不同车型的相机安装位置差异很大。我见过一些方案,直接把相机外参写死,结果换了一辆车就全废了。所以,外参一定要做在线标定,或者至少要有离线标定流程。
2.2.3 相机坐标系 → 图像坐标系
这一步是透视投影,用到了相机内参。
相机内参通常是一个3x3矩阵K:
K = [[fx, 0, cx],
[ 0, fy, cy],
[ 0, 0, 1]]
其中fx, fy是焦距(像素单位),cx, cy是光心偏移。
投影公式:
u = fx * (X_c / Z_c) + cx
v = fy * (Y_c / Z_c) + cy
说白了,就是把3D点除以深度Z,再乘以焦距,加上光心偏移。这就是针孔相机模型。
个人经验:我建议你在做投影时,一定要检查Z_c是否为正。如果Z_c为负,说明点在相机后面,投影出来是错的。我曾经因为这个bug,调试了整整两天。
2.3 外参标定基础
外参标定,就是求R和T。常用的方法有:
- 手眼标定:利用棋盘格,求解相机与机械臂(或车辆)之间的变换。
- PnP方法:已知3D-2D对应点,求解相机位姿。OpenCV的
solvePnP就是干这个的。 - 在线标定:利用车道线、地面特征等,实时优化外参。这是量产方案的主流。
我简单说一下PnP的思路。假设你有一组3D点(世界坐标系下)和对应的2D像素点,那么:
// 伪代码
cv::Mat rvec, tvec;
cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
// rvec是旋转向量,tvec是平移向量
输出就是相机的外参。但要注意,solvePnP对噪声敏感,点越多越准。我一般至少用20个点。
2.4 内参标定基础
内参标定,就是求K和畸变系数。最经典的方法是张正友标定法。
步骤很简单:
- 打印一张棋盘格,贴在平面上。
- 用相机从不同角度拍20-30张照片。
- 用OpenCV的
calibrateCamera函数计算。
// 伪代码
cv::Mat cameraMatrix, distCoeffs;
std::vector<cv::Mat> rvecs, tvecs;
cv::calibrateCamera(objectPoints, imagePoints, imageSize,
cameraMatrix, distCoeffs, rvecs, tvecs);
避坑指南:我曾经用一张不平整的棋盘格做标定,结果内参误差很大,导致后续所有投影都偏移了。所以,棋盘格一定要贴平,最好用玻璃板压着。另外,照片要覆盖整个视野,尤其是边缘区域。
2.5 从像素反推3D:BEV视角的关键
做BEV感知,我们经常需要把图像像素映射到地平面(z=0)上。这其实是逆透视变换(IPM)。
公式推导如下:
- 已知像素(u, v),内参K,外参[R|T]。
- 假设地面z=0,那么世界坐标系下的点P_w = [X, Y, 0, 1]^T。
- 投影方程:s * [u, v, 1]^T = K * [R|T] * [X, Y, 0, 1]^T。
- 解这个方程,就能求出X, Y。
说白了,就是利用地面约束,把2D像素提升到3D。这也是BEV视角能成立的前提——我们假设所有目标都在地面上。
核心公式:
X = (u - cx) * Z / fx
Y = (v - cy) * Z / fy
// 其中Z是深度,由地面假设或雷达提供
2.6 本章小结
这一章内容不少,但都是基本功。我帮你总结一下:
- 四个坐标系:世界、车辆、相机、图像。记住它们的定义和方向。
- 变换流程:世界→车辆→相机→图像。每一步都是刚体变换或投影。
- 内参外参:内参是相机本身的属性,外参是相机在空间中的位姿。
- 标定方法:张正友法标内参,PnP或手眼标定标外参。
- BEV关键:利用地面假设,从像素反推3D位置。
下一章,我们会把这些变换写成代码,实现一个完整的BEV投影管线。到时候你会看到,这些公式到底是怎么跑起来的。
好了,今天就到这里。有问题随时在群里问我。