3. 体素滤波(VoxelGrid):下采样原理、体素大小对点云密度的影响、参数选择策略
3.1 体素滤波到底在干什么?
体素滤波,说白了就是用一个个小立方体去“框”你的点云。
你想象一下,把整个三维空间切成无数个均匀的小格子。每个格子里可能有好几个点,也可能一个都没有。体素滤波要做的,就是每个格子里只保留一个点,其他的全扔掉。
这个“保留一个点”的方式,最常见的是取格子内所有点的重心。也有取中心点的,但我个人习惯用重心,因为更贴近原始数据的分布。
嗯,这里要注意:体素滤波不是简单的随机抽点。它是结构化的下采样,能很好地保留点云的几何形状。
3.2 体素大小——这个参数有多关键?
体素大小,就是那个小立方体的边长。它直接决定了你下采样后的点云长什么样。
我举个例子你就明白了:
- 体素太小(比如 0.01m):每个格子几乎只框住一两个点,下采样效果微乎其微。点云还是那么密,计算量没降下来。
- 体素太大(比如 0.5m):一个格子里可能框住几百上千个点,最后只保留一个。点云瞬间变得稀疏,细节全丢了。
- 体素适中(比如 0.05m):既能有效降采样,又能保留主要结构。这是我最常用的范围。
核心结论:体素大小直接控制输出点云的密度。体素越大,输出点越少;体素越小,输出点越密。这个关系是单调的,但不是线性的。
3.3 体素大小对点云密度的影响——我踩过的坑
我在做室内SLAM的时候遇到过一个问题。当时用16线激光雷达扫描一个房间,原始点云大概有30万个点。我想着下采样到5万个点左右,就随手设了个0.1m的体素。
结果你猜怎么着?
输出点云只剩1.2万个了。墙面上的点稀稀拉拉,墙角都看不清楚了。后来我才意识到,室内环境点云分布不均匀——墙面上的点本来就密,一个0.1m的格子里可能框了50个点;而空旷区域点本来就少,一个格子里可能只有两三个点。
体素滤波对所有区域一视同仁,结果就是密集区域被过度下采样,稀疏区域反而保留得还行。
所以我的建议是:先看看你的点云密度分布。如果分布很不均匀,可以考虑分区域设置不同的体素大小。或者用自适应体素滤波,不过那是后话了。
3.4 参数选择策略——实战经验总结
体素大小怎么选?我一般按这个思路来:
- 先看传感器:激光雷达的角分辨率决定了点云的基础密度。比如Velodyne VLP-16,水平分辨率0.1°-0.4°,在10米处点间距大概是1.7cm-7cm。体素大小至少要比这个间距大,否则没意义。
- 再看应用场景:
- 做配准(ICP、NDT):体素可以大一点,0.1m-0.2m都行,关键是保留几何特征。
- 做分割、识别:体素要小一点,0.02m-0.05m,细节不能丢。
- 做实时SLAM:体素大小取决于你的算力。我一般从0.05m开始试,不行再调大。
- 最后试出来:没有万能参数。我习惯先设一个值,跑一遍看看输出点云数量,再根据目标点数反推体素大小。
小技巧:如果你用PCL的pcl::VoxelGrid,可以设一个setLeafSize(0.05f, 0.05f, 0.05f)。然后打印一下输出点云的size(),看看是不是你想要的密度。不是的话,调大或调小,再试一次。一般试两三次就能找到合适的值。
3.5 代码示例——PCL中的体素滤波
给你看一段我常用的代码:
// 创建体素滤波对象
pcl::VoxelGrid<pcl::PointXYZ> voxel_filter;
// 设置输入点云
voxel_filter.setInputCloud(input_cloud);
// 设置体素大小——这里我设0.05m
voxel_filter.setLeafSize(0.05f, 0.05f, 0.05f);
// 执行滤波
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered_cloud(new pcl::PointCloud<pcl::PointXYZ>());
voxel_filter.filter(*filtered_cloud);
// 看看效果
std::cout << "原始点数: " << input_cloud->size() << std::endl;
std::cout << "滤波后点数: " << filtered_cloud->size() << std::endl;
这段代码很简单,但很实用。我每次做点云预处理都会用它。
3.6 体素滤波的核心逻辑——一张图看懂
下面这张图展示了体素滤波的完整流程:
3.7 避坑指南——我曾经犯过的错
我曾经踩过的坑,你千万别再踩:
- 体素设得太小,等于没滤波:有一次我设了0.005m的体素,结果输出点云只少了5%。白白浪费计算时间。
- 体素设得太大,把特征滤没了:做建筑物立面提取时,我设了0.3m的体素,结果窗户边缘全没了,提取出来的立面跟抹了水泥一样平。
- 忘了考虑点云的单位:有些数据集用毫米,有些用米。如果你用毫米单位设0.05,那体素就是0.05mm,等于没滤波。
- 对非均匀分布点云一刀切:前面说过了,室内场景点云分布极不均匀。我后来改用自适应体素滤波,效果好很多。
3.8 什么时候该用体素滤波?
说实话,体素滤波不是万能的。我一般这么判断:
| 场景 | 推荐使用 | 原因 |
|---|---|---|
| 点云配准前预处理 | ✅ 强烈推荐 | 减少计算量,同时保留几何结构 |
| 实时SLAM前端 | ✅ 推荐 | 控制帧率,保证实时性 |
| 点云分类/分割 | ⚠️ 谨慎使用 | 体素太大可能丢失细节特征 |
| 高精度三维重建 | ❌ 不推荐 | 会丢失边缘和细节信息 |
嗯,总结一下:体素滤波是点云处理的基本功。参数调优没有捷径,多试几次,多看看输出效果,慢慢就有感觉了。
我的个人习惯:每次调参前,先看一眼原始点云的密度分布。然后用一个经验值(比如0.05m)跑一遍,看输出点数。再根据目标点数,按比例调整体素大小。一般两三次就能找到合适的值。