ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenMVS源码编译避坑指南:依赖选型与CMake配置全解析

OpenMVS源码编译避坑指南:依赖选型与CMake配置全解析 1. 为什么说OpenMVS源码编译最大的坑不是源码而是依赖环境OpenMVS这个名字做三维重建的人应该都不陌生。它是目前开源社区里效果最完整的多视角稠密重建管线之一输入一组照片输出稠密点云、网格模型还能帮你做纹理映射一条流水线全包了。很多人在网上看到它的效果图兴冲冲clone了仓库然后卡在了编译这一步。我最初编译OpenMVS的时候也犯过同样的错误——以为重点在源码本身。真正动手之后才发现OpenMVS的代码结构其实很清爽CMakeLists写得也算规矩真正折磨人的是它那一大串外部依赖Eigen、OpenCV、Boost、Ceres Solver、CGAL还有可选的CUDA。这些库各自有版本要求版本之间又互相牵制稍有不慎就给你编出一堆莫名其妙的链接错误。这篇文章我就把整个OpenMVS源码编译的完整过程拆开讲一遍。从依赖选型、CMake配置、分平台编译实操到常见的报错排查链路全部走一遍。无论你是Windows用户还是Linux/macOS用户只要照着这一篇走都能少踩几个坑。先说一个总体的认识OpenMVS本身的编译说白了就是一个标准的CMake项目——cmake生成构建文件然后make或者MSBuild编译。难点全在依赖库的版本匹配和查找路径上。理解了这个定位后面遇到问题就知道往哪个方向排查了。2. 动手之前先理清依赖库的版本选型策略这里我先说结论OpenMVS对依赖库的版本要求从来都不是“越新越好”。很多人编译失败就是因为用了太新的OpenCV或者太新的CGAL结果跟OpenMVS源码里的接口对不上。2.1 核心依赖清单与版本建议OpenMVS源码里有一个README.md里面会列出推荐的依赖版本。但这些版本信息更新得不算勤快实际操作时你需要结合系统环境自己判断。我梳理过一套在不同平台上都比较稳的版本组合列在下面这张表里依赖库建议版本作用注意事项Eigen3.4.x线性代数基础库头文件库不需要编译但路径必须指对OpenCV3.4.x或4.5.x图像读写、特征提取版本差异可能带来API兼容问题4.x需要关注cv::命名空间变化Boost1.65~1.83文件系统、线程、program_options版本过老过新都可能触发编译错误Ceres Solver2.0.x或2.1.x非线性最小二乘优化BA核心依赖Eigen和glog版本不能太老CGAL5.4.x或5.5.x计算几何算法新版CGAL要求C17注意编译标准一致VCGLib源码内置网格处理基础库OpenMVS源码自带的vcglib子模块无需单独装CUDA可选11.x或12.xGPU加速稠密重建不装也能编但速度会差很多2.2 版本之间的隐藏兼容链条这几条版本之间是有连锁关系的我建议你按这个逻辑来选而不是一个个独立选Cerès和Eigen是强绑定关系。Ceres编译时会检查Eigen版本太新的Eigen可能触发Ceres的EIGEN_VERSION判断报错。稳妥做法是选了Ceres 2.1.x就配Eigen 3.4.x不要动辄去试Eigen 3.8的实验分支。CGAL决定C标准。CGAL 5.5之后的版本基本默认要求C17OpenMVS本身的代码也要用-DCMAKE_CXX_STANDARD17来对齐否则编译时到处报std::filesystem找不到之类的错。Boost版本跟OpenCV也有联动。如果你用vcpkg或Homebrew统一管理依赖务必保证它们用的是同一套编译工具链和运行时。混用MSVC的Debug/Release库是Windows下最常见的一类问题。2.3 我的选型建议如果你不想纠结直接照抄我这套经过验证的组合Eigen 3.4.0 OpenCV 4.5.5 Boost 1.76 Ceres Solver 2.0.0 CGAL 5.4.4这套组合在Ubuntu 20.04、CentOS 7以及Windows 10/11的VS2019/VS2022下我都试过编译链路是通的。如果你坚持用更高版本大概率会踩到某个接口改动到时候排查的成本远高于你省下的那点编译时间。提示OpenMVS的vcglib子模块是编译必需的。clone的时候记得用--recursive参数否则后面CMake配置的时候会报找不到vcglib目录。这个参数很多人第一次都会忘。3. CMake配置的完整逻辑每个开关背后是什么依赖装齐了接下来就是CMake配置。这一环节的常见误区是“照着网上的命令抄一遍”。抄能跑通自然好但一旦报错就容易抓瞎。我建议你先把OpenMVS的CMakeLists打开扫一遍看清楚里面到底有哪些开关每个开关对应什么作用。3.1 OpenMVS的CMake选项全解析OpenMVS的CMakeLists里对外暴露的主要选项有这几个-DCMAKE_BUILD_TYPERelease # 构建类型不要用Debug性能和链接行为差别很大 -DMVS_DIR... # OpenMVS源码根目录一般多指生成时项目文件所在路径 -DMVS_USE_CUDAON/OFF # 是否启用CUDA加速有N卡建议ON -DMVS_USE_OPENMPON/OFF # 多核CPU并行默认ON -DMVS_USE_CGALON/OFF # 是否启用CGAL相关功能建议ON -DMVS_USE_BOOSTON/OFF # Boost默认ON -DMVS_USE_OPENCVON/OFF # OpenCV默认ON -DMVS_USE_CERESON/OFF # Ceres默认ON -CUDA_TOOLKIT_ROOT_DIR... # CUDA安装路径Windows下经常要手动指定 -CUDA_GENERATION... # 根据显卡架构指定如Kepler/Pascal等 -OpenCV_DIR... # OpenCV的CMake配置目录 -CGAL_DIR... # CGAL的CMake配置目录3.2 最重要的两个路径变量MVS_DIR 和 MVS_DEPS_DIR在OpenMVS的CMake逻辑里厂商实际上希望你把外部依赖统一放在一个目录下然后通过MVS_DIR和MVS_DEPS_DIR联合指引。不过我在实际使用中发现大多数人直接用系统级别的包管理安装依赖这种情况下更省事的方式是让CMake自动通过find_package去寻找而不必刻意创建依赖目录。关键是你得确保CMake能找到这些包的配置文件。以Windows为例CMake会去注册表、环境变量和常用路径里搜索*Config.cmake。如果找不到一款非常典型的情况是CMake Error at CMakeLists.txt:65 (find_package): By not providing FindOpenCV.cmake in CMAKE_MODULE_PATH this project asked CMake to find a package configuration file provided by OpenCV, but CMake did not find one.这种报错的本质是OpenCV_DIR没指对。OpenCV安装后会生成一个OpenCVConfig.cmake在Windows上通常位于opencv/build/x64/vc15/lib取决于版本把这个路径通过-DOpenCV_DIR传给CMake报错就没了。同样的逻辑适用于CGAL_DIR、Ceres_DIR。3.3 我推荐的CMake配置命令以Linux为例假设依赖全部装在系统路径里cd OpenMVS mkdir -p build cd build cmake .. \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_CXX_STANDARD17 \ -DMVS_USE_CUDAON \ -DCUDA_TOOLKIT_ROOT_DIR/usr/local/cuda \ -DCUDA_GENERATIONPascal \ -DOpenCV_DIR/usr/lib/x86_64-linux-gnu/cmake/opencv4 \ -DCGAL_DIR/usr/lib/x86_64-linux-gnu/cmake/CGAL \ -DCeres_DIR/usr/local/lib/cmake/Ceres注意-DCMAKE_CXX_STANDARD17这一步。如果你的CGAL是5.5以上版本这一步缺了就等着编译报错吧。Windows下用CMake GUI更直观填完路径选项后点ConfigureVS版本选对再点Generate然后打开生成的.sln文件编译。整个过程里最容易出问题的是VS版本和库的编译工具链不一致。换句话说依赖库是MSVC 2019编译的你却用VS2022的生成器去编OpenMVS链接时就容易出奇葩错误。统一工具链是Windows编译的理想要素。4. 分平台编译实操Windows、Linux、macOS各自要注意什么授人以鱼不如授人以渔。我把三个主流平台的完整编译路径分别走一遍你在哪个平台就对照看哪一段。4.1 Windows MSVCvcpkg是省力通道但也有限制Windows下编译OpenMVS我强烈建议直接用vcpkg装依赖。理由很简单手动从源码编译OpenCVBoostCeresCGAL光Boost就能让你折腾一下午。vcpkg可以有一条命令搞定整套依赖。先安装vcpkg并集成到Visual Studiogit clone https://github.com/microsoft/vcpkg.git cd vcpkg .\bootstrap-vcpkg.bat .\vcpkg integrate install然后安装OpenMVS需要的库这一条会去下载编译时间比较长.\vcpkg install opencv4[core,contrib,nonfree] boost-system boost-filesystem boost-program-options eigen3 ceres-solver cgal --triplet x64-windows装完之后在CMake GUI配置时vcpkg会自动被integrate install注册到系统里CMake能找到vcpkg的包。但是有一个容易忽略的地方vcpkg默认会装一个最新版OpenCV而OpenMVS对OpenCV的某些旧接口还有依赖。如果遇到接口匹配问题你需要指定安装历史版本.\vcpkg install opencv4[core]4.5.5接着CMake配置时再补充一条-DCMAKE_TOOLCHAIN_FILE[vcpkg路径]/scripts/buildsystems/vcpkg.cmake用vcpkg编译的好处是依赖之间的关系vcpkg会帮你协调好省心。坏处是第一次安装这些库要花很长时间而且vcpkg编译过程中如果中途断了重来一遍非常痛苦。我试过在内存只有8G的机器上编Boost直接被编译器内存不足干崩好几次。建议把/MP参数加上VS的多核编译同时保证硬盘有10G以上的空余。Windows下还有一个高频坑OpenMVS的三方库中OpenCV的world模式把所有模块编进一个lib和默认模式生成的lib命名不一样。如果你在链接时报LNK2019 unresolved external symbol八成是OpenCV模块没对上去检查链接库里是不是缺少对应的opencv_xxx4.lib文件。4.2 Linuxapt安装为主Ceres建议源码编译Linux是OpenMVS最友好的平台。Ubuntu/Debian下大部分依赖直接用apt装sudo apt install libeigen3-dev libopencv-dev libboost-all-dev libcgal-dev libceres-dev libgflags-dev libgoogle-glog-dev libsuitesparse-dev这里有一个需要注意的细节apt里的libceres-dev往往版本偏老。比如Ubuntu 20.04自带的是Ceres 1.14而OpenMVS的某些功能模块需要Ceres 2.0以上的接口。如果你不打算用OpenMVS里的全部功能老版本Ceres也能凑合编过但如果你要跑BABundle Adjustment相关的完整管线我建议源码编译一份Ceres 2.1.x装到系统里再回来编OpenMVS。Ceres源码编译很简单git clone https://github.com/ceres-solver/ceres-solver.git cd ceres-solver mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease make -j$(nproc) sudo make install装完Ceres后记得确认一下CMake能找到它ls /usr/local/lib/cmake/Ceres如果能列出CeresConfig.cmake说明CMake路径没问题。Linux编译OpenMVS的另一个隐藏问题是OpenMP和CUDA的配合。如果你在CMake里同时开了-DMVS_USE_OPENMPON和-DMVS_USE_CUDAON在部分老版显卡驱动上会出现运行时冲突表现是程序一启动就直接段错误。遇到这种情况可以先关掉OpenMP试试大多数场景下GPU已经够快CPU并行是锦上添花。4.3 macOSHomebrew是好帮手但OpenMP要手动装macOS下的OpenMVS编译依赖基本靠Homebrew搞定brew install eigen opencv boost ceres-solver cgal但有一个macOS特有的坑Homebrew默认的clang编译器在Apple Silicon机器上不一定自带OpenMP支持。如果你编译时开了-DMVS_USE_OPENMPON很可能会看到一个奇怪的报错fatal error: omp.h file not found这个报错的意思是系统找不到omp.h头文件。解决办法是手动安装libompbrew install libomp然后在CMake时指定一下cmake .. -DOpenMP_CXX_FLAGS-Xpreprocessor -fopenmp -DOpenMP_CXX_LIB_NAMESomp -DOpenMP_omp_LIBRARY$(brew --prefix libomp)/lib/libomp.dylib这一条命令就是告诉编译器“去找Homebrew目录下的libomp”。不写的话编译器会用默认路径搜索Apple Silicon上往往搜不到。macOS下编译时还有一个很容易被忽视的问题OpenCV版本。Homebrew当前默认的OpenCV是4.x对OpenMVS来说4.x整体兼容性还可以但个别函数比如cv::imread对路径的编码处理在macOS的某些版本上会有诡异行为。这个不影响编译影响的是运行时。如果后面跑测试数据集时发现图像加载不出来优先检查路径和图像编码格式。4.4 三平台对比小结平台依赖安装方式主要风险点我的建议Windowsvcpkg或手动装工具链不统一、OpenCV lib命名统一MSVC版本用vcpkg管理Linuxapt 源码补装Ceres版本太老、OpenMP与CUDA冲突Ceres源码编译CUDA与OpenMP先开一个macOSHomebrewOpenMP缺失、OpenCV运行时问题手动加libomp路径运行时再调试5. 编译报错的完整排查链路从报错信息反推根因这一节是全文的重头戏。你费尽千辛万苦终于把CMake配置跑通了然后make报错。怎么排查我分几个典型场景逐一讲。5.1 CMake阶段的报错百分之八十是路径问题第一阶段是CMake配置阶段报错基本逃不开下面这几类找不到包Could not find a package configuration file provided by Ceres。根因Ceres_DIR没设置或设置错了。排查先在终端里执行list命令查看Cereal的安装位置然后把实际路径传给CMake。注意不要只传给父目录CMake要的是包含CeresConfig.cmake的那个目录。版本不匹配The Eigen version is too old或requires Eigen 3.3.7。根因某些库比如Ceres在编译时强制检查Eigen版本。排查检查是否有多个版本的Eigen存在。Ubuntu下有时候/usr/include/eigen3和/usr/local/include/eigen3里各装了一份CMake用了老的那份。直接用-DEIGEN3_INCLUDE_DIR指到新版路径即可。Python/其他无关依赖干扰偶尔报找不到Python或者Qt的错。根因OpenMVS的构建系统里某些第三方模块可能被系统全局的配置污染。排查这种情况极少见通常关闭对应的MVS_USE_*开关就可以。5.2 编译阶段的报错一看到C11/C14/C17字样就要警觉第二步开始真正编译代码最常见的一类报错是error: #error This file requires compiler and library support for the ISO C 2011 standard.这个报错的根因不是你的编译器太老而是CMake没有把C11/C17标准传给编译器。OpenMVS在部分分支上要求C17但CMakeLists里可能没有硬性设置而是依赖你手动传递。解决办法是CMake时加-DCMAKE_CXX_STANDARD17我在Ubuntu 20.04上第一次编的时候漏了这个参数结果CGAL的头文件里疯狂报错一度以为是自己CGAL装坏了。其实问题很简单就是标准没对齐。另一类典型编译报错是模板实例化相关error: no matching function for call to XXX::Compute这类问题基本可以锁定为版本接口变化。比如Ceres 1.x到2.x很多函数的参数从ceres::Problem变成了ceres::Problem::Options代码里如果OpenMVS源码是按Ceres 2.0的接口写的你用Ceres 1.x编译就会报这种错。反过来也一样。所以如果源码是从最新master分支拉的建议依赖也尽量靠近最新稳定版如果源码是某个release版本建议依赖版本和release发布的时间接近。5.3 链接阶段的报错Windows最痛Linux稍少链接阶段报错在Windows上最常见典型表现是大量LNK2019、LNK2001。这类报错我有一个百试百灵的排查顺序确认所有依赖库都是同一个编译器和同一个运行时编译的。混合使用MT静态运行时和MD动态运行时会在链接时爆炸。确认Debug和Release的库没有混用。比如你编译OpenMVS的Release版却把OpenCV的Debug libes链接进来了那LNK2001就是家常便饭。确认库路径没有被vcpkg和系统路径同时污染。Windows下有无数人因为PATH环境变量同时指向多个OpenCV版本而链接错库排查方式就是打开Visual Studio的链接器输入选项一条条看链接的是不是你想用的lib文件。Linux上链接报错较少但如果是自己从源码编译的Ceres可能会遇到unresolved symbol glog::...这是没装glog导致的。补一个sudo apt install libgoogle-glog-dev如果还报suitesparse相关错误sudo apt install libsuitesparse-dev5.4 一个完整的排查链路示例说了这么多我放一个自己之前实打实遇到过的排查过程方便你理解我是怎么一步步找到根因的。现象Windows上CMake配置顺利VS编译时报LNK2019: unresolved external symbol void __cdecl cv::copyMakeBorder(...)。第一步我先去查这是不是OpenCV的符号。copyMakeBorder是OpenCV核心库的函数在opencv_core4.dll里。于是我去VS的链接器设置里看发现工程链接的是opencv_world460.lib。问题就来了我的OpenCV安装版本是4.5.5而vcpkg里装的可能是4.6.0这两者的lib命名和符号版本都不一样。CMake的OpenCV_DIR指向了vcpkg里的4.6.0但我手动装过一个4.5.5的包系统环境变量里有一个路径干扰了。解决办法很简单把CMake缓存清掉重新指定OpenCV_DIR到vcpkg的share/opencv目录然后重新Configure、Generate。编译立刻通过。这个例子说明什么OpenMVS编译报错绝大多数时候不是源码问题而是环境里有多份同名的路径互相打架。所以我一直建议开始配置之前就把系统的PATH、CMAKE_PREFIX_PATH先检查一遍确保只有一个版本的依赖库在一个可控目录下。5.5 CUDA相关的报错最后快速提一下CUDA的坑。如果你开了-DMVS_USE_CUDAON那么编译时可能会遇到CMake Error: CUDA unknown architecture compute_30这是因为新版CUDA Toolkit里已经移除了对旧架构比如Kepler/compute_30的支持。解决办法是在CMake时指定一个合理的架构比如Pascal架构对应compute_60老一点的卡用compute_50-DCUDA_GENERATIONPascal如果编译时提示cuda_runtime.h找不到那是CUDA_TOOLKIT_ROOT_DIR没有指定正确。Windows下通常是这样-DCUDA_TOOLKIT_ROOT_DIRC:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.8装CUDA的时候如果是默认路径一般就是这个目录。注意不要写成有空格的形式路径如果带空格CMake里一定要加引号。6. 编译完成之后验证产物、跑通最小示例、后续还能怎么扩展编译通过不代表万事大吉。打开build目录你会看到一堆可执行文件其中有几个核心工具是每天都用得上的DensifyPointCloud稠密点云重建ReconstructMesh网格重建RefineMesh网格细化TextureMesh纹理映射InterfaceViewer可视化查看器需要编译时开相关开关先跑一个最简单的示例把整个流程验证一遍。OpenMVS官方提供了测试数据和一些处理脚本一般来说你会准备一个图片文件夹然后按顺序执行# 1. 用OpenMVG或者其他SfM工具生成位姿文件.mvs格式 # 2. 稠密重建 ./DensifyPointCloud input.mvs -o output.mvs -w working_dir # 3. 网格重建 ./ReconstructMesh output.mvs -o mesh.mvs -w working_dir # 4. 细化网格 ./RefineMesh mesh.mvs -o refined.mvs -w working_dir # 5. 纹理映射 ./TextureMesh refined.mvs -o textured.mvs -w working_dir如果这几步都能顺利跑通你的编译就完全成功了。这里有一个关键点OpenMVS的输入不是直接的图片而是的.mvs文件里面记录的是相机位姿和稀疏点云。所以一般需要配合OpenMVG一起使用。OpenMVG也是一个独立的开源项目也需要编译。两个项目之间的衔接本质就是OpenMVG导出OpenMVS能识别的场景格式。如果你只想测OpenMVS本身官网的Tests目录里有一些现成的数据可以直接跑不必从头做SfM。流程虽然短但能验证你的二进制文件是否真的正常工作。编译完成之后后续还能怎么扩展我提供几个方向整合自己的采集流程用手机拍一组照片跑一遍OpenMVGOpenMVS看看整个重建效果。调优参数OpenMVS的命令行参数非常多比如--resolution-level控制处理分辨率--dense-config-file控制稠密重建策略。不同数据集差别很大值得花时间做几组对照实验。二次开发OpenMVS的代码结构清晰你完全可以修改DensifyPointCloud的逻辑替换深度图融合策略或者改TextureMesh的纹理映射算法。想在工程里落地的话这一步的意义远大于单纯的使用。我个人的建议是第一次编译别追求把CUDA和所有模块全开先把CPU版本跑通后面再逐步开CUDA优化。这个做法的好处是缩小问题排查范围——如果CPU版能编过跑通说明依赖和源码本身没问题后面加CUDA如果失败问题一定出在CUDA相关配置上不会有“什么都可能出问题”的困扰。7. 把这一步走通之后的一些个人体会做三维重建的人绕不开OpenMVS。它不像一些商业软件装了就能用正因为它开源、可定制才需要你先亲手把它编译出来。这个过程可能会耗掉你两三天甚至更久的时间但请相信绝大多数时间不是花在最后那几步而是花在“环境为什么对不上”上。我的建议是别硬扛多用CMake的日志信息报错时仔细读输出内容里的路径提示。output.txt里每一条Found XXX at /path/to/xxx都值得扫一眼确认路径是否指向了你想用的那个库。路径对不上八成就是问题所在这比反复清缓存重来快得多。编译通了之后手里的这套工具就是真正属于你的了。后续不管是跑公开数据集还是自己采集的照片能随时改参数、看中间结果、调试算法这种掌控感是直接用预编译binaries的人体会不到的。这也是我为什么愿意花专门的时间写这篇OpenMVS源码编译的文章——它值得被认真对待也值得你亲手走一遍。
返回列表