目标:理解 MVS 如何在已知相机位姿下恢复稠密几何,能使用 COLMAP/OpenMVS 完成稠密重建,能用 OpenCV 做双目视差实验,并能回答常见面试问题。
目录
- 1. MVS 是什么
- 2. MVS 解决什么问题
- 3. MVS 和 SfM、SLAM、NeRF、3DGS 的关系
- 4. MVS 基本输入和输出
- 5. MVS 核心原理
- 6. 极线约束和深度搜索
- 7. 代价体 Cost Volume
- 8. PatchMatch MVS
- 9. 深度图、法线图和融合
- 10. MVS 常见方法分类
- 11. 数据采集建议
- 12. 实操一:COLMAP 稠密重建
- 13. 实操二:OpenMVS 稠密重建和网格纹理
- 14. 实操三:OpenCV 双目视差和点云
- 15. 实操四:检查 MVS 输出质量
- 16. MVS 在 3DGS/NeRF 工作流中的定位
- 17. 常用参数和调参经验
- 18. 常见问题排查
- 19. 面试常问问题
- 20. 练习任务
- 21. 参考资料
1. MVS 是什么
MVS,全称 Multi-View Stereo,多视图立体。
它的目标是:
在已知多张图像的相机内外参后,恢复场景的稠密三维几何。一句话理解:
SfM 先告诉我们相机在哪里,MVS 再利用这些相机视角,把场景表面恢复得更密。典型输入:
- 多张有重叠的图片。
- 每张图片的相机内参。
- 每张图片的相机外参。
- 可选稀疏点云。
典型输出:
- 每张图片的深度图。
- 每张图片的法线图。
- 稠密点云。
- Mesh。
- 带纹理 Mesh。
2. MVS 解决什么问题
SfM 输出通常是稀疏点云,只有少量特征点位置。
MVS 想进一步恢复:
每个可见表面位置在哪里? 每个像素对应的深度是多少? 如何把多视图深度融合成稠密点云或 mesh?应用:
- 三维重建。
- 建筑和文物数字化。
- 无人机测绘。
- 工业检测。
- 机器人环境建模。
- 3D 数据集生成。
- Mesh 纹理重建。
3. MVS 和 SfM、SLAM、NeRF、3DGS 的关系
3.1 MVS 和 SfM
关系最直接:
SfM: 恢复相机位姿 + 稀疏点云 MVS: 使用 SfM 位姿恢复稠密几何典型流程:
图片 -> SfM -> 相机参数 + 稀疏点云 -> MVS -> 深度图 + 稠密点云 + Mesh3.2 MVS 和 SLAM
SLAM 偏实时定位和建图,MVS 多用于离线高质量稠密重建。
3.3 MVS 和 NeRF/3DGS
NeRF/3DGS 主要用于新视角合成,不一定直接输出干净 mesh。
MVS 主要追求显式几何:
depth maps dense point cloud mesh3DGS 常用 COLMAP 的 SfM 结果,不一定需要 MVS。但如果要 mesh、稠密点云或几何监督,MVS 会很有用。
4. MVS 基本输入和输出
4.1 输入
MVS 输入通常要求:
- 图像之间有足够重叠。
- 相机位姿准确。
- 相机内参准确。
- 图像清晰。
- 场景尽量静态。
如果位姿错,MVS 很难恢复正确深度。
4.2 输出
常见输出:
depth map: 每张参考图上每个像素的深度 normal map: 每个像素对应表面的法线方向 dense point cloud: 多张深度图融合后的稠密点云 mesh: 从点云或深度图重建的表面 textured mesh: 带纹理的 mesh5. MVS 核心原理
MVS 的核心假设:
同一个三维表面点,在不同视角中应该有一致的外观。这叫 photo-consistency,光度一致性。
对于参考图像中的一个像素,MVS 会在不同深度假设下,把该 3D 点投影到其他视角,比较颜色或特征是否一致。
流程:
选参考图像 -> 对每个像素假设多个深度 -> 投影到邻近视角 -> 计算匹配代价 -> 选择代价最小的深度 -> 空间正则化和一致性检查6. 极线约束和深度搜索
对于两张已知相机位姿的图像,一个像素在另一张图中的匹配点不需要全图搜索,而是在极线上搜索。
双目校正后,极线通常变成水平线,此时匹配问题变成视差搜索:
disparity = x_left - x_right depth = fx * baseline / disparity多视图情况下,深度假设会投影到多个源视图,综合多个视图的匹配代价。
7. 代价体 Cost Volume
深度估计常构建 cost volume:
height x width x depth_candidates每个位置表示:
某个像素在某个深度假设下的匹配代价。传统方法可能使用:
- NCC。
- SAD/SSD。
- Census transform。
- Patch matching。
深度学习方法可能使用:
- 特征提取网络。
- 多视图特征 warping。
- 3D CNN 正则化 cost volume。
8. PatchMatch MVS
PatchMatch 是 COLMAP MVS 中非常重要的思想。
核心思想:
随机初始化深度和法线假设, 通过邻域传播和随机搜索,不断改进每个像素的深度/法线。为什么有效:
- 相邻像素通常在同一表面上,深度和法线相近。
- 好的假设可以从邻居传播过来。
- 随机搜索避免陷入局部差结果。
COLMAP 的patch_match_stereo会为每张图估计深度图和法线图。
9. 深度图、法线图和融合
9.1 深度图
深度图表示每个像素到相机的距离或 z 深度。
9.2 法线图
法线图表示每个像素对应表面的方向。
法线有助于:
- PatchMatch 平面假设。
- 几何一致性。
- 后续融合和网格重建。
9.3 深度融合
每张图都可以生成一张深度图。融合时需要把这些深度图反投影到世界坐标,并做一致性检查。
融合要解决:
- 同一个表面点被多个视角看到。
- 深度噪声。
- 遮挡。
- 离群点。
- 重复点。
COLMAP 使用stereo_fusion生成稠密点云。
10. MVS 常见方法分类
10.1 Voxel-based MVS
把空间划成体素,判断哪些体素属于表面。
优点:
- 几何直观。
缺点:
- 内存消耗大。
- 分辨率受体素大小限制。
10.2 Depth-map-based MVS
为每个参考视角估计深度图,再融合。
优点:
- 工程常用。
- 可扩展性好。
- 与图像分辨率对应自然。
COLMAP、OpenMVS 常见流程都和 depth-map-based 思路相关。
10.3 Patch-based MVS
用小面片表示场景表面,例如 PMVS。
10.4 Learning-based MVS
代表:
- MVSNet。
- R-MVSNet。
- CasMVSNet。
- PatchmatchNet。
特点:
- 用神经网络学习特征和代价聚合。
- 对弱纹理和复杂场景可能更鲁棒。
- 需要训练数据,泛化和显存开销要关注。
11. 数据采集建议
MVS 比 SfM 更依赖密集纹理和稳定光照。
建议:
- 相邻图片重叠率 70% 左右。
- 避免运动模糊。
- 避免强反光、玻璃、水面。
- 曝光和白平衡稳定。
- 不要频繁变焦。
- 尽量拍摄有纹理表面。
- 对薄结构、多孔结构多拍角度。
- 避免动态人车。
不利场景:
- 白墙。
- 黑色无纹理物体。
- 透明物体。
- 镜面金属。
- 重复纹理。
- 草、树叶、水面等细碎动态区域。
12. 实操一:COLMAP 稠密重建
这个流程从已完成 SfM 的 COLMAP sparse 模型开始。
目录假设:
project/ images/ workspace/ database.db sparse/ 0/ cameras.bin images.bin points3D.bin12.1 图像去畸变
colmap image_undistorter\--image_pathimages\--input_pathworkspace/sparse/0\--output_pathworkspace/dense\--output_typeCOLMAP输出:
workspace/dense/ images/ sparse/ stereo/12.2 PatchMatch Stereo
colmap patch_match_stereo\--workspace_pathworkspace/dense\--workspace_formatCOLMAP\--PatchMatchStereo.geom_consistencytrue如果没有 GPU:
colmap patch_match_stereo\--workspace_pathworkspace/dense\--workspace_formatCOLMAP\--PatchMatchStereo.geom_consistencytrue\--PatchMatchStereo.gpu_index-112.3 深度融合
colmap stereo_fusion\--workspace_pathworkspace/dense\--workspace_formatCOLMAP\--input_typegeometric\--output_pathworkspace/dense/fused.ply12.4 Mesh 重建
Poisson:
colmap poisson_mesher\--input_pathworkspace/dense/fused.ply\--output_pathworkspace/dense/meshed-poisson.plyDelaunay:
colmap delaunay_mesher\--input_pathworkspace/dense\--output_pathworkspace/dense/meshed-delaunay.ply12.5 查看结果
可以使用:
- COLMAP GUI。
- MeshLab。
- CloudCompare。
- Blender。
查看:
workspace/dense/fused.ply workspace/dense/meshed-poisson.ply workspace/dense/meshed-delaunay.ply13. 实操二:OpenMVS 稠密重建和网格纹理
OpenMVS 常用于从 COLMAP 结果继续做稠密点云、mesh 和纹理。
13.1 从 COLMAP 转 OpenMVS
OpenMVS 提供接口工具,例如InterfaceCOLMAP。具体命令随安装方式略有差异,常见思路:
InterfaceCOLMAP\-iworkspace/dense\-oscene.mvs如果你的 OpenMVS 工具路径不同,请查看:
InterfaceCOLMAP--help13.2 稠密点云
DensifyPointCloud scene.mvs输出常见:
scene_dense.mvs scene_dense.ply13.3 重建 Mesh
ReconstructMesh scene_dense.mvs输出常见:
scene_dense_mesh.mvs scene_dense_mesh.ply13.4 优化 Mesh
RefineMesh scene_dense_mesh.mvs13.5 纹理贴图
TextureMesh scene_dense_mesh_refine.mvs输出带纹理的 mesh,常见格式包括:
obj mtl texture images注意:
- OpenMVS 命令和文件名会随版本和参数变化。
- 实操时先用
--help看当前安装版本的命令参数。
14. 实操三:OpenCV 双目视差和点云
这个实验是双目 stereo,不是完整多视图 MVS,但有助于理解视差、深度和点云。
安装:
pipinstallopencv-python numpy open3d准备:
left.png right.png要求:
- 两张图已经双目校正。
- 极线大致水平。
- 已知
fx和 baseline。
保存为stereo_depth_demo.py:
importcv2ascvimportnumpyasnpimportopen3daso3ddefmain():left=cv.imread("left.png",cv.IMREAD_GRAYSCALE)right=cv.imread("right.png",cv.IMREAD_GRAYSCALE)color=cv.imread("left.png",cv.IMREAD_COLOR)ifleftisNoneorrightisNoneorcolorisNone:raiseRuntimeError("Please provide left.png and right.png.")stereo=cv.StereoSGBM_create(minDisparity=0,numDisparities=128,blockSize=5,P1=8*1*5*5,P2=32*1*5*5,mode=cv.STEREO_SGBM_MODE_SGBM_3WAY,)disparity=stereo.compute(left,right).astype(np.float32)/16.0fx=700.0baseline=0.10cx=left.shape[1]/2.0cy=left.shape[0]/2.0valid=disparity>1.0depth=np.zeros_like(disparity,dtype=np.float32)depth[valid]=fx*baseline/disparity[valid]ys,xs=np.where(valid)z=depth[ys,xs]x=(xs-cx)*z/fx y=(ys-cy)*z/fx points=np.stack([x,y,z],axis=1)colors=color[ys,xs][:,::-1]/255.0pcd=o3d.geometry.PointCloud()pcd.points=o3d.utility.Vector3dVector(points)pcd.colors=o3d.utility.Vector3dVector(colors)o3d.io.write_point_cloud("stereo_points.ply",pcd)print("saved stereo_points.ply")if__name__=="__main__":main()重点公式:
depth = fx * baseline / disparity如果 disparity 很小,深度会很大,噪声也会被放大。
15. 实操四:检查 MVS 输出质量
15.1 看稠密点云
用 CloudCompare 或 MeshLab 打开:
fused.ply重点看:
- 是否有大片飞点。
- 主要物体是否完整。
- 表面是否过厚。
- 点云密度是否均匀。
- 是否有明显断裂和空洞。
15.2 看 Mesh
检查:
- 是否有破洞。
- 是否有错误连接。
- 薄结构是否丢失。
- 反光/透明区域是否异常。
- 纹理是否错位。
15.3 看深度图
COLMAP dense 目录中会保存 stereo 结果。不同版本文件格式不同,可以用 COLMAP GUI 或工具脚本查看深度图。
深度图异常表现:
- 大片无效。
- 边缘毛刺。
- 平面波浪。
- 前景背景混合。
16. MVS 在 3DGS/NeRF 工作流中的定位
16.1 3DGS 是否需要 MVS
原始 3DGS 常见流程只需要 SfM 的 sparse 输出:
cameras images points3D不一定需要 MVS 的 dense 点云。
但 MVS 可以用于:
- 生成更稠密的几何参考。
- 检查 SfM 位姿是否可靠。
- 给其他方法提供深度监督。
- 提取 mesh 做传统资产。
- 和 3DGS 结果做几何对比。
16.2 NeRF 是否需要 MVS
NeRF 训练通常需要相机位姿,不一定需要 MVS。MVS 深度可以作为监督或先验,用于加速或约束几何。
16.3 MVS 和 3DGS 的输出差异
| 对比 | MVS | 3DGS |
|---|---|---|
| 主要输出 | 深度图、稠密点云、mesh | 高斯点模型、新视角渲染 |
| 目标 | 显式几何 | 高质量实时渲染 |
| 对纹理依赖 | 高 | 高,但优化方式不同 |
| 对动态物体 | 敏感 | 也敏感 |
| 是否直接 mesh | 可以 | 默认不是 |
17. 常用参数和调参经验
17.1 COLMAP PatchMatch 参数
常见关注:
PatchMatchStereo.geom_consistency PatchMatchStereo.window_radius PatchMatchStereo.num_samples PatchMatchStereo.num_iterations PatchMatchStereo.gpu_index建议:
- 初学优先使用默认参数。
- 开启 geometric consistency 通常能减少错误深度。
- 显存不足时降低图片分辨率或减少并行。
17.2 stereo_fusion 参数
关注:
StereoFusion.min_num_pixels StereoFusion.max_reproj_error StereoFusion.max_depth_error StereoFusion.max_normal_error直觉:
- 参数严格:点云更干净,但可能更稀疏。
- 参数宽松:点云更密,但飞点更多。
具体参数名和默认值建议用:
colmap stereo_fusion-h查看当前版本。
17.3 图片分辨率
图片越大:
- 细节更多。
- 计算更慢。
- 显存占用更高。
如果只是学习流程,可以先缩小图片。
17.4 视角选择
MVS 不一定用所有图像做源视角。源视角要:
- 和参考图有足够重叠。
- 有合适基线。
- 不要太近,也不要太远。
- 光照差异不要太大。
18. 常见问题排查
18.1 稠密点云很稀疏
可能原因:
- SfM 位姿不准。
- 图片纹理少。
- 图片重叠不足。
- PatchMatch 参数太严格。
- 图像分辨率太低。
处理:
- 提高图片质量。
- 增加视角。
- 检查 SfM 结果。
- 适当放宽 fusion 参数。
18.2 飞点很多
可能原因:
- 弱纹理。
- 反光/透明区域。
- 动态物体。
- 位姿误差。
- fusion 参数太宽松。
处理:
- 开启几何一致性。
- 收紧 fusion 参数。
- 清理动态图片。
- 删除反光严重区域。
18.3 Mesh 破洞多
可能原因:
- 点云本身缺失。
- 视角覆盖不足。
- 表面弱纹理。
- 过滤太严格。
处理:
- 补拍。
- 放宽融合参数。
- 使用 Poisson 重建尝试补洞。
- 用后处理工具修复 mesh。
18.4 纹理错位
可能原因:
- 相机位姿不准。
- mesh 几何不准。
- 图片曝光差异大。
- 纹理投影选择不合理。
18.5 透明和反光物体重建差
这是 MVS 经典难点。
原因:
- photo-consistency 假设不成立。
- 不同视角看到的颜色变化大。
- 透明物体没有稳定表面纹理。
19. 面试常问问题
19.1 MVS 是什么?
MVS 是 Multi-View Stereo,多视图立体。它在已知多张图像相机内外参的情况下,通过多视图一致性恢复场景的稠密三维几何。
19.2 MVS 和 SfM 有什么区别?
SfM 用特征匹配恢复相机位姿和稀疏点云;MVS 在已知相机位姿基础上恢复稠密深度、稠密点云或 mesh。
19.3 MVS 的输入和输出是什么?
输入是多张图像、相机内参和外参。输出通常是深度图、法线图、稠密点云、mesh 或带纹理 mesh。
19.4 MVS 的核心假设是什么?
核心假设是光度一致性:同一个三维表面点在多个视角下应该具有一致或相近的外观。
19.5 什么是深度图?
深度图表示图像中每个像素对应的三维点到相机的深度。
19.6 什么是法线图?
法线图表示每个像素对应表面的方向,常用于平面假设、几何一致性和融合。
19.7 什么是 cost volume?
cost volume 是一个三维代价空间,记录每个像素在不同深度假设下的匹配代价。
19.8 PatchMatch MVS 的核心思想是什么?
随机初始化深度/法线假设,通过邻域传播和随机搜索不断优化每个像素的深度和法线。
19.9 为什么 MVS 需要已知相机位姿?
因为 MVS 需要把参考图像中的深度假设投影到其他视角比较一致性,如果相机位姿不准,投影位置会错,深度估计也会错。
19.10 MVS 为什么怕弱纹理?
弱纹理区域不同深度下的外观差异不明显,匹配代价难以区分,深度估计容易不稳定。
19.11 MVS 为什么怕反光和透明物体?
因为反光和透明物体在不同视角下外观变化大,不满足光度一致性假设。
19.12 双目视差和深度是什么关系?
校正双目中:
depth = fx * baseline / disparity视差越大,深度越近;视差越小,深度越远。
19.13 MVS 中如何融合多张深度图?
把每张深度图反投影成 3D 点,再根据多视图几何一致性、深度一致性、法线一致性等条件过滤和合并,得到稠密点云。
19.14 COLMAP 的稠密重建流程是什么?
先用image_undistorter去畸变,再用patch_match_stereo估计深度和法线,最后用stereo_fusion融合成稠密点云,可选poisson_mesher或delaunay_mesher生成 mesh。
19.15 OpenMVS 常见流程是什么?
通常从 COLMAP 导入模型,执行DensifyPointCloud得到稠密点云,ReconstructMesh生成 mesh,RefineMesh优化 mesh,TextureMesh生成纹理。
19.16 MVS 和 3DGS 有什么关系?
MVS 主要输出显式稠密几何;3DGS 主要优化高斯表示用于新视角渲染。3DGS 通常需要 SfM 位姿和稀疏点,不一定需要 MVS,但 MVS 可用于几何参考或深度监督。
19.17 MVS 结果质量怎么看?
看稠密点云覆盖是否完整、飞点是否多、mesh 是否有破洞和错误连接、纹理是否错位、深度图是否平滑且边缘合理。
19.18 MVS 点云飞点多怎么办?
检查 SfM 位姿,开启几何一致性,收紧融合参数,删除动态和反光图片,增加视角覆盖并提高图像质量。
19.19 MVS 和深度学习 MVS 有什么区别?
传统 MVS 通常依赖手工相似性度量和优化策略;深度学习 MVS 使用神经网络提取特征、构建和正则化 cost volume,可能对复杂场景更鲁棒,但需要训练数据和更多显存。
19.20 面试中如何概括 MVS 项目经验?
可以这样回答:
我用 MVS 做过多视角稠密重建。流程是先用 SfM/COLMAP 恢复相机内外参和稀疏点云, 再进行图像去畸变,使用 PatchMatch Stereo 为每张参考图估计深度图和法线图, 然后通过多视图几何一致性把深度图融合成稠密点云,最后可选 Poisson 或 Delaunay 生成 mesh。 排查时我会重点看 SfM 位姿质量、图像重叠和纹理、深度图有效区域、飞点数量和 mesh 破洞情况。20. 练习任务
20.1 跑通 COLMAP MVS
准备一组图片,先跑 SfM,再执行:
image_undistorter patch_match_stereo stereo_fusion poisson_mesher查看fused.ply和 mesh。
20.2 比较稀疏和稠密点云
比较:
SfM sparse points3D MVS fused.ply观察点数量、覆盖范围和噪声差异。
20.3 调整 fusion 参数
尝试更严格和更宽松的 fusion 参数,观察:
- 点云密度。
- 飞点数量。
- 表面完整度。
20.4 OpenCV 双目实验
使用一组校正过的双目图片,运行StereoSGBM,输出视差图和点云。
20.5 OpenMVS 流程
从 COLMAP 模型导入 OpenMVS,依次运行:
InterfaceCOLMAP DensifyPointCloud ReconstructMesh RefineMesh TextureMesh观察每一步结果变化。
21. 参考资料
- COLMAP 官方文档:https://colmap.github.io/
- COLMAP CLI 文档:https://colmap.github.io/cli.html
- COLMAP Tutorial:https://colmap.github.io/tutorial.html
- COLMAP Output Format:https://colmap.github.io/format.html
- OpenMVS 官方仓库:https://github.com/cdcseacave/openMVS
- OpenMVS Wiki:https://github.com/cdcseacave/openMVS/wiki
- OpenCV StereoSGBM 文档:https://docs.opencv.org/4.x/d2/d85/classcv_1_1StereoSGBM.html
- OpenCV reprojectImageTo3D 文档:https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html
- MVSNet 论文:https://arxiv.org/abs/1804.02505
- PatchmatchNet 论文:https://arxiv.org/abs/2112.01411
- Multiple View Geometry in Computer Vision,Hartley & Zisserman。