第1章:PCL点云库入门
各位同学,欢迎来到《点云滤波与IMU融合定位算法实战》的第一课。
说实话,每次带新人入门点云处理,我都要先问一句:「你装好PCL了吗?」
PCL,全称Point Cloud Library,是点云处理领域最常用的开源库。我做了这么多年SLAM,几乎每个项目都离不开它。今天咱们就花一章的时间,把PCL的核心模块、数据结构和可视化工具捋一遍。
1.1 PCL核心模块介绍
PCL的模块划分得很清晰。我个人习惯把它分成三大块:滤波、配准、分割。当然还有别的模块,但这三个是咱们做SLAM最常用的。
1.1.1 滤波模块
滤波是点云预处理的第一步。你想想看,激光雷达扫出来的原始点云,噪声多、离群点多、数据量大,直接拿来用肯定不行。
PCL的滤波模块提供了很多滤波器,我挑几个常用的说说:
- 直通滤波器(PassThrough):按坐标轴范围裁剪点云。比如我只想保留前方10米内的点,设个x轴范围就行。
- 体素滤波器(VoxelGrid):下采样用的。把空间划分成小立方体,每个立方体只保留一个重心点。数据量能降一个数量级。
- 统计滤波器(StatisticalOutlierRemoval):去除离群点。计算每个点邻域的统计特征,把偏离太远的点干掉。
- 半径滤波器(RadiusOutlierRemoval):如果某个点周围指定半径内点数太少,就认为是噪声。
1.1.2 配准模块
配准,说白了就是把两片点云对齐。这在SLAM里太重要了——你要把当前帧和地图对齐,才能知道自己在哪。
PCL配准模块的核心算法:
- ICP(Iterative Closest Point):最经典的配准算法。迭代找最近点,计算变换矩阵。收敛慢,但精度高。
- NDT(Normal Distributions Transform):把点云用正态分布表示,配准速度比ICP快很多。我在做自动驾驶定位时特别喜欢用NDT。
- 特征匹配配准:先提取特征点(如FPFH、SHOT),再匹配特征,最后用RANSAC求变换。适合粗配准。
1.1.3 分割模块
分割就是把点云分成不同的物体或区域。比如从一堆点里把地面、墙壁、行人分开。
常用的分割方法:
- 平面分割(RANSAC):用随机采样一致性算法拟合平面。提取地面、墙面特别好用。
- 欧几里得聚类(EuclideanClusterExtraction):根据点之间的距离聚类。适合分离独立的物体。
- 区域生长(RegionGrowing):基于法向量和曲率,把相似的点聚在一起。
1.2 PCL数据结构
学PCL,首先要搞懂它的数据结构。说白了,就是怎么存点云。
1.2.1 PointCloud
pcl::PointCloud 是PCL最核心的数据结构。它本质上是一个模板类,里面存了一堆点。
关键成员:
points:点数据的vector,存了所有点。width和height:如果是有序点云,width是每行点数,height是行数;无序点云height=1。is_dense:标记是否有无效点(NaN)。
// 创建一个PointCloud对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 设置点云属性
cloud->width = 1000;
cloud->height = 1; // 无序点云
cloud->is_dense = false;
cloud->points.resize(cloud->width * cloud->height);
// 填充点数据
for (size_t i = 0; i < cloud->points.size(); ++i) {
cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
}
1.2.2 PointXYZ
pcl::PointXYZ 是最基础的点类型,只包含x、y、z三个坐标。你想想看,大部分场景下我们只需要位置信息,这就够了。
其他常用点类型:
| 点类型 | 包含字段 | 适用场景 |
|---|---|---|
| PointXYZ | x, y, z | 纯几何位置 |
| PointXYZRGB | x, y, z, r, g, b | 带颜色信息的点云 |
| PointXYZI | x, y, z, intensity | 激光雷达强度数据 |
| PointNormal | x, y, z, normal_x, normal_y, normal_z, curvature | 需要法向量和曲率 |
pcl::PointCloud 的模板参数。你可以自定义点类型,但建议优先用PCL自带的,兼容性更好。
1.3 PCL可视化工具
做点云处理,可视化太重要了。你看不到数据,怎么调试?PCL提供了两个可视化工具:CloudViewer 和 PCLVisualizer。
1.3.1 CloudViewer
CloudViewer 是最简单的可视化类。适合快速看一眼点云长什么样。
#include <pcl/visualization/cloud_viewer.h>
// 创建viewer对象
pcl::visualization::CloudViewer viewer("Simple Cloud Viewer");
// 显示点云
viewer.showCloud(cloud);
// 保持窗口打开
while (!viewer.wasStopped()) {
// 可以在这里做其他处理
}
嗯,就这么几行代码,你就能看到点云了。但 CloudViewer 功能有限,不能添加多个点云、不能交互。
1.3.2 PCLVisualizer
如果你需要更复杂的可视化,用 PCLVisualizer。它支持:
- 同时显示多个点云
- 添加坐标轴、文字、形状
- 鼠标交互(旋转、缩放、选点)
- 回调函数(比如点击点云获取坐标)
#include <pcl/visualization/pcl_visualizer.h>
// 创建PCLVisualizer
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0); // 黑色背景
// 添加点云
viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
// 添加坐标轴
viewer->addCoordinateSystem(1.0);
// 设置视角
viewer->initCameraParameters();
// 循环显示
while (!viewer->wasStopped()) {
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
PCLVisualizer,因为它可以同时显示原始点云和滤波后的点云,方便对比效果。我曾经在调试地面分割时,把原始点云设成白色,地面点设成绿色,非地面点设成红色,一眼就能看出分割效果好不好。
本章知识体系
下面这张图,是我自己画的PCL入门知识结构。你看一眼,心里就有数了。
好了,第一章的内容就到这里。PCL入门其实不难,关键是动手敲代码。我建议你今晚就把上面的代码示例跑一遍,看看点云长什么样。
记住,做SLAM,数据结构和可视化是基本功。后面几章我们会深入滤波和配准,到时候这些基础就派上用场了。
- 创建一个包含1000个随机点的PointCloud,用CloudViewer显示出来。
- 用PCLVisualizer同时显示两个不同颜色的点云。
- 尝试用PassThrough滤波器裁剪点云,观察效果。