搞三维重建的朋友应该都绕不开 Colmap 这个开源神器,尤其是做运动恢复结构(SfM)、多视角立体视觉(MVS)或者给 NeRF、3D Gaussian Splatting 准备数据的时候,基本都要靠它。但这里有个很容易踩的坑:在 Ubuntu 22.04 上直接用 apt 安装的 Colmap,往往是 CPU 版本,特征提取、稠密重建这些环节跑起来简直慢到怀疑人生。所以很多人最后都要走一遍带 CUDA 支持的源码编译安装路线,这篇文章就针对“Ubuntu 22.04 + Colmap + CUDA 编译安装”这套组合,把全流程、显卡架构查询方法、以及我实际踩过的坑一次讲透。适合刚上手三维重建、被 CPU 版 Colmap 折磨过的同学,也适合需要在服务器上从头部署整套环境的开发者参考。
1. 编译前的整体思路与方案选型
1.1 为什么必须带 CUDA 编译 Colmap
先说结论:如果你只是处理几十张小图,CPU 版 Colmap 咬咬牙还能忍;一旦到了几百上千张图像的数据集,CPU 版和 GPU 版的差距就不是“快一点”而是“数量级碾压”。
原因在于 Colmap 内部几个核心模块都重度依赖 CUDA:
- 特征提取阶段,SIFT 特征检测的 GPU 实现比 CPU 实现快很多,尤其是在高分辨率图像上;
- 特征匹配阶段,暴力匹配和几何验证都有 CUDA kernel 加速;
- 稠密重建(Delaunay 三角化、像素级深度估计)更是 CUDA 的主场,CPU 版在这里基本属于灾难级别。
而 apt 仓库里的 Colmap 包,问题不只是没开启 CUDA,还在于版本往往滞后。Ubuntu 22.04 自带的 Colmap 是 3.7 左右的老版本,SfM 管线和一些接口跟现在的上游代码差了不少。所以无论从性能还是功能角度看,源码编译带 CUDA 的版本都是更稳的选择。
1.2 源码编译 vs 预编译包与容器方案
有人会问,直接拉 Docker 镜像不香吗?确实香,Colmap 官方提供了打包好的 Docker 镜像,开箱即用。但容器方案有两个痛点:
第一,GPU 透传环境如果没有提前配好 NVIDIA Container Toolkit,光是折腾--gpus all就够喝一壶;第二,做研究的时候经常需要改 Colmap 源码、加调试输出、或者链接自己修改过的第三方库,这时候容器镜像的封闭性就成了阻力。
源码编译看起来麻烦,实际上一套流程跑通之后,后续的二次开发、版本切换都会顺畅很多。而且源码编译可以针对你自己的显卡架构做代码生成优化,运行效率比通用预编译包还高一点。这篇文章走的是源码编译路线,目标很明确。
1.3 整体流程的编排逻辑
我习惯把整个编译安装拆成四个阶段,每阶段都有明确出口,方便排查问题:
- 系统环境准备:更新软件源、安装基础工具链(build-essential、git、cmake、ninja);
- CUDA 环境部署:确认显卡驱动正常、安装 CUDA Toolkit、配置环境变量;
- Colmap 依赖安装:把所有第三方库通过 apt 装齐;
- Colmap 源码编译:拉取源码、CMake 配置、编译、安装、验证。
为什么把 CUDA 环境放在依赖安装之前?因为 Colmap 的 CMake 配置阶段会同时检测 CUDA 和第三方库,如果 CUDA 没配好,后面检测到一堆红色警告,你会分不清到底是 CUDA 的问题还是库的问题。先搞定 CUDA,再装库,遇到问题定位起来就清楚多了。
2. 环境准备:基础工具链与 CUDA 部署
2.1 基础工具链安装
先说系统层面的准备。官方建议在干净系统上进行,但如果你已经装了一堆开发环境也没关系,只要注意别把系统自带的 Python 或者 CMake 搞坏就行。
打开终端,先更新软件源并升级:
sudo apt update && sudo apt upgrade -y然后安装编译必需的工具链:
sudo apt install -y build-essential git cmake ninja-build pkg-config这里重点说下构建工具的选择。Colmap 官方文档推荐用 Ninja 而不是 Make,原因是 Ninja 在增量编译时速度更快、并发控制也更合理。Ubuntu 22.04 自带的 CMake 是 3.22 版本,Colmap 要求的 CMake 最低版本是 3.16,所以系统自带的 CMake 完全够用,不需要额外折腾新版。
构建过程中我们还需要一些辅助工具,建议顺手装上:
sudo apt install -y ccache yasmccache 能缓存编译中间产物,如果你后面反复改 CMake 参数、重新编译,能省下不少时间,尤其是 Colmap 这种代码量级的项目,全量编译动辄十几分钟,ccache 的加速效果立竿见影。
2.2 CUDA Toolkit 安装方式对比
CUDA Toolkit 的安装方式主要有三种:deb网络安装、deb本地安装、runfile安装。我实测下来给个对比:
| 安装方式 | 优点 | 缺点 | 推荐指数 |
|---|---|---|---|
| deb 网络安装 | 依赖自动处理、升级方便 | 需要网络稳定,安装过程不可控 | 四星 |
| deb 本地安装 | 离线可用、依赖自动处理 | 包体积大,需要提前下载 | 三星半 |
| runfile 安装 | 路径完全可控、可自定义组件 | 不自动处理依赖,环境变量需要手动配 | 四星 |
如果你追求省心,直接走 deb 网络安装是最稳妥的。在 NVIDIA 官网选择对应系统架构和版本,会得到两条安装命令:
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb sudo dpkg -i cuda-keyring_1.1-1_all.deb sudo apt update sudo apt install -y cuda注意这个命令安装的是cuda这个 meta 包,会把所有 CUDA 组件都装上。如果你只想装 toolkit 而不需要额外的驱动或者文档,可以只装cuda-toolkit-12-3这种带版本号的包。
2.3 runfile 方式安装细节与 gzip 报错处理
虽然 deb 方式省心,但 runfile 方式在特定场景下更好用,比如你需要把 CUDA 装到非标准路径、或者想跳过 NVIDIA 驱动只装 Toolkit。Colmap 编译其实只需要 nvcc 编译器和 CUDA runtime 库,驱动你早就用nvidia-driver装好了,所以 runfile 的“跳过驱动”选项反而成了优势。
runfile 安装的关键步骤:
wget https://developer.download.nvidia.com/compute/cuda/12.3.0/local_installers/cuda_12.3.0_545.23.08_linux.run sudo sh cuda_12.3.0_545.23.08_linux.run执行后会出现一个文本交互界面,按Ctrl+C跳过协议阅读或者直接按q,然后选择你需要的组件。重点来了:如果你的驱动已经装好了,第一个选项[X] Driver记得把X取消掉,只保留 CUDA Toolkit 相关的组件。
这一步很多人会踩一个坑,下载的 runfile 大概率会报gzip: stdin: invalid compressed>export PATH=/usr/local/cuda/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
然后source ~/.bashrc,再执行nvcc --version就能看到 CUDA 版本信息了。
2.4 显卡驱动检查与常见版本匹配问题
在装 CUDA 之前,一定要确认你的 NVIDIA 驱动是正常的。执行:
nvidia-smi能看到显卡型号、驱动版本、以及右上角的 CUDA Version 就说明驱动没问题。注意这个 CUDA Version 表示当前驱动支持的最高 CUDA 版本,不代表你已经装了 CUDA Toolkit,两个概念很多人会混淆。驱动版本决定了你能装哪个版本的 CUDA Toolkit,例如驱动版本如果停留在 535,那 CUDA 12.2 及以下的 Toolkit 都兼容,高于这个版本的就需要先升级驱动。
如果你发现自己还没装 NVIDIA 驱动,最简单的安装方式是:
sudo apt install -y nvidia-driver-535 sudo rebootUbuntu 22.04 用nvidia-driver-535这个版本在我的多台机器上验证过,稳定性没问题。装完后建议用nvidia-smi验证一下 GPU 是否被正确识别。
对于 WSL2 用户,情况更简单,WSL2 里不需要在 Linux 侧装驱动,直接使用 Windows 宿主机的驱动即可。你只需要确认 Windows 端驱动是新的,然后在 WSL2 里正常安装 CUDA Toolkit 就行,Colmap 编译流程和原生 Ubuntu 没有任何区别。
3. 显卡架构查询:如何获取正确的 compute capability
3.1 CUDA 架构(算力)到底是个啥
CUDA 的“架构”全称是 Compute Capability,中文一般叫“计算能力”或者“算力”,用一个形如8.6、8.9的编号表示。这个编号很重要,因为它直接决定了编译出来的 GPU 代码能在哪些显卡上跑。
可以这么理解:CUDA 编译的产物不只是通用的机器码,还包含针对特定 GPU 架构的 SASS 指令。如果你的编译目标和实际显卡架构不匹配,程序运行时会报no kernel image is available的错误。
常见的显卡架构对应关系:
| 显卡系列 | 架构代号 | Compute Capability |
|---|---|---|
| RTX 4090 / 4080 / 4070 / 4060 | Ada Lovelace | 8.9 |
| RTX 3090 / 3080 / 3070 / 3060 | Ampere | 8.6 |
| A100 | Ampere | 8.0 |
| RTX 2080 Ti / 2070 / 2060 | Turing | 7.5 |
| GTX 1080 / 1070 / 1060 | Pascal | 6.1 |
| V100 | Volta | 7.0 |
| Tesla T4 | Turing | 7.5 |
拿 4060 Ti 来说,它属于 Ada Lovelace 架构,Compute Capability 是 8.9,对应 CUDA 版本需要 11.8 以上才支持。很多用 4060 Ti 的同学问“4060ti 支持哪个 CUDA 版本”,本质就是算力和 CUDA Toolkit 版本之间的兼容关系,后面详细讲。
3.2 查询显卡算力的三种方法
方法一,NVIDIA 官方的 CUDA GPU 支持列表。打开官网查对应型号就能看到 Compute Capability,这是最权威的途径,但页面比较长,找起来费时间。
方法二,写一个小程序跑deviceQuery。CUDA Toolkit 自带的 sample 里有现成的代码,不过为了查一个数字去编译 sample 有点小题大做。
方法三,直接看显卡型号对照表。这也是我平时最常用的方式,因为桌面级显卡的算力基本都是固定的,记住几组关键数据就行:20 系是 7.5,30 系是 8.6,40 系是 8.9。如果你拿不准,最保险的方法是在 CMake 配置时用native参数,让编译器自动检测当前显卡架构,这个我们在下一步详细说。
3.3 把算力告诉 Colmap 的正确姿势
Colmap 的 CMake 配置中,与显卡架构相关的变量是CMAKE_CUDA_ARCHITECTURES。这个变量在 CMake 3.18 之后被正式纳入标准,Colmap 的 CMake 脚本会读取它来决定 nvcc 编译时生成什么架构的代码。
最常见的三种写法:
# 写法一:自动检测当前显卡,最省心 -DCMAKE_CUDA_ARCHITECTURES=native # 写法二:指定具体算力,适合固定部署环境 -DCMAKE_CUDA_ARCHITECTURES=89 # 写法三:指定多个算力,生成的程序可在多款显卡上运行 -DCMAKE_CUDA_ARCHITECTURES=75;86;89native的缺点是它只针对当前编译机器上的显卡做优化,生成的程序拷贝到别的显卡上可能跑不了。如果你只是自己用,native简单粗暴完全没问题;如果是给实验室服务器编译,建议先查清楚服务器上是什么卡,直接用具体算力值设置。
关于多架构设置有个性能上的细节值得注意:生成的 SASS 代码会包含多份架构相关的二进制,程序体积更大,加载时间略长。所以如果不是要在不同显卡之间迁移,不建议设置太多架构,一个就够。
4. Colmap 源码编译实操全流程
4.1 第三方依赖安装,一个都不能少
Colmap 的依赖列表是你编译过程中第一个可能劝退你的地方,但说白了就是一次性把包装全。我在 Ubuntu 22.04 上实测有效的依赖安装命令如下:
sudo apt install -y \ libboost-all-dev \ libeigen3-dev \ libfreeimage-dev \ libgflags-dev \ libglew-dev \ libgoogle-glog-dev \ libgtk2.0-dev \ libjpeg-dev \ liblz4-dev \ liblzma-dev \ libpng-dev \ libqt5opengl5-dev \ libsqlite3-dev \ libtiff-dev \ libzstd-dev \ qtbase5-dev这些依赖里面有几个容易踩坑的点值得单独说:
第一,libboost-all-dev装的是 Boost 全量库,Colmap 主要用到 Boost 的filesystem、program_options、thread几个模块,装全量包虽然有点浪费磁盘,但能避免后续“找不到某个 Boost 组件”的诡异报错。
第二,libfreeimage-dev很关键。FreeImage 是 Colmap 图像读写的基础库,某些用 APT 方式装 Colmap 的发行版会漏掉这个依赖,导致编译出来的程序无法读取常见图片格式。如果 FreeImage 没装好,Colmap 运行时会出现Cannot read image的诡异问题。
第三,OpenCV 是另一个核心依赖。Ubuntu 22.04 的仓库里有 OpenCV 4.5.4,版本完全兼容 Colmap。如果你系统里已经通过源码方式装过 OpenCV,可能会遇到版本冲突,建议先卸载掉再看看 Colmap 能不能直接通过系统库编过去。
如果你需要用到 Ceres Solver(做 bundle adjustment 优化的核心库),可以额外安装:
sudo apt install -y libceres-dev装 Ceres 的好处是让 Colmap 的输出 BA 结果更准确。如果你的数据集质量一般、或者图像匹配成功率不稳定,建议装上。
4.2 源码克隆与版本选择策略
依赖齐了之后,就可以拉源码了。Colmap 的 GitHub 仓库在https://github.com/colmap/colmap,直接克隆主干仓库:
git clone https://github.com/colmap/colmap.git cd colmap这里有个版本选择的问题。Colmap 的开发节奏比较快,主干分支(main)随时可能引入新特性或者破坏性变更。如果你需要一个稳定的编译环境,建议切换到最新的 Release tag 而不是直接用 main:
git checkout 3.10我在编译时发现,3.9 和 3.10 版本对 CUDA 12.x 的兼容性都很好,3.8 及以下版本在 CUDA 12 环境下需要额外处理一些头文件兼容问题。如果你用的 CUDA 版本是 12.x,强烈建议直接用 3.9 以上的版本。
如果你的网络环境访问 GitHub 不稳定,可以先用 git 把仓库下载下来,或者找一台网络状况好的机器打包传输。不要在这个过程中频繁切换源,容易造成仓库状态混乱。
4.3 CMake 配置阶段:参数详解与验证
编译配置是全文最重要的环节,这里我把每一步拆开讲清楚。
首先在 Colmap 源码根目录创建 build 目录:
mkdir build && cd build然后执行 CMake 配置命令:
cmake .. -GNinja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CUDA_ARCHITECTURES=native \ -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc解析一下这几个参数:
-GNinja:指定用 Ninja 构建系统,好处是并行编译效率高,报错信息比 Make 更友好;-DCMAKE_BUILD_TYPE=Release:编译优化模式,开启 O3 优化。如果是调试 Colmap 源码,可以改成 Debug,但运行性能会差不少;-DCMAKE_CUDA_ARCHITECTURES=native:自动检测当前显卡架构,让 nvcc 生成适配你显卡的代码;-DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc:显式指定 CUDA 编译器。多 CUDA 版本共存时,这一步可以避免 CMake 找到错误的 nvcc。
还有一个参数值得关注:
-DCMAKE_CUDA_FLAGS="-O3 --use_fast_math"--use_fast_math可以让部分数学函数用近似算法代替精确算法,换来性能提升。默认情况下不推荐开启,因为会损失数值精度;如果你处理的图像数据量大、对精度要求又不是特别苛刻,可以考虑开启。
配置完成后,检查输出信息里有没有警告。重点关注两行内容:一行是Found CUDA,说明 CUDA 被成功识别;另一行是CUDA_SIFT_GPU_FOUND或者类似的特征提取相关打印,如果这里显示 NOT FOUND,说明即使编译成功,SIFT 特征提取也还是 CPU 版本,就失去带 CUDA 编译的意义了。
还有一个常见问题:如果你只装了 CUDA Toolkit 但没有/usr/local/cuda/bin/nvcc这个路径,说明环境变量没生效或者 CUDA 不是通过默认路径安装的。可以先执行which nvcc看看实际路径,然后把 CMake 里的参数改成实际路径。
4.4 编译、安装与验证
CMake 配置顺利完成之后,编译阶段相对省心。执行:
ninja -j$(nproc)-j$(nproc)会让 Ninja 使用所有 CPU 核心进行并行编译。但这里有个经验之谈:如果你的内存小于 16GB,建议把线程数减半,否则编译过程中多个编译任务同时跑,内存会爆掉。
编译完成后安装到系统环境:
sudo ninja install安装完毕后,先在终端里验证一下:
colmap -h如果输出正常的帮助信息,说明安装成功。但“安装成功”不等于“CUDA 版本工作正常”,我还建议跑一次真实的特征提取验证 GPU 是否被真正调用:
colmap feature_extractor --database_path test.db --image_path /path/to/your/images --SiftExtraction.use_gpu 1注意观察日志输出,如果 CUDA 正常,日志里会显示 GPU 设备信息和 SIFT GPU 相关的字样。如果日志里出现 CPU 的提示,说明编译时 CUDA 相关模块没有被正确启用。
5. 高频报错与排查思路
5.1 CUDA 安装环节的报错记录
报错一: 报错一:CMake 找不到 CUDA 如果 CMake 配置时输出 报错二: 配置时会看到类似 报错三:编译过程中内存不足(Killed) Ninja 并行编译时内存打满导致进程被系统杀掉,这在 8GB 内存的机器上非常常见。解决方法是限制编译并行度: 或者更极端一点,用 报错四: 运行 colmap 或者 GUI 界面时偶尔会遇到这个报错,常见于 headless 服务器环境。解决方法是安装 OpenGL 库的 32/64 位版本: 很多人编译完就默认 CUDA 生效了,其实不一定。除了上面提过的 如果看到 我个人还有个习惯,编译完会跑一个小的 benchmark,用同样的数据集对比 CPU 版和 GPU 版的运行时间。差距如果只有 10%~20%,那大概率某个环节没生效,正常情况应该有数倍乃至一个数量级的差距。 另外还有一个细节,Colmap 运行时的 SIFT 特征提取 GPU 开关是gzip: stdin: invalid compressed>export CC=/usr/bin/gcc-11 export CXX=/usr/bin/g++-115.2 Colmap 编译阶段的报错记录
Could NOT find CUDA,先确认nvcc --version能否正常执行。能正常执行但 CMake 找不到,大概率是你 CMake 版本太旧,不认/usr/local/cuda这个软链接。升级 CMake 到 3.22 以上基本能解决。CMAKE_CUDA_ARCHITECTURES相关的 warningManually-specified variables were not used by the project的警告,这通常是 CMake 变量名拼写错误或者该项目不识别该变量。Colmap 3.10 对CMAKE_CUDA_ARCHITECTURES的支持已经完善,如果你仍然看到相关变量被忽略的提示,检查版本是不是太旧。ninja -j4-j2。另外一个思路是增加 swap 空间,虽然编译速度会打折扣,但至少不会中途失败:sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfilelibGL.so.1: cannot open shared object filesudo apt install -y libgl1-mesa-dev libgl1-mesa-glx5.3 运行阶段如何确认 CUDA 真在干活
feature_extractor日志验证法,还有一个更直接的检查方式,在运行 Colmap 的任务时,另开一个终端执行:nvidia-smicolmap进程占用了 GPU 显存而且 GPU-Util 有百分比波动,说明 CUDA 确实在起作用。如果 GPU-Util 一直是 0%,哪怕程序能跑,也说明你的编译配置有问题,回到 CMake 配置环节检查 CUDA 相关的选项。--SiftExtraction.use_gpu 1,匹配阶段的开关是--SiftMatching.use_gpu 1。如果你使用的 Colmap 前端工具(比如某些基于 Python 封装的库)默认没开这两个选项,那即使编译了 CUDA 版,实际跑的还是 CPU。这也是我见过不少人“编译时带 CUDA 了但还是很慢”的根本原因。