1. 为什么要在Windows上死磕COLMAP 3.6的源码编译
如果你接触过三维重建,大概率听说过COLMAP这个名字。它是一套开源的运动恢复结构(Structure-from-Motion)与多视图立体(Multi-View Stereo)流水线工具,在学术界和工业界都被广泛用于从一组照片中恢复相机位姿并生成稠密点云。官方发布的Windows预编译包虽然开箱即用,但版本往往滞后,而且默认不带某些依赖库的完整功能。当你需要用到特定版本的算法、想开启CUDA加速的某些特性,或者要把COLMAP嵌入自己的C++项目时,从源码编译就成了绕不开的一步。
标题里提到的“colmap3.6”指的是COLMAP的一个较早期但非常稳定的版本分支,很多经典论文的复现实验都基于这个版本。“gmp”和“mfpr”则是两个关键的数学库:GMP是大数运算库,MFPR是它的一个高性能分支,在COLMAP的某些几何计算模块中会被间接依赖。在Windows下编译这三个东西,难点不在于代码本身,而在于Windows与Unix-like系统在构建工具链、依赖管理和路径处理上的巨大差异。我前后折腾过好几轮,踩过的坑包括但不限于:CMake找不到Boost、CUDA架构不匹配导致编译中断、GMP在MSVC下链接报错、以及最让人头疼的第三方库版本冲突。
这篇文章面向的是有一定C++基础、用过CMake、但可能在Windows上编译大型开源项目经验不多的开发者。我会把整个流程拆成可复现的步骤,解释每一步为什么要这么做,以及遇到报错时怎么排查。你不需要事先精通GMP或MFPR,但需要有一台装了Visual Studio和CUDA的Windows机器,以及足够的耐心。
2. 编译前的环境准备与工具链选型
2.1 编译器与构建工具的选择逻辑
在Windows上编译COLMAP,第一件事就是确定用哪套编译器。官方文档推荐的是Visual Studio 2019或2022的MSVC工具链,原因很直接:COLMAP的Windows分支对MSVC的支持最完善,CMake脚本里针对MSVC做了大量条件判断。如果你试图用MinGW或Cygwin,大概率会在链接阶段遇到符号不兼容的问题,尤其是涉及CUDA的模块。
我实测下来,Visual Studio 2022 Community版就够用,安装时务必勾选“使用C++的桌面开发”工作负载,并且确保Windows SDK版本在10.0.19041以上。CMake建议用3.20以上的版本,因为COLMAP 3.6的CMakeLists.txt里用到了target_link_libraries的一些较新语法。CMake安装时记得勾选“Add CMake to the system PATH”,否则后面在命令行里调用会很麻烦。
注意:不要用Visual Studio自带的CMake集成来构建COLMAP,它的缓存机制有时会干扰第三方依赖的查找。老老实实用命令行或者CMake GUI。
2.2 CUDA与cuDNN的版本匹配
COLMAP的稠密重建模块依赖CUDA。如果你不需要GPU加速,可以在CMake里关掉CUDA,但那样就失去了COLMAP最大的性能优势。CUDA版本的选择要和你的显卡驱动、以及Visual Studio版本匹配。我用的组合是CUDA 11.8加VS2022,这个组合在COLMAP 3.6上验证通过。CUDA 12.x理论上也可以,但需要确认COLMAP 3.6的CMake脚本是否识别新的架构代号。
安装CUDA时,建议自定义安装,取消掉GeForce Experience和驱动组件,只保留CUDA Toolkit和开发头文件。cuDNN不是必须的,COLMAP的稠密重建用的是自己实现的PatchMatch算法,不直接调用cuDNN。但如果你后续要接深度学习模块,可以提前装好。
2.3 依赖库清单与获取方式
COLMAP 3.6在Windows上编译需要以下第三方库:
| 依赖库 | 用途 | 推荐版本 | 获取方式 |
|---|---|---|---|
| Boost | 文件系统、线程、程序选项 | 1.74-1.82 | 源码编译或预编译包 |
| Eigen | 线性代数 | 3.3.9以上 | 头文件库,直接解压 |
| FreeImage | 图像读写 | 3.18 | 源码编译 |
| GMP/MFPR | 大数运算 | MFPR 4.1.0 | 源码编译 |
| Ceres Solver | 非线性优化 | 2.0以上 | 源码编译 |
| Qt5 | GUI | 5.15 | 官方安装包 |
| glew | OpenGL扩展 | 2.1 | 源码编译 |
| CGAL | 计算几何 | 5.0以上 | 头文件为主 |
这里最麻烦的是Boost、Ceres和GMP/MFPR。Boost和Ceres可以用vcpkg来装,但vcpkg的Boost版本更新太快,有时会和COLMAP 3.6的代码不兼容。我的建议是:Boost用预编译的二进制包,Ceres用源码编译并指定Eigen路径,GMP/MFPR必须从源码编译,因为Windows上没有现成的MSVC版本。
3. GMP与MFPR在MSVC下的编译实操
3.1 为什么COLMAP需要GMP和MFPR
GMP是GNU多精度运算库,MFPR是它的一个分支,专注于更高效的浮点运算。COLMAP在计算相机位姿的某些几何约束时,会用到高精度的有理数运算,尤其是在处理大规模稀疏矩阵的分解时。虽然COLMAP的核心代码没有直接调用GMP的API,但它依赖的Ceres Solver在启用某些选项时会链接GMP。而MFPR则是GMP的一个替代实现,在某些场景下性能更好。
在Linux下,这两个库通常通过包管理器一键安装。但在Windows下,MSVC不提供POSIX环境,GMP的源码里大量使用了Unix特有的头文件和汇编代码,直接编译会报错。所以我们需要用MFPR来替代GMP,因为MFPR对MSVC的支持更友好。
3.2 编译MFPR的详细步骤
首先从MFPR的官方仓库下载源码包,解压到一个没有空格和中文的路径,比如D:\libs\mfpr-4.1.0。然后打开“x64 Native Tools Command Prompt for VS 2022”,cd到源码目录。
MFPR的编译需要先运行一个配置脚本。在Windows下,我们用CMake来生成Visual Studio工程:
mkdir build cd build cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_INSTALL_PREFIX=D:\libs\mfpr-install -DENABLE_ASSERT=OFF -DWITH_PIC=ON这里解释几个关键参数:-G指定生成器,-A x64确保是64位,-DCMAKE_INSTALL_PREFIX指定安装路径,-DENABLE_ASSERT=OFF关闭断言以提升性能,-DWITH_PIC=ON生成位置无关代码,虽然Windows下DLL不需要PIC,但某些静态链接场景会用到。
CMake配置完成后,用以下命令编译并安装:
cmake --build . --config Release --target install如果一切顺利,你会在D:\libs\mfpr-install下看到include、lib和bin三个目录。lib目录里会有mfpr.lib和mfpr.dll(或者只有静态库,取决于配置)。
实操心得:MFPR的CMake脚本在检测编译器时,有时会把MSVC误判为其他编译器,导致生成错误的汇编代码。如果编译过程中出现大量汇编错误,检查
CMakeCache.txt里的CMAKE_C_COMPILER是否指向cl.exe。如果不是,手动指定-DCMAKE_C_COMPILER=cl。
3.3 解决链接时的符号冲突
编译完MFPR后,你可能会在链接COLMAP时遇到“无法解析的外部符号”错误,提示缺少__gmpz_开头的函数。这是因为COLMAP的某些依赖(比如Ceres)默认去找GMP而不是MFPR。解决方法是在CMake配置COLMAP时,显式指定GMP的路径指向MFPR的安装目录:
-DGMP_INCLUDE_DIR=D:\libs\mfpr-install\include -DGMP_LIBRARY=D:\libs\mfpr-install\lib\mfpr.lib如果Ceres已经编译好了并且链接了系统里的其他GMP版本,你可能需要重新编译Ceres,并在编译时传入同样的GMP路径。这就是为什么我建议把Ceres放在MFPR之后编译。
4. COLMAP 3.6的CMake配置与编译过程
4.1 获取源码与目录结构梳理
从COLMAP的官方仓库下载3.6版本的源码压缩包,解压到D:\projects\colmap-3.6。目录结构大致如下:src下是核心代码,cmake下是FindXXX模块,lib下是第三方库的占位。COLMAP 3.6的CMake脚本会尝试自动下载一些依赖,但在国内网络环境下经常失败,所以最好提前把所有依赖准备好,然后通过CMake变量指定路径。
4.2 关键CMake变量的设置与解释
打开CMake GUI,设置源码路径为D:/projects/colmap-3.6,构建路径为D:/projects/colmap-3.6/build。点击Configure,选择Visual Studio 17 2022和x64。第一次Configure会报错,提示找不到Boost、Eigen等。这时候需要手动添加以下变量:
| 变量名 | 值 | 说明 |
|---|---|---|
| BOOST_ROOT | D:/libs/boost_1_82_0 | Boost根目录 |
| Eigen3_DIR | D:/libs/eigen-3.4.0/share/eigen3/cmake | Eigen的CMake配置目录 |
| FreeImage_DIR | D:/libs/FreeImage/build | FreeImage的构建目录 |
| GMP_INCLUDE_DIR | D:/libs/mfpr-install/include | MFPR头文件 |
| GMP_LIBRARY | D:/libs/mfpr-install/lib/mfpr.lib | MFPR库文件 |
| CERES_DIR | D:/libs/ceres-solver/build | Ceres构建目录 |
| Qt5_DIR | D:/Qt/5.15.2/msvc2019_64/lib/cmake/Qt5 | Qt5配置目录 |
| CUDA_TOOLKIT_ROOT_DIR | C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.8 | CUDA路径 |
| CMAKE_CUDA_ARCHITECTURES | 75;86 | 根据你的显卡调整 |
CMAKE_CUDA_ARCHITECTURES这个变量特别重要。如果你用的是RTX 30系显卡,架构是86;20系是75;40系是89。填错了会导致编译出的CUDA内核无法在显卡上运行,运行时直接报“no kernel image is available”。
4.3 编译过程中的常见报错与即时处理
点击Generate后,如果一切正常,会在build目录下生成COLMAP.sln。用Visual Studio打开这个解决方案,选择Release配置,然后“生成解决方案”。这个过程可能持续30分钟到2小时,取决于机器性能。
常见的报错及处理方式:
- 错误C2039:某个成员不是XXX的成员。这通常是Boost版本不兼容导致的。COLMAP 3.6的代码基于Boost 1.74左右的API,如果你用了Boost 1.85,某些接口已经废弃。降级Boost或者手动修改代码。
- 错误LNK2019:无法解析的外部符号。检查是否所有依赖库的路径都正确,尤其是GMP和Ceres。有时候需要把
mfpr.lib和ceres.lib的目录加到链接器的“附加库目录”里。 - CUDA编译错误:identifier "atomicAdd" is undefined。这是CUDA版本和MSVC版本不匹配的典型症状。CUDA 11.8配VS2022需要打一个补丁,或者把CUDA升级到12.x。
注意:编译过程中如果某个模块失败,不要急着重新生成整个解决方案。先单独编译那个失败的项目,看具体错误信息。Visual Studio的错误列表有时会隐藏真正的根因。
5. 编译后的验证与功能测试
5.1 检查生成的可执行文件
编译成功后,在build/src/Release目录下会生成colmap.exe、colmap_gui.exe等可执行文件。先别急着跑,用dumpbin /dependents colmap.exe检查一下依赖的DLL是否都在。如果提示缺少mfpr.dll,把D:\libs\mfpr-install\bin加到系统PATH里,或者直接把DLL复制到exe旁边。
5.2 用示例数据集跑通完整流程
COLMAP官方提供了一些示例数据集,比如南门大桥的图片集。下载后,用命令行跑一遍稀疏重建:
colmap feature_extractor --database_path test.db --image_path images colmap exhaustive_matcher --database_path test.db colmap mapper --database_path test.db --image_path images --output_path sparse如果这三步都能跑通,并且在sparse目录下生成了.bin文件,说明核心功能没问题。然后测试稠密重建:
colmap image_undistorter --image_path images --input_path sparse/0 --output_path dense colmap patch_match_stereo --workspace_path dense colmap stereo_fusion --workspace_path dense --output_path dense/fused.ply这一步会调用CUDA,如果显卡架构设置正确,应该能看到GPU利用率飙升。如果报错“CUDA error: no kernel image is available”,回去检查CMAKE_CUDA_ARCHITECTURES。
5.3 GUI功能的可用性确认
双击colmap_gui.exe,如果能正常打开界面并加载图片,说明Qt的链接没问题。GUI里可以手动做特征提取和匹配,适合调试小规模数据。如果GUI启动时报“找不到Qt5Core.dll”,把Qt的bin目录加到PATH,或者用windeployqt工具把依赖DLL复制过来。
6. 踩坑记录与常见问题速查
6.1 依赖库版本冲突的排查思路
Windows下编译开源项目最大的痛点就是依赖库版本冲突。我的经验是:把所有依赖库的版本号记在一个文本文件里,每次编译失败先对照版本。COLMAP 3.6对Boost的版本特别敏感,1.74到1.78之间最稳。Eigen用3.3.9或3.4.0都行,但不要用3.4.1,那个版本改了一些API导致COLMAP编译不过。
Ceres的版本建议用2.0.0或2.1.0,2.2.0改了Manifold的接口,COLMAP 3.6的代码还没适配。如果你非要用新版本Ceres,需要手动改COLMAP的src/colmap/estimators下的几个文件。
6.2 CUDA架构不匹配的典型症状
CUDA架构不匹配的表现有三种:编译时通过但运行时崩溃、编译时直接报错、或者编译出的程序在特定显卡上性能极低。最隐蔽的是第三种,程序能跑但慢得离谱,因为CUDA用了JIT编译。解决方法是在CMake里把CMAKE_CUDA_ARCHITECTURES设成你显卡的计算能力值,不要用默认的“Auto”。
6.3 内存不足与编译中断的应对
COLMAP的某些源文件(比如src/colmap/mvs下的)非常大,MSVC编译时可能吃掉8GB以上内存。如果你的机器只有16GB内存,建议关掉其他程序,或者用/MP选项开启多核编译但限制并行项目数。在Visual Studio里,工具→选项→项目和解决方案→生成并运行,把“最大并行项目生成数”设为2或3。
如果编译到一半因为内存不足中断,重新生成时可能会报“无法打开XXX.obj”的错误。这时候清理一下build目录里的中间文件,或者直接删掉build重新来。
6.4 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| CMake找不到Boost | BOOST_ROOT未设置或路径错误 | 设置BOOST_ROOT为Boost根目录 |
| 链接报错缺少gmpz符号 | GMP路径指向了错误的库 | 重新指定GMP_LIBRARY为mfpr.lib |
| CUDA编译报atomicAdd未定义 | CUDA与MSVC版本不匹配 | 升级CUDA或打VS补丁 |
| 运行时提示no kernel image | CUDA架构设置错误 | 修改CMAKE_CUDA_ARCHITECTURES |
| GUI启动缺少Qt5Core.dll | Qt的bin目录不在PATH | 添加PATH或用windeployqt |
| 编译到一半内存不足 | 单个源文件过大 | 减少并行项目数或增加虚拟内存 |
最后再分享一个小技巧:如果你只是想在Windows上用COLMAP做重建,不想折腾编译,可以考虑用WSL2装Ubuntu,然后在里面用apt装COLMAP。但如果你需要修改源码或者做二次开发,Windows原生编译仍然是更好的选择,因为调试器可以直接附加到进程上。我个人的体会是,第一次编译花了两天,第二次只用了两小时,关键是把依赖库的版本和路径都固定下来,写成一个CMake脚本,以后换机器直接复用。