简介本资源面向需要在Windows平台使用Qt与MinGW构建三维点云应用的C开发者提供PCL及其全部依赖库的完整编译成果。PCL是专注三维点云处理的开源库覆盖采集、预处理、特征提取到表面重建Qt负责跨平台图形界面MinGW提供GCC工具链Boost、Eigen、FLANN、Qhull、VTK则分别承担通用工具、矩阵运算、近邻搜索、几何计算与三维可视化职责。压缩包共约2000个文件以1997个hpp头文件为主另含1个txt、1个pdf与1个doc说明文档整体约151.31MB头文件可直接用于包含与链接文档便于查阅版本与配置信息。目前已有36人学习下载。对于不想自行折腾编译链、希望快速在QtMinGW环境接入PCL的读者这份资源能省去大量依赖排查与编译时间直接进入点云算法与可视化开发。1. 为什么在 Qt 里用 MinGW 编译 PCL 是个麻烦事如果你在 Windows 上做点云开发大概率绕不开 PCL。官方预编译包只给 MSVC 版本而 Qt 默认搭配的往往是 MinGW 工具链。这两件事撞在一起就是一场依赖地狱Boost、Eigen、FLANN、Qhull、VTK 五个库要逐个用同一套 GCC 编译ABI 必须完全对齐差一个版本号就是满屏的 undefined reference。我见过太多人在这卡三天最后放弃 Qt 换 Visual Studio。但 MinGW 编译出来的程序不依赖 MSVC 运行库打包体积小和 Qt 的 qmake 集成也更顺。这篇笔记就是把我自己踩过的坑拆开从工具链准备到 CMake 参数逐个讲清楚让你能在 Qt Creator 里用 MinGW 跑通一个完整的点云可视化 Demo。适合已经会 C 和 CMake、但被 PCL 依赖搞烦的从业者。2. 工具链准备MinGW、CMake 和 Qt 的版本对齐2.1 为什么版本对齐比编译本身更重要PCL 的依赖链是 Boost → FLANN → VTK → PCL每一层都要求 C 标准一致、异常模型一致、线程模型一致。MinGW 有几个发行版官方 mingw-w64、Qt 自带的 MinGW、以及 MSYS2 里的 mingw-w64。它们虽然都叫 MinGW但 GCC 版本、posix/win32 线程模型、sjlj/seh 异常模型可能不同。一旦混用链接阶段就会报undefined reference to std::thread或者_Unwind_Resume找不到。我的建议是全部用 Qt 自带的 MinGW。Qt 安装器里勾选 MinGW 组件后路径通常在Qt/Tools/mingw*/bin。这个工具链和 Qt 的 qmake 是配套验证过的省去自己配 MSYS2 的麻烦。CMake 用 Qt 安装器里自带的版本或者单独装一个 3.20 以上的版本但要注意 CMake 的 generator 必须选MinGW Makefiles不能选 Ninja 除非你确认 ninja 也在 PATH 里。2.2 环境变量与目录规划先把目录结构定下来后面所有编译都往这里装。我一般这样规划# 假设工作根目录 D:/pcl_mingw/ ├── src/ # 各库源码 ├── build/ # 各库编译目录 ├── install/ # 统一安装前缀 │ ├── boost/ │ ├── eigen/ │ ├── flann/ │ ├── qhull/ │ ├── vtk/ │ └── pcl/ └── toolchain.cmake环境变量里把 MinGW 的 bin 放到最前面避免系统里其他 GCC 干扰# 在 cmd 或 PowerShell 里临时设置建议写进脚本 set PATHD:/Qt/Tools/mingw1120_64/bin;%PATH% set CMAKE_PREFIX_PATHD:/pcl_mingw/install提示不要用中文路径不要有空格。VTK 和 PCL 的 CMake 脚本对空格路径处理得不好报错信息还特别隐晦。验证工具链gcc --version g --version cmake --version mingw32-make --version四个命令都能输出版本号且 gcc 和 g 版本一致才算准备好。如果mingw32-make找不到说明 MinGW 的 bin 没进 PATH或者你装的是只有编译器的精简包。2.3 一个容易忽略的点线程模型MinGW 的 GCC 有 posix 和 win32 两种线程模型。PCL 和 Boost 的某些组件依赖std::thread必须用 posix 版本。检查方法gcc -v输出里找Thread model: posix。如果是 win32后面 Boost 编译会直接失败。Qt 自带的 MinGW 一般是 posix但如果你从别处下载的压缩包务必确认这一行。3. 依赖库逐个编译Boost、Eigen、FLANN、Qhull 的编译参数3.1 Boost用 b2 还是 CMakeBoost 是第一个要编的因为 FLANN 和 PCL 都依赖它。Boost 官方推荐 b2 工具但在 MinGW 下 b2 的配置有点绕。我一般用 b2因为 CMake 编 Boost 会漏掉一些编译选项。先进入 Boost 源码目录执行 bootstrapcd D:/pcl_mingw/src/boost_1_84_0 bootstrap.bat gcc这会生成b2.exe。然后写一个user-config.jam放到%HOMEPATH%下内容指定 MinGW 的 gusing gcc : mingw : D:/Qt/Tools/mingw1120_64/bin/g.exe ;编译命令b2.exe install ^ --prefixD:/pcl_mingw/install/boost ^ --build-typecomplete ^ --toolsetgcc-mingw ^ --with-system ^ --with-filesystem ^ --with-thread ^ --with-date_time ^ --with-iostreams ^ --with-serialization ^ --with-regex ^ -j8参数说明--prefix是安装路径--build-typecomplete会同时编静态库和动态库PCL 链接时两种都可能用到--with-xxx只编 PCL 需要的模块省时间-j8按 CPU 核数调整。编完后install/boost/lib下应该有libboost_system-mgw11-mt-1_84.a这类文件mgw11表示 MinGW GCC 11mt表示多线程。注意如果 b2 报gcc.link相关错误多半是 user-config.jam 路径写错或者 g 不在 PATH 里。b2 不会自动读 PATH必须在 jam 文件里写绝对路径。3.2 Eigen头文件库但别直接复制Eigen 是纯头文件库理论上解压就能用。但 PCL 的 CMake 脚本会找Eigen3Config.cmake所以还是要走一遍 CMake 安装流程生成配置文件。cd D:/pcl_mingw/build mkdir eigen cd eigen cmake D:/pcl_mingw/src/eigen-3.4.0 ^ -G MinGW Makefiles ^ -DCMAKE_INSTALL_PREFIXD:/pcl_mingw/install/eigen ^ -DCMAKE_BUILD_TYPERelease ^ -DBUILD_TESTINGOFF mingw32-make install -j8Eigen 没有编译产物make install只是复制头文件和生成Eigen3Config.cmake。BUILD_TESTINGOFF能省掉一堆测试代码的编译。装完后检查install/eigen/share/eigen3/cmake/Eigen3Config.cmake是否存在后面 PCL 配置时要指向这个目录。3.3 FLANN最容易翻车的一个FLANN 依赖 Boost编译前要告诉它 Boost 在哪。FLANN 的 CMake 脚本对 MinGW 支持一般有几个参数必须手动关。cd D:/pcl_mingw/build mkdir flann cd flann cmake D:/pcl_mingw/src/flann-1.9.2 ^ -G MinGW Makefiles ^ -DCMAKE_INSTALL_PREFIXD:/pcl_mingw/install/flann ^ -DCMAKE_BUILD_TYPERelease ^ -DBOOST_ROOTD:/pcl_mingw/install/boost ^ -DBOOST_INCLUDEDIRD:/pcl_mingw/install/boost/include ^ -DBOOST_LIBRARYDIRD:/pcl_mingw/install/boost/lib ^ -DBUILD_PYTHON_BINDINGSOFF ^ -DBUILD_MATLAB_BINDINGSOFF ^ -DBUILD_EXAMPLESOFF ^ -DBUILD_TESTSOFF ^ -DUSE_OPENMPOFF mingw32-make install -j8BOOST_ROOT三个变量必须同时给只给一个 FLANN 可能找不到。USE_OPENMPOFF是因为 MinGW 的 OpenMP 和 FLANN 的某些模板代码冲突开了会报_mm_malloc未定义。Python 和 MATLAB 绑定直接关掉用不上还容易出错。编完后install/flann/lib下应该有libflann_cpp.a和libflann_cpp_s.a。PCL 默认找flann_cpp_s如果只编了动态库链接时会报找不到。3.4 Qhull重命名库文件Qhull 的 CMake 脚本在 MinGW 下生成的库名可能和 PCL 期望的不一致。PCL 找的是libqhullstatic.a或libqhull_r.a而 Qhull 自己可能生成libqhullstatic_r.a。cd D:/pcl_mingw/build mkdir qhull cd qhull cmake D:/pcl_mingw/src/qhull-2020.2 ^ -G MinGW Makefiles ^ -DCMAKE_INSTALL_PREFIXD:/pcl_mingw/install/qhull ^ -DCMAKE_BUILD_TYPERelease ^ -DBUILD_SHARED_LIBSOFF ^ -Dqhull_BUILD_STATICON mingw32-make install -j8装完后去install/qhull/lib看一眼如果只有libqhullstatic_r.a而没有libqhullstatic.a手动复制一份改名。这是血泪经验PCL 的 FindQhull 模块写死了名字。4. VTK 编译PCL 可视化的前置条件4.1 VTK 版本选择和 CMake 参数VTK 是这几个库里编译最久的也是最容易出问题的。PCL 1.13 以上建议配 VTK 9.2 或 9.3。VTK 9 的 CMake 脚本对 MinGW 支持比 VTK 8 好很多但还是要关掉一些模块。cd D:/pcl_mingw/build mkdir vtk cd vtk cmake D:/pcl_mingw/src/VTK-9.3.0 ^ -G MinGW Makefiles ^ -DCMAKE_INSTALL_PREFIXD:/pcl_mingw/install/vtk ^ -DCMAKE_BUILD_TYPERelease ^ -DBUILD_SHARED_LIBSON ^ -DVTK_BUILD_TESTINGOFF ^ -DVTK_BUILD_EXAMPLESOFF ^ -DVTK_BUILD_DOCUMENTATIONOFF ^ -DVTK_GROUP_ENABLE_QtNO ^ -DVTK_GROUP_ENABLE_WebNO ^ -DVTK_GROUP_ENABLE_MPINO ^ -DVTK_GROUP_ENABLE_ImagingYES ^ -DVTK_GROUP_ENABLE_RenderingYES ^ -DVTK_GROUP_ENABLE_ViewsYES ^ -DVTK_MODULE_ENABLE_VTK_GUISupportQtNO ^ -DVTK_MODULE_ENABLE_VTK_RenderingQtNO mingw32-make install -j8关键参数BUILD_SHARED_LIBSON编动态库PCL 可视化模块默认链接动态 VTKVTK_GROUP_ENABLE_QtNO和后面两个 Qt 模块关掉因为我们要用 Qt 自己的 QVTKOpenGLNativeWidget不需要 VTK 自带的 Qt 绑定开了反而会和 Qt 版本冲突VTK_GROUP_ENABLE_MPINO关掉并行MinGW 下 MPI 支持不完整。4.2 编译时间和内存VTK 全量编译在 8 核机器上大概 40 分钟到 1 小时。如果内存小于 16G-j8可能触发 OOM改成-j4。编译过程中如果某个模块报模板实例化错误先看是不是 C 标准没对齐。VTK 9 默认用 C17MinGW 11 支持没问题但如果你的 GCC 低于 9需要手动加-DCMAKE_CXX_STANDARD17。装完后检查install/vtk/lib/cmake/vtk-9.3/vtk-config.cmake是否存在。PCL 配置时VTK_DIR指向这个目录。5. PCL 本体编译CMake 配置与 Qt 集成5.1 PCL 的 CMake 参数逐个拆前面五个库都装好后PCL 的编译反而简单因为依赖路径都能通过CMAKE_PREFIX_PATH找到。但 PCL 自己的选项很多关掉不需要的模块能省一半编译时间。cd D:/pcl_mingw/build mkdir pcl cd pcl cmake D:/pcl_mingw/src/pcl-pcl-1.13.1 ^ -G MinGW Makefiles ^ -DCMAKE_INSTALL_PREFIXD:/pcl_mingw/install/pcl ^ -DCMAKE_BUILD_TYPERelease ^ -DCMAKE_PREFIX_PATHD:/pcl_mingw/install/boost;D:/pcl_mingw/install/eigen;D:/pcl_mingw/install/flann;D:/pcl_mingw/install/qhull;D:/pcl_mingw/install/vtk ^ -DBOOST_ROOTD:/pcl_mingw/install/boost ^ -DEIGEN_ROOTD:/pcl_mingw/install/eigen ^ -DFLANN_ROOTD:/pcl_mingw/install/flann ^ -DQHULL_ROOTD:/pcl_mingw/install/qhull ^ -DVTK_DIRD:/pcl_mingw/install/vtk/lib/cmake/vtk-9.3 ^ -DBUILD_SHARED_LIBSON ^ -DBUILD_appsOFF ^ -DBUILD_examplesOFF ^ -DBUILD_toolsOFF ^ -DBUILD_global_testsOFF ^ -DWITH_QTON ^ -DWITH_VTKON ^ -DWITH_CUDAOFF ^ -DWITH_OPENNIOFF ^ -DWITH_OPENNI2OFF ^ -DWITH_PCAPOFF ^ -DWITH_VTKON mingw32-make install -j8CMAKE_PREFIX_PATH用分号隔开多个路径这是 CMake 的列表语法。WITH_QTON会编译 PCL 的 Qt 可视化模块但注意这个 Qt 模块和 Qt Creator 里的 Qt 是两回事它只是 PCL 内部用 Qt 做窗口管理。WITH_CUDAOFF除非你有 N 卡且装了 CUDA Toolkit否则开了必挂。WITH_OPENNI系列是深度相机支持不用就关。5.2 编译报错排查表报错信息原因解决undefined reference to boost::system::...Boost 库没链接或版本不匹配检查BOOST_ROOT确认libboost_system-mgw11-mt-1_84.a存在Could NOT find FLANNFLANN 的 cmake 配置文件没生成重新编 FLANN确认install/flann/share/flann/FLANNConfig.cmake存在undefined reference to qhull::...Qhull 库名不对手动复制libqhullstatic_r.a为libqhullstatic.aVTK not foundVTK_DIR指向错误指向vtk-config.cmake所在目录不是 VTK 根目录Qt5::Widgets not foundQt 的 CMake 路径没进CMAKE_PREFIX_PATH把 Qt 的lib/cmake目录加进去5.3 在 Qt Creator 里配置 PCL 工程PCL 装好后Qt 工程里用 qmake 或 CMake 都能链接。我一般用 CMake因为 PCL 的 CMake 配置文件更完整。一个最小的CMakeLists.txtcmake_minimum_required(VERSION 3.20) project(PCLQtDemo LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) find_package(Qt5 REQUIRED COMPONENTS Widgets) find_package(PCL 1.13 REQUIRED COMPONENTS common io visualization) add_executable(PCLQtDemo main.cpp mainwindow.cpp mainwindow.h ) target_link_libraries(PCLQtDemo Qt5::Widgets ${PCL_LIBRARIES} ) target_include_directories(PCLQtDemo PRIVATE ${PCL_INCLUDE_DIRS}) target_link_directories(PCLQtDemo PRIVATE ${PCL_LIBRARY_DIRS}) target_compile_definitions(PCLQtDemo PRIVATE ${PCL_DEFINITIONS})find_package(PCL ... COMPONENTS ...)只找需要的模块common是基础类型io是文件读写visualization是可视化。PCL_LIBRARIES会自动带上 Boost、FLANN、VTK 的链接项不用手动加。在 Qt Creator 里打开这个 CMakeListsKit 选 MinGWCMake 配置里加-DCMAKE_PREFIX_PATHD:/pcl_mingw/install/pcl;D:/pcl_mingw/install/vtk;D:/Qt/5.15.2/mingw_64。注意 Qt 的路径也要加进去否则find_package(Qt5)找不到。6. 避坑与排查五个让我重装系统的瞬间6.1 坑一Boost 编了 win32 线程模型现象PCL 链接时报undefined reference to std::thread::_M_start_thread。原因Boost 用 win32 线程模型编译而 PCL 和 Qt 用 posix 模型两者 ABI 不兼容。解决gcc -v确认Thread model: posix如果不是换 Qt 自带的 MinGW 重新编 Boost。b2 的user-config.jam里可以显式加threadingmulti但线程模型是编译器决定的b2 改不了。6.2 坑二VTK 的 Qt 模块和 Qt Creator 冲突现象编译 PCL 可视化模块时报QVTKOpenGLWidget重复定义或 Qt 版本不匹配。原因VTK 自带的 Qt 绑定链接了另一个版本的 Qt和 Qt Creator 用的 Qt 冲突。解决VTK 编译时加-DVTK_MODULE_ENABLE_VTK_GUISupportQtNO -DVTK_MODULE_ENABLE_VTK_RenderingQtNO完全关掉 VTK 的 Qt 模块。PCL 可视化用QVTKOpenGLNativeWidget时自己从 VTK 的库链接不走 VTK 的 Qt 封装。6.3 坑三FLANN 的 OpenMP 导致模板报错现象FLANN 编译到lsh_table.h时报_mm_malloc未定义或omp_get_max_threads找不到。原因MinGW 的 OpenMP 实现和 FLANN 的 SIMD 指令集检测冲突。解决CMake 加-DUSE_OPENMPOFF。如果已经编了一半删掉 build 目录重来CMake 缓存里的 OpenMP 标志不会自动清除。6.4 坑四Qhull 库名不匹配现象PCL 配置时报Could NOT find Qhull (missing: QHULL_LIBRARY)。原因Qhull 2020 版本生成的静态库叫libqhullstatic_r.aPCL 的 FindQhull 找的是libqhullstatic.a。解决进install/qhull/lib复制libqhullstatic_r.a为libqhullstatic.a复制libqhull_r.a为libqhull.a。这是最省事的办法改 PCL 的 CMake 模块反而容易引入新问题。6.5 坑五路径里有空格或中文现象CMake 配置阶段报The source directory ... does not exist但路径明明是对的。原因VTK 和 PCL 的某些 CMake 脚本没有给路径加引号空格被当成参数分隔符。解决所有源码、build、install 路径都用纯英文无空格。如果已经装了移到新路径后必须删 build 目录重新 CMake缓存里的旧路径不会自动更新。7. 验证与进阶跑通一个点云可视化 Demo7.1 最小验证代码装完不是终点能跑起来才算。写一个读 PCD 文件并显示的 Demo// main.cpp #include QApplication #include pcl/point_types.h #include pcl/io/pcd_io.h #include pcl/visualization/pcl_visualizer.h #include vtkGenericOpenGLRenderWindow.h #include QVTKOpenGLNativeWidget.h int main(int argc, char** argv) { QApplication app(argc, argv); // 加载点云如果文件不存在就生成一个随机云 pcl::PointCloudpcl::PointXYZ::Ptr cloud(new pcl::PointCloudpcl::PointXYZ); if (pcl::io::loadPCDFilepcl::PointXYZ(test.pcd, *cloud) -1) { cloud-width 1000; cloud-height 1; cloud-points.resize(cloud-width * cloud-height); for (auto p : cloud-points) { p.x 1024.0f * rand() / (RAND_MAX 1.0f); p.y 1024.0f * rand() / (RAND_MAX 1.0f); p.z 1024.0f * rand() / (RAND_MAX 1.0f); } } // 用 QVTKOpenGLNativeWidget 承载 PCLVisualizer QVTKOpenGLNativeWidget* widget new QVTKOpenGLNativeWidget; auto renderWindow vtkSmartPointervtkGenericOpenGLRenderWindow::New(); widget-setRenderWindow(renderWindow); auto viewer new pcl::visualization::PCLVisualizer(viewer, false); viewer-setRenderWindow(renderWindow); viewer-addPointCloudpcl::PointXYZ(cloud, sample); viewer-setPointCloudRenderingProperties( pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, sample); widget-resize(800, 600); widget-show(); return app.exec(); }这段代码的关键是QVTKOpenGLNativeWidget和vtkGenericOpenGLRenderWindow的配合。PCLVisualizer 的构造函数第二个参数传false表示不自己创建窗口而是用外部传入的 render window。如果传truePCL 会自己弹一个独立窗口和 Qt 的界面分离这不是我们想要的。7.2 编译和运行CMakeLists 里加上 VTK 的 Qt 模块find_package(VTK REQUIRED COMPONENTS CommonCore CommonDataModel RenderingCore RenderingOpenGL2 GUISupportQt InteractionStyle ) target_link_libraries(PCLQtDemo ${VTK_LIBRARIES})GUISupportQt提供QVTKOpenGLNativeWidgetRenderingOpenGL2是渲染后端。如果链接时报vtkRenderingOpenGL2找不到检查 VTK 编译时VTK_GROUP_ENABLE_Rendering是不是YES。运行后应该能看到一个 Qt 窗口里面显示随机点云。鼠标左键旋转、滚轮缩放、中键平移。如果窗口全黑先检查显卡驱动再确认 VTK 的 OpenGL 后端是不是OpenGL2而不是OpenGL。7.3 进阶把 PCL 可视化嵌入 Qt 布局上面的 Demo 是独立窗口实际项目里通常要把点云视图嵌到主窗口的某个区域。做法是把QVTKOpenGLNativeWidget作为一个普通 QWidget 加到布局里// mainwindow.cpp MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) { QWidget* central new QWidget; QVBoxLayout* layout new QVBoxLayout(central); m_vtkWidget new QVTKOpenGLNativeWidget; layout-addWidget(m_vtkWidget); QPushButton* btn new QPushButton(重置视角); layout-addWidget(btn); setCentralWidget(central); auto renderWindow vtkSmartPointervtkGenericOpenGLRenderWindow::New(); m_vtkWidget-setRenderWindow(renderWindow); m_viewer.reset(new pcl::visualization::PCLVisualizer(viewer, false)); m_viewer-setRenderWindow(renderWindow); connect(btn, QPushButton::clicked, this, [this]() { m_viewer-resetCamera(); m_vtkWidget-renderWindow()-Render(); }); }resetCamera后必须手动调Render()否则界面不刷新。这是 PCLVisualizer 和原生 VTK 的一个差异PCL 的spinOnce在嵌入模式下不生效得直接操作 render window。7.4 一个我每次都会做的检查从那以后我每次编完 PCL都会先跑一个只读 PCD 文件、不做任何可视化的小程序确认pcl::io和pcl::common链接正常再跑可视化。因为可视化依赖 VTKVTK 的问题会掩盖 PCL 本身的问题。先验证基础模块再验证可视化排查范围能小一半。希望帮到你。本文还有配套的精品资源点击获取