COLMAP与CasMVSNet实战:从零搭建三维重建全流程
1. 项目概述三维重建这几年真的是在机器人和自动驾驶圈子里火得不行各种基于深度学习的MVS多视图立体匹配网络一个接一个往外冒。但是模型再好落不了地也是白搭。我在跑CasMVSNet的时候就发现这东西的坑不在网络结构本身而在数据准备和环境搭建——营养全在COLMAP出点云、出位姿这一步。你用Liem(生命格式)或者其他公开数据集还好一旦换成自己拍的图、网上扒的图COLMAP的参数、输出格式、相机模型每一项都可能让你的训练或者推理直接翻车。这篇博客我打算从零开始完整记录我如何使用autodl服务器跑通CasMVSNet以及如何用COLMAP生成自己想要的数据格式。如果你正面临“数据集格式不对”“自己拍的照片不知道怎么做成标准输入”“在云服务器上装环境装到怀疑人生”这些问题这篇文章应该能帮你省下一到两周的折腾时间。我会把每一步的关键参数、报错点、还有跳过的坑都写清楚适合有一定深度学习基础、但对三维重建全链路还不熟悉的同学。1.1 核心需求解析搞CasMVSNet这类型算法最大的痛点是数据不只要求图片还需要每张图对应的相机内参、外参以及深度图的范围信息。COLMAP作为最常用的SfM工具天然可以生成这些参数所以CasMVSNet的官方仓库也提供了COLMAP数据到MVS数据格式的转换脚本。我们要做的就是把这条链路给打通。在autodl云服务器上做这件事有一个巨大的优势GPU不需要我自己买按小时租跑坏了也不心疼。配合VSCode远程连接体验其实和本地开发几乎一样只是数据上传和下载稍微麻烦一点。我会把上传、解压、环境搭建、COLMAP运行、CasMVSNet推理整个流程全都过一遍。1.2 适用人群说明如果你是下面几类人之一那这篇内容非常对口正在做三维重建相关课题的研究生想用深度学习MVS方法但不会处理数据或者已经在用COLMAP但不知道怎么把结果输入到CasMVSNet这类网络里又或者你手上有一堆相机拍的照片想重建出一个相对精细的模型但卡在环境配置这一步。当然如果你是纯做算法研究、只想在公开数据集上跑跑看效果那也可以直接跳到训练和推理部分。2. 环境准备与服务器选型2.1 为什么选择autodl以前我在本地用RTX 2080 Ti跑MVS类的模型显存是真的吃紧。CasMVSNet这种级联结构在推理阶段还好但训练时一个batch都放不下更别提中间还会生成大量的代价体。后来我转战autodl主要看中它三个点环境镜像省心、GPU型号灵活、按时计费可控。autodl有一个很实用的功能就是官方PyTorch镜像。你不需要自己从零装CUDA、cuDNN和PyTorch直接在租机时指定镜像版本开机就能进conda环境跑代码。这样可以把大量时间省下来专注在数据和算法本身。它默认支持VSCode、JupyterLab、SSH直连基本能覆盖大部分开发场景。而且如果你中途发现显卡不够用可以直接换一台更高配置的实例数据盘可以制作成镜像或者迁移。2.2 租机与基础配置流程第一次在autodl租机的流程很简单我大致梳理一下。注册登录后进入算力市场选择一张合适的显卡。对于CasMVSNet来说显存至少要8GB起步我个人的建议是选择RTX 3090、RTX 4090或者A5000系列16GB以上显存跑起来才比较舒服。尤其是训练的时候显存不够极易导致OOM白白浪费租机费用。选好机器后在创建实例页面选择镜像。这里的核心要点是框架选择PyTorch版本建议选较新的比如1.13或2.xCUDA版本选择11.x或12.x。再看一下python版本最好是3.8到3.10之间太老或太新都会有一些依赖问题。后面执行代码时都是以conda环境为基础所以镜像选得合适能少踩很多坑。创建实例时还需要挂载数据盘。autodl在root目录下通常有一个autodl-tmp数据盘容量较大且支持扩容适合放数据集、项目和生成的中间结果。强烈建议把所有大文件都放在这个目录下不要放在系统盘因为系统盘的容量一般只有30GB左右跑几个数据集加上检查点就满了。开机之后可以通过网页的JupyterLab进入也可以用VSCode远程连接。实际操作中我更推荐VSCode配合Remote-SSH插件体验非常接近本地开发。autodl会提供一个SSH登录指令格式一般是 ssh -p 端口 root地址把密码填好直接就能连上。如果你用的是VSCode只需要在远程资源管理器里新建一个SSH主机粘贴命令再输入密码服务器上的代码就可以像本地一样编辑调试了。2.3 COLMAP在Linux端的安装在autodl的镜像上安装COLMAP最方便的方式是用apt。但这里有个坑apt源里面的COLMAP版本很可能比较老某些时候比如相机模型或者输出格式的兼容性会出现和CasMVSNet转换脚本不匹配的情况。所以我更推荐使用conda安装或者源码编译。conda方式一行命令就能搞定conda install -c conda-forge colmap这样装的是最新稳定版包含完整的SfM和MVS功能。但如果你需要CUDA加速的特征提取和匹配还需要保证COLMAP是在CUDA环境下编译的。conda-forge通常默认支持CUDA但有些老版本可能不支持所以在安装前先确认一下版本号。源码编译是更保险的路径。先安装依赖项apt-get update apt-get install -y \ git cmake ninja-build build-essential \ libboost-program-options-dev libboost-filesystem-dev \ libboost-graph-dev libboost-system-dev libeigen3-dev \ libflann-dev libfreeimage-dev libmetis-dev \ libgoogle-glog-dev libgtest-dev libsqlite3-dev \ libglew-dev qtbase5-dev libqt5opengl5-dev libcgal-dev然后克隆COLMAP源码按官方文档执行标准cmake构建流程。源码编译虽然耗时但能确保和CUDA版本匹配不容易出现莫名其妙的崩溃。我在autodl上用源码编译大约花了二十分钟整个过程没有特别意外就是依赖要装全。安装完成后可以在终端里测试一下colmap -h如果正常输出帮助信息就说明COLMAP已经可用了。3. COLMAP数据生产实操3.1 COLMAP工作流与核心原理COLMAP是一个开源的SfM运动恢复结构和MVS多视角立体视觉工具。它的工作流程大体分两段稀疏重建和稠密重建。稀疏重建先对每张图片提取特征点比如SIFT特征然后进行特征匹配通过多对视图之间的匹配关系估计相机的位姿。这里的原理是基于对极几何和光束法平差优化最终得到相机的内外参数以及场景的稀疏点云。稠密重建则是在稀疏点云的引导下对每个像素估计深度生成更密集的三维点云。我们使用COLMAP产生的数据重点在于稀疏重建阶段生成的两样东西每张图片的相机参数文件cameras.bin/images.bin和三维点云。CasMVSNet这类MVS网络需要的就是这些参数把它转成自己的格式然后用代价体进行深度估计。理解这一点很关键因为只有知道COLMAP输出的各部分是什么含义才能在格式转换出问题时快速想到是哪里出的错。3.2 用自己的图片生成CasMVSNet输入数据假设你已经有一批自己拍的或网上下载的图片存储在一个名为images的文件夹里。这里有一个强烈建议图片数量最好在10张以上且每对相邻图片之间要有足够的视差也就是从不同角度拍摄同一个物体区域。如果图片太少或者拍摄角度太接近COLMAP的特征匹配会失败后续就没法生成有效的相机参数。在autodl的终端里创建工作目录并运行mkdir -p /root/autodl-tmp/project/jizai/images colmap feature_extractor \ --database_path /root/autodl-tmp/project/jizai/database.db \ --image_path /root/autodl-tmp/project/jizai/images \ --ImageReader.single_camera 1 \ --ImageReader.camera_model PINHOLEfeature_extractor负责特征提取。这里我特别标注了相机模型为PINHOLE这样输出的内参只有fx、fy、cx、cy四个参数方便CasMVSNet的转换脚本解析。如果不指定COLMAP默认可能用SIMPLE_RADIAL等模型多出来几个畸变系数虽然也可以转但处理和验证逻辑会多一些。然后进行特征匹配和稀疏重建colmap exhaustive_matcher \ --database_path /root/autodl-tmp/project/jizai/database.db mkdir -p /root/autodl-tmp/project/jizai/sparse colmap mapper \ --database_path /root/autodl-tmp/project/jizai/database.db \ --image_path /root/autodl-tmp/project/jizai/images \ --output_path /root/autodl-tmp/project/jizai/sparse在图片数量不是特别多少于100张的情况下用exhaustive_matcher暴力匹配即可。如果图片量大了可以改用sequential_matcher或vocab_tree_matcher速度会快很多。映射过程结束后会在sparse目录下生成0号子目录里面包含cameras.bin、images.bin、points3D.bin。如果这一步失败大概率是特征匹配数量不够可以用COLMAP的GUI界面打开数据库检查匹配情况或者适当调低特征提取阈值。在服务器上通常没有GUI环境我一般直接看输出日志里的匹配对数太少就想办法补拍或调整图片集。3.3 格式转换colmap2mvsnet脚本的使用CasMVSNet官方仓库的utils文件夹里有一个colmap2mvsnet.py脚本作用是把COLMAP生成的稀疏重建结果转换成MVS风格的数据格式。转换后的目录结构会像这样datasets/custom/小鹿/ ├── images ├── cams ├── pair.txt └── ...images里是输入的图片副本cams里是每张图对应的相机参数txt文件pair.txt保存视图配对关系和得分。转换之前先把CasMVSNet仓库克隆到服务器上cd /root/autodl-tmp/project git clone https://github.com/kwea123/CasMVSNet_pl.git这个仓库是PyTorch Lightning版本比官方TensorFlow版更容易上手。然后执行转换cd CasMVSNet_pl python utils/colmap2mvsnet.py \ --dense_folder /root/autodl-tmp/project/jizai \ --save_folder /root/autodl-tmp/project/jizai/mvsnet_input \ --convert_format脚本会读取sparse/0下的参数生成mvsnet_input目录。我建议把--save_folder设置成一个独立目录不要把结果和原始COLMAP输出的目录混在一起避免后面路径解析出错。转换完成后检查一下cams文件夹里的txt文件内容应该包括相机的内参矩阵、外参矩阵以及深度范围。如果你发现深度范围是0到0那就说明转换时没有正确读取点云需要在脚本后面增加点云约束范围参数比如--max_disp或者--depth_range。4. CasMVSNet原理与代码结构解析4.1 为什么选CasMVSNetCasMVSNet是CVPR 2020发布的一项工作核心思想是级联cascade代价体。传统的MVSNet会在单一分辨率下构建一个巨大的3D代价体然后用3D卷积正则化这种方法非常吃显存分辨率一高基本就废了。CasMVSNet则是从粗到细先在低分辨率下估计一个大概的深度范围然后逐级细化每级只需要在一个较小的深度区间内构建代价体精度和显存消耗的平衡做得非常好。实际使用中我用CasMVSNet在DTU数据集上的测试效果和MVSNet差不多但推理速度明显更快显存占用也小。对于从COLMAP生成的紧凑场景数据来说CasMVSNet对相机位姿误差的鲁棒性也比一些单阶段方法好一些。这也是我推荐它的原因。4.2 代码目录结构与关键模块casMVSNet_pl仓库的代码结构比较清晰主要模块包括datasets/负责数据加载和预处理dtu.py负责DTU数据集general.py负责自定义数据models/网络模型定义包含特征提取、代价体构建、深度图回归等模块train.py和test.py训练和推理入口utils/包含colmap2mvsnet.py等辅助脚本注意如果你用的是官方TensorFlow版目录结构会不同但核心模块思路类似。PyTorch Lightning版对调试更友好因为checkpoint、日志这些都被框架管理起来了我们只需要关注数据和模型本身。在跑推理前要先修改一下配置文件或者直接通过命令行指定数据路径。Lightning的test脚本一般读取一个配置类包含数据根目录、模型权重路径、输出目录等。这里我把关键的命令行参数展示一下python test.py \ --dataset general \ --data_root /root/autodl-tmp/project/jizai/mvsnet_input \ --model_path /root/autodl-tmp/project/pretrained/casmvsnet.ckpt \ --outdir /root/autodl-tmp/project/jizai/output \ --save_vis--save_vis表示输出深度图的可视化结果方便检查重建效果。如果你不想保存可视化去掉即可。5. 训练与推理全流程记录5.1 预训练权重准备与模型加载CasMVSNet_pl仓库通常会提供在DTU或BlendedMVS上预训练的权重。下载后的权重文件可能是.ckptPyTorch Lightning格式或.pthPyTorch格式。如果只有.pth文件但代码是用Lightning写的你可能需要手动构造模型后加载state_dict或者用脚本转换一下格式。我遇到过的一个小坑是训练时的输入图像尺寸和推理时不匹配导致特征图尺寸对不上。CasMVSNet内部会做多次降采样和反卷积如果输入图片不是32的整数倍最后可能会出现尺寸错位直接报错。所以我在推理前会统一把所有图片resize到合适的分辨率比如1600x1200或640x480然后在转换脚本里同步调整相机参数。5.2 训练的关键超参数与显存控制训练CasMVSNet最核心的超参数包括depth_interval、num_depth、batch_size和学习率。depth_interval是深度采样间隔这直接决定了深度估计的精度同时也决定了代价体的大小。num_depth越大代价体通道数越多显存占用越大。如果你在训练时OOM优先降低batch_size其次降低num_depth。下面是我在autodl上训练的一个经典配置python train.py \ --dataset general \ --data_root /root/autodl-tmp/project/blendedmvs \ --batch_size 4 \ --num_depth 48 \ --interval_scale 1.6 \ --lr 0.0001 \ --max_epochs 20batch_size设置要根据显卡显存来定。在RTX 3090上num_depth为48时batch_size可以设为4或6如果显存只有16GB建议把batch_size降到2。学习率建议用0.0001或0.001配合cosine退火效果比较稳定。5.3 在autodl上进行tensorboard监控训练过程中最好开启tensorboard便于监控loss和深度图质量。CasMVSNet_pl在训练完成后会自动在logs目录下生成event文件。在autodl上查看tensorboard有两种常用方式一种是在JupyterLab里直接打开一个终端运行tensorboard --logdir logs然后在浏览器里通过JupyterLab代理访问另一种是通过本地SSH端口转发。我常用第一种简单省事但注意要绑定合适的端口并在autodl的安全组里放行。6. 常见问题与排查技巧实录6.1 list of common errors and fixes报错或问题原因解决办法COLMAP mapper生成0个相机特征匹配数量太少或图片序列质量低增加图片数量调整特征提取阈值减小匹配距离比例colmap2mvsnet时报错找不到cameras.bin数据目录层级不对确认sparse/0目录下存在cameras.bin映射输出需经过mapper生成cams里depth range为0没有正确使用点云约束使用convert_format时添加--depth_range参数或后处理时设置min_depth/max_depthCUDA out of memorynum_depth/batch_size过大降低batch_size降低输入图像分辨率或改用更大显存的GPU推理输出的深度图全黑相机参数读取错误或数据归一化错误仔细检查cams txt中的内参矩阵是否与图片分辨率匹配确认深度范围是否覆盖场景真实深度VSCode连接autodl不稳网络波动使用SSH配置KeepAlive参数或改用autodl内置的SSH隧道重连6.2 深度估计异常值过滤技巧CasMVSNet输出的深度图偶尔会有一些异常像素尤其是在遮挡边界和低纹理区域。如果直接把所有点投影到三维空间会看到很多漂浮的噪点。我通常的经验是先做一遍深度一致性检查具体来说就是相邻视图之间的深度估计差超过某个阈值比如相对深度差5%就剔除该像素。此外还可以用COLMAP生成的稀疏点云作为空间约束把距离最近稀疏点太远的估计深度直接置为无效。在CasMVSNet代码里DepthMapFusion已经内置了一些滤波逻辑可以根据源码实现微调参数。个人建议在自定义数据上先保存深度图然后用点和网格处理软件比如MeshLab或Open3D进行后续去噪和重建这样比在代码里硬调滤波参数要直观得多。6.3 数据上传下载的走心建议autodl服务器和本地之间的数据传递可以使用scp命令或者autodl的文件管理器。我个人习惯用scp上传压缩包然后在服务器上解压比一个个文件传要快得多scp -P 端口 /本地路径/jizai.zip root地址:/root/autodl-tmp/project/上传之后在服务器上解压unzip jizai.zip要注意autodl的数据盘在关机后依然保留但如果你选择了无卡模式或释放实例数据可能会被清理。所以我在每次跑完重要实验后都会把生成的关键文件先打包下载到本地。虽然有一点麻烦但总比数据丢了重新跑一遍强。7. 后续扩展方向7.1 从深度图到完整点云与网格重建CasMVSNet输出的是一组深度图要得到完整的点云还需要做深度融合和点云融合。CasMVSNet官方提供了fusibile工具可以把所有视图的深度图融合成一个完整的点云。在autodl上编译fusibile也很简单克隆仓库后执行cmake和make即可。融合时需要传入相机参数、深度图路径和pair.txt深度一致性阈值建议设置在0.1到0.3之间。融合后的点云可以用Open3D做泊松重建得到封闭的网格模型。如果场景比较小可以直接导入MeshLab检查重建质量。走完整条链路之后你就能体会到从原始图像到三维模型的完整闭环有多爽。7.2 接入Codex与自动化实验最近VSCode里很流行用Codex这类AI辅助编程工具autodl也支持在VSCode中安装扩展并连接。我自己在调试CasMVSNet的代码时会让Codex帮忙写一些可视化脚本和参数扫描脚本实测下来能节省不少时间。比如自动批量修改num_depth、interval_scale这些参数把多组实验的指标或者可视化结果整理成表格再用脚本统一拷贝到输出目录。这种半自动化的实验管理思路特别适合需要跑大量消融实验的科研场景。不过要提醒一下使用Codex连接远程服务器时要确保本地和服务器都已经安装了对应的扩展或工具链并且在授权时仔细看权限范围不要让AI直接操作关键的数据删除或覆盖动作。把AI当辅助编码工具没问题但数据安全还得自己把关。7.3 BlendedMVS与DTU数据集迭代接入如果你的目标是训练一个泛化性更强的CasMVSNet模型建议在BlendedMVS上预训练然后在DTU上微调。这两个数据集都可以从网上下载但体积很大动辄几十GB。这时候你需要在autodl上用下载工具或直接wget下载并确保数据盘空间充足。数据集准备好后修改数据集类的读取路径就能无缝切换到训练流程。第一次跑训练前我建议先跑通一个batch确认数据读取、预处理和损失计算都没问题再开始完整训练循环这样可以少走很多弯路。7.4 基于稀疏视角的改进思路在实际项目中经常遇到图片很少的情况比如只有5到6张图而且视角跨度很大。CasMVSNet在这种情况下容易因为视角遮挡和匹配歧义导致深度估计质量下降。我当时做的一个改进是先利用COLMAP生成的稀疏点云约束深度搜索范围然后在网络训练时加入边缘感知的平滑损失让深度图在物体边界处更锐利。虽然不是所有数据集都有效但在自己采集的小规模场景上这个改动确实能提升重建完整度。如果你也面临类似问题可以尝试类似思路。做完了以上的事情最初的目标也就达成了一个阶段。我个人在实际操作中的体会是CasMVSNet和COLMAP这一套组合熟练之后真的能成为快速出模型、出场地效果的利器。跑通一次后面的实验就都是体力活了。真心建议大家拿到新数据时先用小分辨率跑通全流程确认相机参数、深度范围这些都合理了再上高分辨率精修这样可以省下大量因低级错误浪费的算力成本。