4. 多视图几何基础
大家好,我是你们的自动驾驶感知讲师。今天咱们聊聊多视图几何——说白了,就是怎么让车看懂不同摄像头拍到的同一场景。你想想看,一辆车上装了6个甚至更多摄像头,每个摄像头看到的画面都不一样,怎么把这些信息统一起来?这就是多视图几何要解决的问题。
我个人习惯把多视图几何比作「视觉世界的坐标系转换器」。它帮我们搞清楚:同一个物体在不同相机画面里是什么关系,以及怎么从2D图像反推3D位置。嗯,这里要注意,这些知识是BEV感知的数学地基,绕不过去的。
核心观点:多视图几何是连接2D图像与3D世界的桥梁。没有它,BEV感知就是空中楼阁。
1.1 对极几何——两视图之间的约束
先讲对极几何。这东西说白了就是描述两个相机看同一个点时的几何关系。我刚开始接触时也觉得抽象,后来在项目中调试双目测距,才真正理解它的价值。
对极几何的核心就一句话:左图上的一个点,在右图上对应的搜索范围是一条线,而不是整张图。这条线就叫「极线」。
我的经验:在实际的BEV项目中,对极几何帮我们大幅缩小了特征匹配的搜索空间。原来要遍历整张图找匹配点,现在只需要沿着极线搜就行,速度提升至少10倍。
对极几何有几个关键元素:
- 基线:两个相机光心的连线
- 极点:基线与成像平面的交点
- 极平面:空间点与两个光心确定的平面
- 极线:极平面与成像平面的交线
你想想看,如果两个相机是平行放置的(比如车载双目相机),极线就是水平的。这意味着左右图的匹配点只在同一行上搜索——这就是为什么很多双目算法只做水平方向的匹配。
1.2 本质矩阵 E——已知相机内参时的神器
本质矩阵 E 是什么?它是对极几何的数学表达。但有个前提:你得知道相机的内参。
E 矩阵是一个 3x3 的矩阵,秩为2。它把左图上的一个点,映射到右图上的极线。公式长这样:
// 本质矩阵约束
x2^T * E * x1 = 0
// 其中 x1, x2 是归一化平面上的点坐标
// E = [t]× * R
// [t]× 是平移向量的反对称矩阵
// R 是旋转矩阵
我记得有一次在项目中,用 E 矩阵做视觉里程计。当时采集的数据里相机内参标定得不太准,结果 E 矩阵分解出来的旋转和平移全是错的。后来重新标定了内参,一切才恢复正常。所以这里要提醒大家:E 矩阵对相机内参非常敏感。
避坑指南:我曾经在实车测试时发现,车辆颠簸会导致相机内参轻微变化。如果你用出厂标定的内参算 E 矩阵,结果可能偏差很大。建议在车上做一次在线标定,或者用鲁棒性更强的算法。
1.3 基础矩阵 F——不知道内参也能用
基础矩阵 F 和 E 矩阵本质是一回事,但 F 矩阵不需要知道相机内参。它直接操作像素坐标:
// 基础矩阵约束
p2^T * F * p1 = 0
// 其中 p1, p2 是像素坐标
// F = K2^(-T) * E * K1^(-1)
// K1, K2 是两个相机的内参矩阵
说白了,F 矩阵就是把 E 矩阵「包裹」了一层内参信息。在自动驾驶场景中,如果你用的是不同型号的相机(比如前视广角+侧视长焦),F 矩阵就特别有用——它不需要你精确知道每个相机的内参。
但要注意,F 矩阵的自由度是7(因为尺度等价性和秩为2的约束),而 E 矩阵的自由度是5。这意味着 F 矩阵需要更多点对来求解,而且对噪声更敏感。
| 矩阵 | 自由度 | 需要内参 | 适用场景 |
|---|---|---|---|
| 本质矩阵 E | 5 | 是 | 已知内参的双目/多目 |
| 基础矩阵 F | 7 | 否 | 未知内参或混合相机 |
| 单应矩阵 H | 8 | 否 | 平面场景或纯旋转 |
1.4 单应矩阵 H——平面场景的利器
单应矩阵 H 和前两个不太一样。它描述的是同一个平面在两个视图之间的映射关系。说白了,如果场景中所有点都在一个平面上(比如地面、墙面),那么 H 矩阵就能完美描述它们之间的变换。
在BEV感知中,单应矩阵用得特别多。为什么?因为地面就是一个平面。我们可以用 H 矩阵把前视相机拍到的地面区域,直接投影到鸟瞰图上。
// 单应矩阵约束
p2 = H * p1
// H 是一个 3x3 矩阵
// 对于地面平面 n^T * X = d
// H = K2 * (R - t * n^T / d) * K1^(-1)
实际应用:在BEV感知中,我们经常用单应矩阵做「逆透视映射」(IPM)。把前视图像中的地面区域,投影到俯视图上。这样车道线、路沿等地面元素就能在BEV空间里直接处理了。
但这里有个坑:单应矩阵假设所有点都在同一个平面上。如果场景中有立体的物体(比如行人、车辆),用 H 矩阵投影就会产生畸变。我见过一些新手直接把整张图做 IPM,结果行人被拉成了长条——嗯,这就是没理解单应矩阵的适用范围。
1.5 三角化——从2D到3D的逆推
三角化,说白了就是已知两个视图的匹配点,以及相机之间的位姿,反推出空间点的3D坐标。这是BEV感知中获取深度信息的关键步骤。
原理很简单:两条射线(从两个相机光心出发,经过匹配点)的交点就是空间点。但实际中因为噪声,两条射线往往不相交。所以我们要找「最接近」两条射线的点。
// 三角化的线性解法
// 对于匹配点 x1, x2 和投影矩阵 P1, P2
// 构建线性方程组:
// x1 × (P1 * X) = 0
// x2 × (P2 * X) = 0
// 用SVD求解 X
我个人习惯用「中点法」做三角化——取两条射线距离最近的两个点,取它们的中点作为3D点。这个方法简单,而且在实际项目中效果不错。
我的经验:三角化的精度很大程度上取决于两个相机的基线长度。基线越长,深度估计越准。但车载相机基线不能太长(车就那么宽),所以远距离物体的深度估计误差会很大。在BEV感知中,我一般只对30米以内的物体做三角化,再远就用其他方法了。
1.6 PnP问题——已知3D求2D位姿
PnP(Perspective-n-Point)问题和三角化正好相反。它是已知一些3D点及其在图像上的2D投影,求相机相对于这些3D点的位姿(旋转和平移)。
在自动驾驶中,PnP用得最多的地方是视觉定位。比如我们知道地图上一些路标的3D位置,然后在图像中检测到这些路标,就能算出当前相机(也就是车)的位置。
PnP问题有很多解法:
- P3P:只用3个点,速度快但容易受噪声影响
- EPnP:用4个以上点,精度和鲁棒性更好
- DLT:直接线性变换,简单但需要至少6个点
- 迭代法:比如Levenberg-Marquardt优化,精度最高但慢
// OpenCV中的PnP求解
// 输入:3D点、2D点、相机内参、畸变系数
// 输出:旋转向量、平移向量
bool success = cv::solvePnP(
objectPoints, // 3D点
imagePoints, // 2D点
cameraMatrix, // 内参矩阵
distCoeffs, // 畸变系数
rvec, // 输出旋转向量
tvec // 输出平移向量
);
避坑指南:我曾经在项目中用PnP做车辆定位,发现结果经常跳变。后来排查发现,是因为用了共面的3D点(比如地面上的标记点)。当所有3D点共面时,PnP问题会有歧义——说白了就是解不唯一。解决方案是加入非共面的点,或者用RANSAC做鲁棒估计。
小结
这一章我们聊了多视图几何的六个核心概念。它们之间的关系是这样的:
- 对极几何是理论基础,描述了视图之间的约束关系
- 本质矩阵 E 和 基础矩阵 F 是对极几何的数学表达,区别在于是否知道内参
- 单应矩阵 H 专门处理平面场景,在BEV的IPM中特别有用
- 三角化从2D匹配反推3D位置
- PnP从3D-2D对应关系反推相机位姿
这些知识在BEV感知中无处不在。比如BEV空间中的深度估计、多相机融合、时序对齐,都离不开这些几何基础。我个人觉得,花时间把这些概念吃透,后面学BEV会轻松很多。
可可精品资料库