2、点云数据预处理:体素滤波降采样、直通滤波、统计滤波去噪、点云可视化
各位同学,咱们今天聊聊点云预处理。说实话,很多刚入行的朋友拿到激光雷达数据,直接就往匹配算法里塞,结果跑出来的结果惨不忍睹。我当年也干过这种傻事——数据量太大,内存直接爆了,程序卡死,气得我差点砸键盘。
点云预处理,说白了就是给数据「洗个澡」。原始点云里啥都有:远处的噪声点、地面反射的杂波、甚至飞鸟打过来的回波。你不处理干净,后面的匹配精度就别想了。今天咱们重点讲四个操作:体素滤波、直通滤波、统计滤波,还有可视化。
核心思路:先降采样减少数据量,再切掉无用区域,最后剔除离群噪声点。三步走完,数据就清爽多了。
2.1 体素滤波降采样
体素滤波,我习惯叫它「点云瘦身术」。原理很简单:把三维空间切成一个个小立方体(体素),每个立方体里只保留一个点——通常是重心点或者中心点。
你想想看,原始点云可能有几十万甚至上百万个点,但很多点其实是冗余的。比如一面墙,你扫了10万个点,其实1000个点就能描述清楚它的位置。体素滤波就是干这个的。
我的经验:体素大小选多少合适?一般0.1m~0.5m之间。城区道路场景我常用0.2m,高速场景可以放宽到0.3m。太小了降采样效果不明显,太大了会丢失细节结构。
代码实现也很直接,用PCL库的话几行就搞定:
// C++ PCL 体素滤波示例
pcl::VoxelGrid<pcl::PointXYZ> voxel_filter;
voxel_filter.setInputCloud(cloud);
voxel_filter.setLeafSize(0.2f, 0.2f, 0.2f); // 体素边长0.2米
voxel_filter.filter(*cloud_filtered);
嗯,这里要注意:体素大小不是越小越好。我见过有人设成0.01m,结果降完还有几十万个点,等于没降。反过来,设成1m的话,一堵墙可能就剩两三个点了,匹配时根本对不准。
2.2 直通滤波
直通滤波,说白了就是「切一刀」。激光雷达扫出来的数据范围很大,但咱们关心的往往只是某个区域。比如自动驾驶场景,车前方50米内的点云才有意义,再远的点要么是噪声,要么是天空。
直通滤波就是沿着某个坐标轴(X、Y或Z)设定一个范围,范围外的点全部扔掉。我一般在Z轴(高度)上先切一刀——把地面以上的点保留,地面以下的点(比如路面反射的杂波)直接过滤掉。
避坑指南:我曾经在高速项目上吃过亏——直通滤波的阈值设得太紧,把路牌和 overhead gantry(龙门架)的点云也切掉了,导致定位时缺少关键特征。后来我学乖了,阈值留10%~20%的余量。
代码示例:
// 直通滤波:只保留Z轴 -1.5m 到 3.0m 范围内的点
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud(cloud);
pass.setFilterFieldName("z");
pass.setFilterLimits(-1.5, 3.0);
pass.filter(*cloud_filtered);
为什么选-1.5到3.0?因为激光雷达一般装在车顶,地面在Z=0附近,-1.5m能滤掉地面以下的噪声,3.0m以上基本就是树枝、路灯杆的顶部了。当然,具体数值得根据你的安装高度来调。
2.3 统计滤波去噪
统计滤波,这是我最喜欢的一步。它专门对付那些「孤魂野鬼」——离群点。比如激光打到玻璃上产生的异常回波,或者远处飘来的一个孤立点。
原理也不复杂:对每个点,计算它到最近K个邻居的平均距离。如果这个距离太大(超过均值+若干倍标准差),就判定为离群点,直接干掉。
我习惯用K=50,标准差倍数设为1.0。为什么是50?太少的话统计意义不大,太多的话计算量上去了。标准差倍数1.0意味着只保留距离在均值±1σ范围内的点,比较严格。
关键参数:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| K(邻居数) | 30~100 | 点数少时用小值,点数多时用大值 |
| 标准差倍数 | 0.5~2.0 | 越小越严格,去噪越狠 |
// 统计滤波去噪
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
sor.setInputCloud(cloud);
sor.setMeanK(50); // 50个最近邻
sor.setStddevMulThresh(1.0); // 标准差倍数
sor.filter(*cloud_filtered);
我记得有一次做园区低速场景,点云里总有一些飘忽不定的噪声点,匹配结果时好时坏。排查了半天,发现是路边的灌木丛被风吹动产生的。统计滤波一上,这些点全被干掉了,匹配稳定多了。
2.4 点云可视化
预处理做完了,怎么看效果?可视化呗。我强烈建议每做完一步都看一眼结果,别等到最后才发现数据有问题。
PCL自带的可视化工具就挺好用:
// 可视化原始点云和滤波后的点云对比
pcl::visualization::PCLVisualizer viewer("点云预处理效果");
int v1(0), v2(1);
viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);
viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);
viewer.addPointCloud(cloud_original, "original", v1);
viewer.addPointCloud(cloud_filtered, "filtered", v2);
while (!viewer.wasStopped()) {
viewer.spinOnce();
}
左边显示原始点云,右边显示处理后的。你一眼就能看出:原始点云密密麻麻,滤波后稀疏了很多,但关键结构(比如建筑物轮廓、路沿)都还在。如果发现重要特征被误删了,赶紧回去调参数。
小技巧:可视化时把点的大小设成2~3像素,颜色按高度着色(Z轴)。这样能更清楚地看到地面、车辆、树木的层次关系。我习惯用彩虹色映射,红色代表高处,蓝色代表低处。
好了,点云预处理这块就讲这么多。体素滤波降采样、直通滤波切区域、统计滤波去噪声、可视化验证效果——四步走完,你的点云数据就干净利落了。后面做匹配的时候,你会发现计算速度快了不少,精度也上去了。
记住一句话:预处理花的时间,会在后面十倍百倍地省回来。别偷懒,每一步都认真做。