第4章:点云预处理实战:体素滤波、统计滤波、半径滤波,去除离群点与下采样

点云数据拿到手,第一件事是什么?

不是急着做配准,也不是急着做分割。我个人的习惯是——先做预处理。为什么?因为原始点云太“脏”了。传感器噪声、环境干扰、远距离的飘点……这些乱七八糟的东西如果不处理掉,后面所有的算法都会被带偏。

说白了,预处理就是给点云“洗个澡”。洗完之后,数据干净了,计算量也小了,后面的活儿才好干。

4.1 为什么要做点云预处理?

你想想看,一个激光雷达扫一圈,可能产生几十万个点。这里面有多少是真正有用的?

  • 离群点:莫名其妙飘在空中的点,可能是传感器误触发的。
  • 噪声点:物体边缘的抖动、反射干扰造成的。
  • 冗余点:平坦地面上密密麻麻的点,其实几个点就能代表。

我在项目中遇到过最夸张的一次,一个室内扫描的点云,离群点占了将近15%。如果不滤掉,后续的平面拟合直接跑偏。嗯,从那以后我再也不敢跳过预处理了。

核心目标:

  • 去除噪声和离群点,提高数据质量
  • 降低点云密度,减少计算量
  • 保持几何结构不变,不破坏关键特征

4.2 三种滤波方法详解

预处理主要靠三种滤波:体素滤波、统计滤波、半径滤波。它们各管一摊,配合使用效果最好。

4.2.1 体素滤波(Voxel Grid Filter)—— 下采样的主力

体素滤波说白了就是“降采样”。它把空间划分成一个个小立方体(体素),每个体素内只保留一个点(通常是重心点)。

这样做的好处很明显:点云密度均匀了,计算量大幅下降。我习惯把体素大小设为0.01m~0.05m,具体看场景。如果是室内小物体,0.01m就够了;如果是室外大场景,0.05m更合适。

我的经验:体素大小不要设得太小,否则降采样效果不明显。也不要太大,否则会丢失细节。0.02m是个不错的起点。

// C++ PCL 示例:体素滤波
pcl::VoxelGrid<pcl::PointXYZ> voxel_filter;
voxel_filter.setInputCloud(cloud);
voxel_filter.setLeafSize(0.02f, 0.02f, 0.02f); // 体素大小 2cm
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
voxel_filter.filter(*cloud_filtered);

4.2.2 统计滤波(Statistical Outlier Removal)—— 去离群点的利器

统计滤波的原理很简单:计算每个点到它K个近邻的平均距离。如果这个距离超出了全局平均距离的某个倍数(标准差倍数),就判定为离群点。

为什么会这样?因为离群点通常孤零零的,周围没什么邻居,平均距离自然就大。

我记得有一次做室外道路点云处理,统计滤波帮我清掉了所有飘在空中的树叶点。参数设置上,我一般取K=50,标准差倍数设为1.0~2.0。倍数越小,滤掉的点越多。

注意:标准差倍数设得太小(比如0.5),会把正常点也滤掉。设得太大(比如3.0),离群点又滤不干净。建议先试1.0,看效果再调。

// C++ PCL 示例:统计滤波
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
sor.setInputCloud(cloud);
sor.setMeanK(50);          // 近邻点数
sor.setStddevMulThresh(1.0); // 标准差倍数
sor.filter(*cloud_filtered);

4.2.3 半径滤波(Radius Outlier Removal)—— 另一种去噪思路

半径滤波和统计滤波有点像,但判断标准不同。它检查每个点周围指定半径内是否有足够多的邻居。如果邻居数量少于阈值,就干掉它。

这个滤波器对稀疏的离群点特别有效。我曾经用它处理过激光雷达扫描的墙角点云,那些因为反射角度问题产生的孤立点,半径滤波一把就清干净了。

// C++ PCL 示例:半径滤波
pcl::RadiusOutlierRemoval<pcl::PointXYZ> ror;
ror.setInputCloud(cloud);
ror.setRadiusSearch(0.05);   // 搜索半径 5cm
ror.setMinNeighborsInRadius(10); // 最少邻居数
ror.filter(*cloud_filtered);

4.3 三种滤波对比

滤波方法 主要用途 关键参数 适用场景
体素滤波 下采样,降低密度 体素大小 所有场景,尤其是大场景
统计滤波 去除离群点 K近邻数、标准差倍数 噪声均匀的场景
半径滤波 去除稀疏离群点 搜索半径、最少邻居数 孤立点较多的场景

4.4 实战流程:先滤波,再下采样

在实际项目中,我通常按这个顺序来:

  1. 先统计滤波或半径滤波:把明显的离群点干掉。
  2. 再体素滤波:把干净的点云降采样,降低计算量。

为什么要先滤波再下采样?你想想看,如果先下采样,离群点还在里面,只是密度变低了。后面再做滤波,效果会打折扣。我曾经犯过这个错,后来就记住了。

推荐流程:

原始点云 → 统计滤波(去噪) → 体素滤波(降采样) → 干净点云

4.5 知识体系总览

下面这张图把本章的核心逻辑串起来了。你可以看到,预处理不是随便选一个滤波就完事,而是有策略的。

点云预处理知识体系 原始点云 去噪阶段:统计滤波 / 半径滤波 下采样阶段:体素滤波 干净点云 注:先滤波去噪,再下采样降密度,顺序不可颠倒。

4.6 避坑指南

做点云预处理这些年,我踩过不少坑。分享几个给你:

我曾经犯过的错:

  • 体素滤波参数设得太大,结果把物体的棱角都磨平了,后续特征提取全废。
  • 统计滤波的标准差倍数设得太小,把正常的地面点也滤掉了,导致地面拟合缺了一块。
  • 半径滤波的搜索半径设得太小,离群点一个都没滤掉,白跑一趟。

嗯,这些坑你记住了,就能少走弯路。预处理做好了,后面的配准、分割、识别才能稳稳当当。

我的建议:每次调参后,用可视化工具看一眼效果。别光看数据,眼睛比数字靠谱。


专注资料整理