第76章:PCL:集成PCL点云库
点云处理,说白了就是让计算机理解三维世界。PCL(Point Cloud Library)是目前最流行的开源点云库之一。我最早接触PCL是在做机器人导航项目时,当时需要处理激光雷达的数据,嗯,那会儿真是被编译折腾得够呛。
这一章,我就带你搞定PCL的CMake集成。咱们不搞花架子,直接上干货。
为什么需要PCL?
你想想看,如果你要处理三维点云数据,从滤波、分割到配准、识别,自己从头写?那得写到猴年马月去。PCL把这些都封装好了,你只需要调用API就行。
我个人习惯把PCL看作「三维世界的OpenCV」。它提供了:
- 点云数据的读写(PCD、PLY等格式)
- 滤波算法(直通滤波、体素滤波、统计滤波)
- 特征提取(法线、PFH、FPFH等)
- 点云配准(ICP、NDT等)
- 分割算法(RANSAC、欧式聚类等)
PCL的模块结构
PCL不是一个大而全的库,它分了很多子模块。我在项目中遇到过最头疼的事,就是不知道到底该链接哪个模块。下面这张图帮你理清关系:
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链接库。搞懂了这三步,其他第三方库的集成思路也差不多。