尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

VS2017下PCL1.9.1从零配置全攻略:依赖库、链接与避坑指南

VS2017下PCL1.9.1从零配置全攻略:依赖库、链接与避坑指南 做点云处理和三维视觉的朋友应该都体会过 PCL 配置的酸爽。尤其是项目还在用 VS2017手头拿到的又恰好是 PCL1.9.1 的预编译包时光是各种 include、lib、DLL 就能折腾一下午。这篇我把自己在 Win10 下从零配置 VS2017 PCL1.9.1 的完整过程整理出来从版本选择、安装目录规划、环境变量到 VS2017 里附加包含目录、附加库目录、预处理定义和 lib 清单再到常见编译错误怎么排查全部按实际操作的顺序讲透。适合第一次装 PCL 的初学者也适合被 LNK2019、0xc000007b 折磨过的老手。1. 版本与方案选型为什么偏偏是 VS2017 PCL1.9.11.1 版本对应关系先说清楚PCL 官方预编译包不是“一个包通吃所有 VS 版本”。PCL 1.9.1 发布时的 AllInOne 安装包明确区分了 msvc2015 和 msvc2017 两个版本对应的编译器分别是 VS2015vc140和 VS2017vc141。我这里使用的是PCL-1.9.1-AllInOne-msvc2017-win64.exe它能匹配 VS2017 默认的 v141 工具集。如果你强行拿 VS2017 去链接用 vc150 之前编译的库理论上部分能用但 Boost 的 lib 命名里会带上vc140、vc141这样的标签混用很容易出现 LNK2019 或运行时崩溃别自找麻烦。那为什么老项目都爱守着 VS2017 PCL1.9.1 这个组合因为 PCL 1.9.1 是最后一代官方默认使用 Boost 三元组、也比较好配的版本网上教程最多遇到问题搜索引擎一搜一大把。后续 PCL 1.10、1.11 对 C14/17 的适配更好但 AllInOne 包的配套版本往往不是 VS2017而是 VS2019 或更高。如果你手头正好是 VS2017又不想从源码重新编译 PCL选 1.9.1 就是最省时间的路径。1.2 依赖库角色别搞混PCL 不是一坨孤零零的代码库它站在一堆第三方库的肩膀上。在 1.9.1 的 AllInOne 安装包里官方默认打包了几个关键依赖Boost提供智能指针、文件系统、线程等基础能力PCL 早期的代码大量使用boost::shared_ptr位置在3rdParty\Boost。Eigen矩阵运算和线性代数核心点云变换、法线估计都靠它位置在3rdParty\Eigen。FLANN快速最近邻搜索库KdTree 检索的底层实现位置在3rdParty\FLANN。Qhull凸包和 Delaunay 三角化相关算法位置在3rdParty\Qhull。VTK可视化模块的依赖没有它 PCLVisualizer 跑不起来位置在3rdParty\VTK。这些库在安装时会被放到 PCL 根目录下的3rdParty文件夹里。配置 VS2017 时除了要告诉编译器去include目录找头文件还要告诉链接器去对应的lib目录找库文件。很多人只配了 PCL 自己的 include 和 lib导致编译时头文件过了、链接时一堆符号找不到原因就在这里。1.3 安装路径规划这一步偷懒后面全是坑安装 PCL 前最好先规划一个干净的路径。我的建议是直接装到D:\PCL或D:\PCL1_9_1不要用默认的C:\Program Files\PCL更不要放进带中文或空格的目录。原因有三个第一路径带空格会让某些老版本依赖库的构建脚本抓狂第二中文路径在某些控制台程序里会出现编码问题第三VS 工程的附加包含目录和附加库目录里都要写这个路径路径越短越好排查。我自己一般用D:\PCL1_9_1后面所有例子都按这个路径写。2. 下载与安装把 PCL 和第三方依赖库装进一个干净的目录2.1 安装包从哪里拿PCL 官方 GitHub Release 页面能找到所有历史版本。对 1.9.1需要下载两个文件PCL-1.9.1-AllInOne-msvc2017-win64.exe主安装包包含 PCL 库文件和第三方依赖库的安装向导。PCL-1.9.1-AllInOne-msvc2017-win64-pdb-msvc2017.zip调试符号文件包强烈建议一起下载调试崩溃问题时能省大量时间。下载时注意后缀必须是win64别错下成win32。如果你的机器是 64 位 WindowsVS2017 编译目标也是 x64那么 64 位库才能无缝对接。2.2 安装过程与目录结构双击 AllInOne 安装包后前几步一路 Next到选择安装路径时改成D:\PCL1_9_1。安装过程中会弹出一个“是否安装第三方依赖库”的界面务必勾选并保证这几个第三方库也安装到D:\PCL1_9_1\3rdParty下。装完之后检查一下目录结构理想状态是这样的D:\PCL1_9_1\ │ ├── bin\ # PCL 的 DLL 和 exe ├── include\pcl-1.9\ # PCL 头文件 ├── lib\ # PCL 的 .lib 文件 ├── cmake\ # 给 CMake 用的配置 └── 3rdParty\ ├── Boost\ ├── Eigen\ ├── FLANN\ ├── Qhull\ └── VTK\如果3rdParty下缺了某个库或者整个目录为空说明安装时依赖库向导没跑完。解决办法是重新运行安装包在取消所有选项后单独勾选“3rdParty”相关组件或者去 PCL Release 页面找对应的3rdParty压缩包手动解压到D:\PCL1_9_1\3rdParty。2.3 环境变量配置PCL_ROOT 和 PATH装完后需要把 PCL 的 DLL 目录加进系统环境变量否则运行时会出现“找不到 pcl_common.dll”之类的报错。按Win R输入sysdm.cpl打开“系统属性 → 高级 → 环境变量”。在“系统变量”里新建一个变量变量名PCL_ROOT 变量值D:\PCL1_9_1然后在“系统变量 → Path”里追加以下条目%PCL_ROOT%\bin %PCL_ROOT%\3rdParty\Boost\lib %PCL_ROOT%\3rdParty\FLANN\bin %PCL_ROOT%\3rdParty\Qhull\bin %PCL_ROOT%\3rdParty\VTK\bin注意不要把 PCL 的 bin 目录放在 Path 最前面免得它自带的某些 DLL 覆盖掉系统里其他软件的运行库。配置完成后重启命令提示符输入echo %PCL_ROOT%验证一下路径是否生效。2.4 调试符号包怎么解压把前面下载的 PDB 压缩包解压到D:\PCL1_9_1\bin里面的.pdb文件和.dll同名VS 调试器会自动去 exe 所在目录和符号路径里找。不放 PDB 也能编译运行只是崩溃时看不到调用栈里的函数名排查问题会吃力很多。3. VS2017 工程配置附加目录、预处理器定义与 lib 清单3.1 新建工程和平台准备打开 VS2017新建一个“Windows 桌面应用程序 → 空项目”或者“C 控制台应用”名字随意比如PCLTest。创建完成后第一件事不是写代码而是把活动平台切到 x64。操作路径是“生成 → 配置管理器”在“活动解决方案平台”下拉框里选择“新建”平台选 x64不要勾选“创建新的项目平台”直接从 Win32 复制过来即可。切到 x64 后后续所有属性配置都要在Debug|x64和Release|x64两个配置下分别做。很多人一上来就在默认的 Win32 平台下配置结果编译时提示找不到 64 位库或者链接成功但运行就报 0xc000007b就是因为平台搞错了。另外确认 VS2017 已经安装了“使用 C 的桌面开发”工作负载里面有 MSVC v141 工具集和 Windows 10 SDK。没有这个组件项目连创建都困难。3.2 附加包含目录怎么填右键项目 → 属性在顶部“配置”下拉框里选择“Debug”“平台”选择“x64”。然后进入C/C → 常规 → 附加包含目录把以下路径加进去D:\PCL1_9_1\include\pcl-1.9 D:\PCL1_9_1\3rdParty\Boost\include\boost-1_64 D:\PCL1_9_1\3rdParty\Eigen\eigen3 D:\PCL1_9_1\3rdParty\FLANN\include D:\PCL1_9_1\3rdParty\Qhull\include D:\PCL1_9_1\3rdParty\VTK\include\vtk-8.1这里最容易被坑的是 Boost 和 Eigen 的路径层级。Boost 头文件实际位于3rdParty\Boost\include\boost-1_64\boost但附加包含目录要填到boost-1_64这一层编译器才能用#include boost/shared_ptr.hpp的方式找到它。Eigen 则要填到eigen3这层因为源码里通常写的是#include Eigen/Dense编译器会在eigen3目录下找到Eigen文件夹。3.3 附加库目录配置还是在项目属性里进入链接器 → 常规 → 附加库目录加以下路径D:\PCL1_9_1\lib D:\PCL1_9_1\3rdParty\Boost\lib D:\PCL1_9_1\3rdParty\FLANN\lib D:\PCL1_9_1\3rdParty\Qhull\lib D:\PCL1_9_1\3rdParty\VTK\lib这里的D:\PCL1_9_1\lib是 PCL 自己编译好的静态库目录后面几个是第三方依赖库的库文件目录。配完这个链接器才能找到pcl_common_debug.lib、libboost_system-vc141-mt-gd-1_64.lib、vtkCommonCore-8.1.lib这些文件。3.4 预处理器定义进入C/C → 预处理器 → 预处理器定义把下面几项加进去_CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE这几项的作用是关掉老 C 函数和 STL 的安全检查警告。PCL 1.9.1 内部用了不少fopen、strcpy这类函数不定义这些宏编译时会刷出一大片 C4996 警告虽然不影响运行但会干扰你定位真正的问题。3.5 运行库与 C 语言标准这里是个隐藏大坑。进入C/C → 代码生成 → 运行库必须选“多线程调试 DLL (/MDd)”Debug 配置或“多线程 DLL (/MD)”Release 配置。PCL 官方的预编译二进制使用的是动态 CRT如果你的工程默认选了/MTd或/MT链接时就会报 LNK2038 mismatch detected for RuntimeLibrary或者一堆关于__imp_开头的符号找不到。再看C/C → 语言 → C 语言标准建议保持默认或显式选择“ISO C14 标准”。PCL 1.9.1 发布时 C17 还没普及它的头文件在 C17 模式下偶尔会触发std::unary_function已移除之类的编译错误。VS2017 支持的最高 C 模式也就是 17如果你项目里有人改成了 C17遇到奇怪的模板报错先改回 C14 试一下。3.6 lib 清单Debug 全加 debug 版Release 就去掉 _debug链接配置里最让人头大的就是 lib 清单。PCL 的模块划分很细有pcl_common、pcl_io、pcl_visualization、pcl_filters、pcl_segmentation、pcl_features等等。如果你只写了几行测试代码其实只需要用到的模块对应的 lib。我的建议是新手不要试图追求“最小依赖”直接在附加依赖项里把整个D:\PCL1_9_1\lib目录下的所有pcl_*_debug.lib全选粘贴进去然后再加上 Boost 和 VTK 的 lib。这样虽然看起来笨但能最大程度避免漏库导致的 LNK2019。在 Debug 配置下打开链接器 → 输入 → 附加依赖项添加类似下面这些pcl_common_debug.lib pcl_io_debug.lib pcl_visualization_debug.lib pcl_filters_debug.lib pcl_search_debug.lib pcl_kdtree_debug.lib pcl_octree_debug.lib pcl_sample_consensus_debug.lib libboost_system-vc141-mt-gd-1_64.lib libboost_filesystem-vc141-mt-gd-1_64.lib libboost_thread-vc141-mt-gd-1_64.lib vtkCommonCore-8.1.lib vtkCommonDataModel-8.1.lib vtkCommonMath-8.1.lib vtkCommonMisc-8.1.lib vtkCommonSystem-8.1.lib vtkCommonTransforms-8.1.lib vtkFiltersSources-8.1.lib vtkInteractionStyle-8.1.lib vtkRenderingAnnotation-8.1.lib vtkRenderingCore-8.1.lib vtkRenderingFreeType-8.1.lib vtkRenderingOpenGL2-8.1.lib vtkRenderingUI-8.1.lib如果实际用到的模块超过上面这些建议直接在 lib 目录里按字母序全选 PCL 的 debug lib 追加进去多了也不会出问题就是链接时间稍长一点。Release 配置下把所有的_debug去掉Boost 库名里的-gd也要去掉比如libboost_filesystem-vc141-mt-1_64.lib。3.7 DLL 部署别让程序运行时到处找文件就算环境变量 PATH 配好了Debug 调试时会用 VS 把 PATH 里的 DLL 加载进来但如果把生成的可执行文件拷到别的机器上或者系统 PATH 被其他软件改乱还是会报找不到 DLL。最稳妥的办法是让 PCL 的 DLL 跟着 exe 走。在项目属性 →生成事件 → 后期生成事件 → 命令行里添加xcopy /Y /D D:\PCL1_9_1\bin\*.dll $(OutDir) xcopy /Y /D D:\PCL1_9_1\3rdParty\Boost\lib\*.dll $(OutDir) xcopy /Y /D D:\PCL1_9_1\3rdParty\FLANN\bin\*.dll $(OutDir) xcopy /Y /D D:\PCL1_9_1\3rdParty\Qhull\bin\*.dll $(OutDir) xcopy /Y /D D:\PCL1_9_1\3rdParty\VTK\bin\*.dll $(OutDir)这样每次编译完所有必需的 DLL 都会自动复制到 exe 所在目录调试和发布都稳定。注意这个命令里两个大目录下如果有同名 DLL后复制的会覆盖前面所以顺序一般按 VTK、FLANN、Qhull、Boost、PCL 调整让 PCL 的 DLL 最后复制进去。4. 首个测试工程生成、读写并可视化点云4.1 测试代码怎么设计配置完成后先写一个能覆盖常用功能的最小测试程序。我的测试代码做了三件事生成一个随机点云、写入 PCD 文件再读回来、用 PCLVisualizer 显示出来。这三步几乎覆盖了 PCL 最核心的 IO 和可视化模块任何一个环节有问题都能立刻暴露出来。#include pcl/point_types.h #include pcl/io/pcd_io.h #include pcl/filters/voxel_grid.h #include pcl/visualization/pcl_visualizer.h #include iostream #include random int main(int argc, char** argv) { // 1. 生成随机点云 pcl::PointCloudpcl::PointXYZ::Ptr cloud(new pcl::PointCloudpcl::PointXYZ()); cloud-width 2000; cloud-height 1; cloud-is_dense false; cloud-resize(cloud-width * cloud-height); std::mt19937 rng(42); std::uniform_real_distributionfloat dist(-1.0f, 1.0f); for (auto p : cloud-points) { p.x dist(rng); p.y dist(rng); p.z dist(rng); } // 2. 写入 PCD 文件 if (pcl::io::savePCDFileBinary(random_cloud.pcd, *cloud) ! 0) { PCL_ERROR(保存 PCD 文件失败\n); return -1; } std::cout 已保存 cloud-size() 个点到 random_cloud.pcd std::endl; // 3. 读回 PCD 文件 pcl::PointCloudpcl::PointXYZ::Ptr loaded(new pcl::PointCloudpcl::PointXYZ()); if (pcl::io::loadPCDFilepcl::PointXYZ(random_cloud.pcd, *loaded) -1) { PCL_ERROR(读取 PCD 文件失败\n); return -1; } std::cout 读取到 loaded-size() 个点 std::endl; // 4. 可视化 pcl::visualization::PCLVisualizer viewer(PCL Viewer); viewer.setBackgroundColor(0.1, 0.1, 0.1); viewer.addPointCloudpcl::PointXYZ(loaded, cloud); viewer.setPointCloudRenderingProperties( pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, cloud); while (!viewer.wasStopped()) { viewer.spinOnce(10); } return 0; }代码里的PCL_ERROR是 PCL 自带的输出宏用来打错误信息。savePCDFileBinary表示按二进制格式保存 PCD 文件文件小、读写快。4.2 编译运行会遇到什么写完代码直接按 F5 编译运行。Debug 模式下编译成功后 VS 会启动一个控制台窗口接着弹出一个 PCL Viewer 窗口里面显示 2000 个随机散点。如果一切正常说明 PCL 的核心库、IO 库、可视化库、VTK 库和 Boost 库全部连通了。如果你在编译阶段报错先停下来看错误是来自 C1083找不到头文件、LNK2019链接符号解析失败还是运行时的 DLL 缺失对应的排查路径完全不同。不要一上来就重装先看错误信息里的文件名和行号大部分问题都能定位到具体环节。4.3 验证实际使用的是不是 PCL 1.9.1有时候机器上装了多个版本的 PCL头文件和库文件可能被 PATH 顺序影响导致实际编译用到的不是你以为的那个版本。可以在代码里临时输出一下 PCL 的版本宏验证#include pcl/pcl_config.h std::cout PCL_VERSION: PCL_VERSION std::endl;PCL_VERSION是一个整数1.9.1 对应的值是1009001。如果输出结果不是这个说明 include 路径可能指到了别的版本回去检查附加包含目录。5. 高频编译错误与排查手册5.1 编译期错误速查表我把平时遇到最多的错误和解决办法整理了一个表方便对照错误信息常见原因解决办法C1083 无法打开包括文件pcl/pcl_config.h附加包含目录没配 PCL 头文件路径检查include\pcl-1.9是否在附加包含目录里C1083 无法打开包括文件Eigen/DenseEigen 路径配到了错误层级附加包含目录应指向3rdParty\Eigen\eigen3C4996fopenconsidered unsafe缺少安全警告宏在预处理器定义里加入_CRT_SECURE_NO_WARNINGSLNK2019 无法解析的外部符号pcl::visualization::...缺少对应的 PCL 模块 lib把 lib 目录下所有pcl_*_debug.lib加进附加依赖项LNK2038 RuntimeLibrary 不匹配项目运行库是 /MT而 PCL 是 /MD把运行库改为“多线程调试 DLL (/MDd)”或“多线程 DLL (/MD)”C2712 或一堆模板编译错误C 语言标准设成了 C17改回 C14 标准D8016/RTC1与/O2冲突工程同时开启调试运行时和优化检查代码生成里的优化选项Debug 默认别改这里想多说一句 LNK2019。很多人遇到“无法解析的外部符号”就慌了其实你只要看符号名里有没有_debug或者vc141这样的标签。如果符号名出现boost::filesystem但你没加 Boost 的 lib那多半就是漏了。最简单的办法还是全量加入 lib 目录下的库文件消掉了再慢慢精简。5.2 运行期错误速查表编译链接过了不等于万事大吉运行时同样有一堆坑。错误现象常见原因解决办法运行提示找不到pcl_common.dllPATH 环境变量没配好或 DLL 未复制把 PCL bin 目录加入 PATH或用后期事件复制 DLL 到 exe 目录运行提示找不到vtkCommonCore-8.1.dllVTK 的 bin 目录没在 PATH 里把3rdParty\VTK\bin加入 PATH 或复制 DLL启动直接报 0xc000007b64 位 DLL 被 32 位进程加载确认项目平台是 x64程序也按 x64 编译运行时崩溃调用栈指向 Boost 或 Eigen 相关多个 PCL/Boost 版本混用清理 PATH 里其他 PCL 相关路径确保只保留一个版本点云显示了但颜色、大小不正常没设置渲染属性检查setPointCloudRenderingProperties的参数0xc000007b 这个错误特别容易误判。它不是“系统文件损坏”而是进程位数和 DLL 位数不匹配。你只需要打开任务管理器确认进程是 64 位再看加载的 DLL 路径来源即可。5.3 排查 DLL 加载问题的工具DLL 加载问题有时候不是简单地缺文件而是同名 DLL 被系统 PATH 里其他程序抢先加载了。我推荐一个工具叫Process Explorer用它的“查找 DLL”功能选中进程后直接看 pcl_common.dll 是从哪个路径加载的。如果加载路径不是D:\PCL1_9_1\bin说明你的 PATH 顺序有问题把 PCL 相关的路径在环境变量里挪到其他软件的 bin 前面。另外一个更直接的办法是在 VS 调试器里打开“模块”窗口找到 pcl_common.dll看它的路径和版本。如果路径不对就按上面的后期生成事件强制复制 DLL 到 exe 目录这样能完全绕开 PATH 顺序问题。6. 踩坑总结与个人建议6.1 我最想提醒新手的几件事第一先让最简 demo 跑通再扩展。不要一上来就建一个几十个模块的大工程然后妄想把所有 PCL 的功能都用上。我见过太多人把 segmentation、registration、surface 的 lib 全部加进去结果链接出一堆符号冲突最后都不知道是哪个模块的问题。先用我上面的测试代码跑通再逐步添加其他模块。第二Debug 和 Release 的配置必须分开设。VS 属性页里“配置”下拉框会记住你当前选的是 Debug 还是 Release很多人在 Debug 下把附加依赖项配好了切到 Release 编译直接报 LNK2019回头看属性页才发现 Release 的附加依赖项全是空的。你可以在“视图 → 属性管理器”里创建两个属性表分别保存 Debug|x64 和 Release|x64 的配置以后新建项目直接导入属性表能省不少事。第三不要同时使用多个 PCL 版本。有时候开发机上既有 PCL 1.8又有 PCL 1.9或者 conda、vcpkg 的路径都在 PATH 里编译器会按照顺序找到第一个 pcl_config.h。遇到诡异问题时先检查项目里pcl/PCLConfig.h的实际情况确认到底用的是哪个版本。6.2 这个环境后续还能怎么用PCL 1.9.1 配好之后基本能覆盖点云滤波、配准、分割、特征提取和可视化这些日常操作。如果你是做机器人或三维重建的可能还需要集成 OpenCV、Eigen、Ceres 之类这些库的配置思路和这里完全一样头文件目录加进附加包含目录库文件目录加进附加库目录DLL 做好部署。掌握了这套手动配置的逻辑以后配任何 C 库都不会再发怵。我个人习惯是把这个工程的属性表专门存一份放在网盘上换电脑或帮同事配环境时直接导入十分钟就能跑起来。配置 PCL 本身不难难的是把每一步做对、把每一个文件路径都搞清楚。希望这篇能帮你少踩几个坑。
返回列表