多视图几何核心解析:从对极几何到三维重建与SLAM工程实践

📅 发布时间:2026/10/5 1:28:27
多视图几何核心解析:从对极几何到三维重建与SLAM工程实践
我这些年折腾三维视觉项目一个很深的感触是单张图片是投影两张图片才是几何。很多人学计算机视觉从分类、检测入门跑通了几个深度学习框架就觉得自己入门了但一碰到三维重建、SLAM、自动驾驶感知这种硬核方向立刻就露怯——本质原因就是多视图几何这一块没吃透。它不依赖玄学般的网络权重而是建立在严谨的几何和代数约束之上是真正意义上“算出来”的视觉。这篇文章我不打算按教科书顺序给你罗列定义而是从一个从业者的视角把“多视图几何”这条学习主线拆开揉碎讲清楚它到底在干什么、每个核心模块解决的痛点是什么、实际工程中又会踩到哪些坑。内容会覆盖从相机模型到对极几何、三角测量、PnP、Bundle Adjustment的全链路既有数学直觉也有代码层面的落地思路。适合正在学习三维视觉的学生、刚接触SLAM或SfM的工程师以及任何想搞明白“为什么两张图能算出三维坐标”的好奇心驱动者。1. 多视图几何到底在解决什么问题从单目到多视图的思维转变先想一个很基础的问题给你一张照片你能恢复出场景的真实三维结构吗答案是不能至少不能唯一确定。原因是投影过程丢失了深度信息一个三维点可以被映射到像平面的某个像素上但反过来这个像素对应的是三维空间中的一整条射线。这就是所谓的“多对一”映射——信息不可逆。单张图不行那双目或者多目呢关键变化在于不同的视角对同一个三维点的观测之间存在一种可以被数学刻画的几何约束。多视图几何研究的就是这种跨视角几何关系。当你知道了多个相机之间的相对位姿和同一个点在多个图像上的投影位置之后就可以反过来求这个点的三维坐标这就是三角测量。更进一步如果你连相机位姿都不知道也可以通过足够多的匹配点先估算出相机的位姿和场景结构这就是运动恢复结构Structure from MotionSfM的基本思想。我第一次真正被这个领域震撼到是跑通了一个简单的SfM流程看着散乱的点云从一堆照片里“长”出来的时候。那种感觉和跑通一个分类网络完全不同它让你觉得视觉系统真的在“理解”三维世界而不是在拟合标签分布。多视图几何在产业界的应用面非常广。视觉SLAM用它来做相机定位和地图构建自动驾驶用它来做多目相机的外参标定和障碍物的三维位置估计工业检测用它来做零件的三维尺寸测量手机摄影用它来实现虚化模拟和AR效果。可以说任何需要从图像中恢复三维信息的场景底层都跑不掉这套几何框架。这套框架和深度学习并不矛盾相反它是深度学习的“地基”。现代基于学习的三维重建方法比如MVSNet、NeRF这类明星方案最终生成的深度图或三维表征也都需要多视图几何提供的相机姿态作支持——如果没有准确的位姿基于学习的多视角融合就是无源之水。2. 先过数学关坐标变换链与最小二乘思想聊多视图几何绕不开坐标变换。这也是很多人在这个领域第一次卡住的地方。其实整套变换逻辑用一句话就能概括把世界坐标系里的一个三维点通过旋转和平移变换到相机坐标系再通过内参投影到像素平面。但具体落地时各种符号定义、齐次坐标、坐标系约定很容易把人绕晕。我的建议是不要死记公式而是理解每个矩阵的“职能”。第一个核心矩阵是内参矩阵K它描述的是相机本身的属性焦距、主点偏移、像素尺度。第二个是外参矩阵包含旋转矩阵R和平移向量t描述的是相机在世界坐标中的位姿。世界坐标系中的点P先经过外参变换到相机坐标系再经过内参投影到像素坐标系整个过程用齐次坐标表示就是一个简单的矩阵连乘。除了这个基本投影链还有一个绕不开的概念是单应矩阵。它描述的是同一平面在两张图像之间的映射关系是一个3x3的矩阵。在纯旋转、平面场景等情况下这个模型非常有用。我见过不少人在平面标记检测、文档拍照矫正、全景拼接这些项目里用到了单应矩阵——它本质上是一种8自由度的几何变换。再说最小二乘。多视图几何里几乎所有核心问题最终都归结于优化给定一堆观测值求一组参数让误差最小。最经典的求解思路是最小二乘但在三维视觉里往往会升级成更稳健的变体。原因很现实你提取的特征匹配中永远存在误匹配一个离群值就可以把普通最小二乘的结果拉偏十万八千里这种情况下就需要RANSAC登场。RANSAC随机采样一致性的思路非常暴力且有效随机采样一小撮匹配点根据这些点估算模型参数然后统计所有数据点中符合这个模型的“内点”数量重复多次保留内点最多的模型。这个思想在多视图几何中无处不在从单应矩阵估计到基础矩阵估计再到PnP求解几乎每个环节都会用到。它不会保证找到数学上的全局最优解但在工程上极其有效——处理带噪声的真实数据这是最实用的方法。3. 对极几何与本质矩阵两张图之间的硬约束从单视图进入双视图最重要的概念就是对极几何。它描述的是同一个三维点P在两个相机成像平面上的投影点p1和p2之间存在的一种内在几何约束与场景结构无关只取决于两个相机的内外参。对极几何的图景是三维点P、两个相机光心O1和O2这三个点确定了一个平面叫做对极平面。对极平面与两个成像平面的交线分别叫做极线。核心结论是——假设已知左边图像上的点p1那么右边图像上对应的点p2一定落在一条直线上这条线就是极线。这是一个极其强大的约束把二维搜索问题压缩到了一维搜索。数学上这个约束最终表达成一个3x3矩阵本质矩阵。它把左图上的点映射到右图上的极线。本质矩阵的特别之处在于它蕴含了相机的相对旋转和平移信息但这些信息被封装在一个特殊结构的矩阵里——它的奇异值具有特定的形式。如果相机内参未知那就要用到基础矩阵它是在像素坐标系下描述这种约束的。在实际工程里我们对极几何最常见的用法是通过大量匹配点对估计本质矩阵然后分解它得到两个相机之间的相对旋转和平移。这一步骤是双目视觉、SFM初始化的基石。我记得第一次手写本质矩阵分解的时候发现分解出来有4组解需要根据点在相机前方的约束筛选出正确的那组——这种细节看书的时候觉得理所当然自己实现的时候才体会到几何推导的微妙。再补充一个高频率使用但经常被误解的操作极线矫正Rectification。它是利用估计出的极线几何关系将两张图像重投影到同一个平面上使得极线变成水平的扫描线。这样做的好处极其明显一旦极线水平了双目匹配问题就退化成了同一行上的搜索问题对应点搜索从二维变成一维计算成本大幅降低。现在大多数双目深度估计的pipeline第一步都是做极线矫正——如果你直接拿原始图像做立体匹配效率会差很多。4. 三角测量与PnP从二维对应到三维坐标的两种路径有了相机位姿之后我们还需要一个操作来真正“产出”三维点这就是三角测量。核心思想很朴素同一个三维点在两张图像上有两个观测射线理论上这两条射线的交点就是三维点的位置。但理想很丰满现实很骨感。由于噪声的存在这两条射线往往不会严格相交于一点而是变成了空间中的两条“异面直线”。这时候就需要一个最优解策略我们可以求解一个三维点使得它到两条射线的距离之和最小。在实际代码实现中通常会使用线性三角化方法——将问题构造成一个齐次线性方程组然后用SVD分解求解。三角测量有一个精度瓶颈需要特别留意基线和角度。当两个视角的夹角太小时射线的交会很不稳定微小图像噪声会导致三维点的大幅偏移也就是说深度估计的不确定性非常大。这种几何退化问题在纯视觉系统中非常常见也是为什么很多系统在平移量小的情况下三维重建质量会断崖式下降。所以在实际数据采集中你需要确保相机之间有足够的平移量或者融合更多的视角来稳定求解。如果说三角测量是“已知位姿求三维点”那么PnPPerspective-n-Point就是“已知三维点和对应像素求相机位姿”。PnP在视觉定位和SLAM中出场率极高——你的地图里有一堆三维路标点当前相机观测到了其中一些点的像素位置那么就可以用PnP估算出当前相机的位姿这是所有基于特征点的重定位系统的核心。PnP的求解方式也有很多种包括直接线性变换DLT、P3P、EPnP等。实际应用中EPnP在小规模点集上非常高效而OpenCV的solvePnP接口方便得很但它内部的算法选择和参数比如useExtrinsicGuess、flags值得仔细研究。PnP还有一个非常容易踩的坑就是对误匹配极其敏感。RANSAC在PnP中的使用几乎是标配随机选取最小数量的匹配对去估算位姿然后用全部匹配做内点统计不断迭代。在工程实践中我会建议你在RANSAC阈值的选择上多做实验——阈值太紧会把正确匹配误伤阈值太松又会放进一堆外点最优值其实取决于特征点的重投影误差分布和经验值直接相关。5. 从增量式到全局式SfM与Bundle Adjustment的工程真相以上提到的都是两个视角之间的几何关系但真实场景往往是几十张、几百张图像。把所有这些图像的特征点关联起来同时恢复出每张图的相机位姿和完整三维点云这就是运动恢复结构SfM要解决的问题。经典的增量式SfM流程路径大约是先做特征提取和匹配建立图像之间的关联然后选择一对匹配质量好、基线合适的图像进行初始化用本质矩阵分解得到初始位姿再用三角测量生成初始点云接下来不断加入新图像用PnP估计新图像的位姿再用三角测量生成新的三维点不断循环扩展。整个过程最后会交由Bundle Adjustment来做全局优化。Bundle Adjustment这个名字很形象——它把所有相机位姿和三维点都看作待优化的“光束”Bundle目标是让所有三维点在所有图像上的重投影误差最小。说白了就是把三维点重新投影回每张图像计算投影位置和实际观测位置的像素差然后调整位姿和三维坐标让这个差距的平方和最小。这个优化问题的变量规模非常大——一个包含几百张图像、几十万个三维点的重建工程动辄就要优化上百万个变量所以稀疏性利用和数值优化技巧极其重要。实际跑SfM时有几个问题你一定会遇到。第一个是累计漂移——增量式SfM在图像序列很长时误差会不断累积导致轨迹从起点开始逐渐偏转最终形成一个明显的“香蕉形”弯曲。这是因为纯视觉的平移估计存在尺度不确定性而且增量过程会不断传递误差。第二个是循环闭合——如果你的相机走了一圈回到原点那闭环检测和全局优化就变得格外重要否则轨迹首尾根本对不上。第三个是场景退化——当成像平面近似于同一个平面时三维结构的解会变得不稳定这是几何上无法回避的病态问题。我们在实际工程里做SfM还会大量依赖COLMAP这类开源工具。但坦率讲COLMAP虽然强大在真实数据上并非万能对纹理稀疏的场景白墙、地面、天空匹配效果很差对玻璃、高光表面也经常翻车。所以做三维重建的数据采集本身就是一个需要设计策略的环节——场景纹理要足够丰富图像间的重叠度要够还要避免大幅度的旋转变化。6. 多视图几何与深度学习融合的几个方向多视图几何本身是个偏经典的领域但在今天的工业界它从来没有像现在这样和深度学习深度交织。这对你来说既是挑战也是重要的加分项。最直接的一个结合点是多视图几何为深度学习提供几何先验和训练数据。比如单目深度估计网络如果想做到尺度一致且绝对尺度准确往往需要大量带真实深度的数据做监督而这些数据的获取很大程度依赖多视图重建生成的高质量深度图。我自己做数据工程时就是先用COLMAP跑一遍多视图重建把稠密深度图渲染出来当标签再用这些标签去训练网络。效果虽然受重建质量影响但比自己硬标数据高效太多了。另一个方向是用深度网络替代传统pipeline中的某个模块。比如特征点检测与匹配——传统的SIFT/ORB虽然在几何上稳健但在弱纹理和光照剧烈变化场景下表现有限而基于学习的特征如SuperPoint、LoFTR系列能捕捉到更语义化的特征稳定性显著提升。这类方法虽然引入了网络推理的算力开销但往往能直接提升下游几何估计的鲁棒性。还有一条更前沿的路子可微分几何优化。在传统几何优化的基础上把网络输出的特征图或概率体直接接入可微分的三角化或者BA模块让整个pipeline可以端到端训练。MVSNet、DeepSFM这些方法都是这条思路的代表作。它们把学习特征和多视图几何约束拧在一起输出的深度图既保持了几何一致性又有极强的语义适应性。我个人的看法是多视图几何不会因为深度学习的发展而过时相反它会成为那些真正想做硬核三维视觉的人的分水岭。很多做深度学习的人不理解“极线约束”很多做传统几何的人接不住“端到端训练”而能把两者打通的人恰恰是行业中最稀缺的角色。7. 学习者最容易陷入的误区与实操建议最后聊一些实实在在的避坑心得这些经验大多是我和身边同事在项目里踩出来的。第一个误区是“背公式不看几何意义”。多视图几何的公式多且长但如果你只是背下来遇到实际问题依然无从下手。我的建议是每学一个公式都在纸上画一遍对应的几何图搞清楚每个符号的物理意义比如极线到底长什么样、本质矩阵的秩为什么是2、为什么一组匹配点只能提供一条约束方程。把几何直觉和代数形式反复对应才能真正内化。第二个误区是“只调库不写代码”。OpenCV确实封装了大部分功能但如果你只是调用solvePnP、triangulatePoints、findFundamentalMat出了问题很难调试。建议至少自己手写一次本质矩阵分解和三角化的核心流程哪怕写得很慢、跑得很笨这个过程带给你的理解要超过十篇论文。你可以先实现一个两视图的完整pipeline——特征匹配、基础矩阵估计、RANSAC、本质矩阵分解、三角测量——这个过程做完多视图几何的骨架基本就掌握了。第三个经验是“重视标定和数据质量”。多视图几何是典型的“垃圾进垃圾出”。内参不准、镜头畸变没校正、图像模糊、重叠度不足这些都会让你的重建结果惨不忍睹。做工程时我几乎一半时间都花在数据筛选、标定和预处理上剩下才是算法调优。很多论文里的漂亮结果放到自采数据上效果平庸绝大多数情况下问题都出在数据质量而不是算法本身。第四个关键点注意数学工具的底层原理。SVD奇异值分解在多视图几何里无处不在——本质矩阵分解要SVD三角测量要SVD基础矩阵求解也要SVD。你需要理解为什么用SVD以及怎么从SVD的结果里提取有效信息比如通过最小奇异值对应的右奇异向量来求解齐次方程组。这些能力在写代码和调试异常结果时会反复用到。我见过不少人不知道SVD和特征分解的区别也不清楚奇异值大小对应的数据意义结果遇到数值不稳定的情况完全不知道该朝哪个方向排查。第五个建议从视觉SLAM项目切入练习。多视图几何的大多数知识点在视觉SLAM中都有明确落点——前端特征匹配对应特征点提取和描述子后端优化对应BA和图优化回环检测可以进一步理解位置识别的地理几何约束。我的学习路径是先跑通一个简单的两视图重建脚本再把这个脚本扩展到多帧增量式重建最后再去读ORB-SLAM3的代码。这个过程大概花了三个月但效果比看半年网课好得多。如果你决定要系统掌握这套东西我建议顺序是先内参模型和坐标变换再单应矩阵再对极几何和基础/本质矩阵然后三角测量和PnP之后用SfM把这些串起来最后研究BA和位姿图优化。每走一步都配合一个具体项目来练手。不要贪多贪快因为几何里的每一步都会成为下一步的前提。等你真的把这条链路走通再回头看刚才用深度学习做三维的那些模型视角绝对会完全不一样。