第76章:PCL:集成PCL点云库

点云处理,说白了就是让计算机理解三维世界。PCL(Point Cloud Library)是目前最流行的开源点云库之一。我最早接触PCL是在做机器人导航项目时,当时需要处理激光雷达的数据,嗯,那会儿真是被编译折腾得够呛。

这一章,我就带你搞定PCL的CMake集成。咱们不搞花架子,直接上干货。

为什么需要PCL?

你想想看,如果你要处理三维点云数据,从滤波、分割到配准、识别,自己从头写?那得写到猴年马月去。PCL把这些都封装好了,你只需要调用API就行。

我个人习惯把PCL看作「三维世界的OpenCV」。它提供了:

  • 点云数据的读写(PCD、PLY等格式)
  • 滤波算法(直通滤波、体素滤波、统计滤波)
  • 特征提取(法线、PFH、FPFH等)
  • 点云配准(ICP、NDT等)
  • 分割算法(RANSAC、欧式聚类等)

PCL的模块结构

PCL不是一个大而全的库,它分了很多子模块。我在项目中遇到过最头疼的事,就是不知道到底该链接哪个模块。下面这张图帮你理清关系:

PCL核心模块结构 PCL核心 (pcl_common) pcl_io(文件读写) pcl_kdtree(空间索引) pcl_octree(八叉树) pcl_filters(滤波) pcl_features(特征) pcl_segmentation(分割) pcl_registration(配准) pcl_surface(曲面重建) pcl_visualization(可视化) pcl_ml(机器学习) 每个模块可独立链接,按需引入即可 依赖方向:上层依赖下层

CMake集成PCL的标准姿势

PCL官方提供了CMake配置文件,用find_package就能搞定。但这里有个坑——PCL依赖很多第三方库,比如Boost、Eigen、FLANN、VTK等。我曾经在Ubuntu 18.04上折腾了一下午,就是因为VTK版本不兼容。

核心思路:用find_package找到PCL,然后链接你需要的组件。

先看一个最基础的CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(pcl_demo)

# 设置C++标准
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 找PCL - 这里指定了需要的组件
find_package(PCL REQUIRED COMPONENTS
    common
    io
    filters
    segmentation
    visualization
)

# 如果没找到,直接报错
if(NOT PCL_FOUND)
    message(FATAL_ERROR "PCL not found! 请先安装PCL库")
endif()

# 包含头文件
include_directories(${PCL_INCLUDE_DIRS})

# 添加可执行文件
add_executable(pcl_demo main.cpp)

# 链接PCL库
target_link_libraries(pcl_demo ${PCL_LIBRARIES})

小提示:PCL_FOUND、PCL_INCLUDE_DIRS、PCL_LIBRARIES 这些变量是find_package自动设置的。你不需要手动拼路径。

实战:点云滤波示例

光说不练假把式。咱们写一个实际例子:读取点云文件,做体素滤波降采样,然后保存结果。

// main.cpp
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>

int main(int argc, char** argv) {
    // 检查参数
    if (argc != 3) {
        std::cerr << "用法: " << argv[0] 
                  << " input.pcd output.pcd" << std::endl;
        return -1;
    }

    // 创建点云对象
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
        new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(
        new pcl::PointCloud<pcl::PointXYZ>);

    // 读取点云
    if (pcl::io::loadPCDFile(argv[1], *cloud) == -1) {
        PCL_ERROR("读取点云文件失败\n");
        return -1;
    }
    std::cout << "原始点云点数: " << cloud->size() << std::endl;

    // 创建体素滤波器
    pcl::VoxelGrid<pcl::PointXYZ> sor;
    sor.setInputCloud(cloud);
    sor.setLeafSize(0.01f, 0.01f, 0.01f);  // 1cm体素
    sor.filter(*cloud_filtered);

    std::cout << "滤波后点云点数: " << cloud_filtered->size() << std::endl;

    // 保存结果
    pcl::io::savePCDFileASCII(argv[2], *cloud_filtered);
    std::cout << "结果已保存到: " << argv[2] << std::endl;

    return 0;
}

进阶:按需链接组件

有些同学喜欢图省事,直接find_package(PCL REQUIRED)不加COMPONENTS。这样会链接所有模块,编译慢不说,生成的可执行文件也大。

我建议你只链接真正用到的组件。比如上面的例子只用到了common、io和filters,那就只写这三个:

find_package(PCL REQUIRED COMPONENTS common io filters)

这样CMake只会去查找这三个模块的库文件,省时省力。

避坑指南

我曾经踩过的坑:

  • Boost版本冲突:PCL 1.8要求Boost 1.65以下,如果你系统装了Boost 1.71,编译会报一堆模板错误。解决方案是用PCL 1.12以上版本,或者手动指定Boost版本。
  • VTK OpenGL2问题:新版本VTK默认用OpenGL2,但PCL可视化模块可能还依赖旧版OpenGL。我在Ubuntu 20.04上遇到过,加个-DVTK_OPENGL2_BACKEND=OpenGL2就好了。
  • Debug/Release混用:PCL的Debug库和Release库不能混用。如果你编译Debug版本,确保链接的也是PCL的Debug库。

安装PCL的快速指南

不同平台安装方式不同,我列个表方便你参考:

平台 安装命令 备注
Ubuntu 18.04 sudo apt install libpcl-dev 默认PCL 1.8.1
Ubuntu 20.04 sudo apt install libpcl-dev 默认PCL 1.10
macOS brew install pcl 需要先装Xcode
Windows vcpkg install pcl 或者用预编译包

个人建议:如果你刚开始学PCL,用Ubuntu 20.04 + apt安装最省心。Windows上编译PCL源码?嗯,那酸爽,我试过一次就不想试第二次了。

验证集成是否成功

写个简单的测试程序,编译运行看看:

# 创建构建目录
mkdir build && cd build

# 配置
cmake ..

# 编译
make -j4

# 运行(需要准备一个test.pcd文件)
./pcl_demo test.pcd output.pcd

如果一切顺利,你会看到类似这样的输出:

原始点云点数: 123456
滤波后点云点数: 23456
结果已保存到: output.pcd

点云数量大幅减少,说明体素滤波生效了。嗯,这就是PCL集成的完整流程。

记住,PCL的CMake集成核心就三步:find_package找到它,include_directories包含头文件,target_link_libraries链接库。搞懂了这三步,其他第三方库的集成思路也差不多。


公众号:蓝海资料掘金营,微信deep3321