4. 直通滤波(PassThrough):原理讲解、沿X/Y/Z轴裁剪、代码实现与参数调优
直通滤波,名字听着挺唬人,其实说白了就是一刀切。
你想想看,我们拿激光雷达或者深度相机扫一圈,经常能扫到一大堆没用的点。比如天花板上的点、地面上的点,或者远处飘着的噪声点。这些点留着干嘛?占内存不说,还拖慢后续处理的速度。
直通滤波就是干这个的——沿着某个坐标轴,设定一个范围,范围内的点留下,范围外的统统干掉。就这么简单粗暴。
4.1 原理:其实就是一把尺子
直通滤波的原理,我可以用一句话讲清楚:指定一个轴,设一个上下限,然后遍历所有点,判断这个轴上的坐标是否在区间内。
举个例子。你有一堆点云,想保留Z轴在0.5米到2.0米之间的点。那代码就会这么干:
for each point in cloud:
if 0.5 <= point.z <= 2.0:
keep this point
else:
discard this point
没了。真的就这么简单。
但你别小看它。我在做AGV小车导航的时候,就靠这一招把地面反射的噪声点全滤掉了。地面上的点对建图没啥用,反而会让平面检测出问题。一刀切掉,世界清净了。
核心思想:直通滤波的本质是一维区间判断。它不关心点的邻居关系,也不管点的密度分布,只看单个坐标值。
4.2 沿X/Y/Z轴裁剪:选对轴很重要
直通滤波可以沿着X、Y、Z三个轴分别做,也可以组合着做。我个人的习惯是:
- 沿Z轴裁剪:最常用。用来去掉地面点和天花板点。比如室内机器人,地面高度设为0,那Z < 0.1的点基本就是地面噪声。
- 沿X轴裁剪:适合去掉机器人前方太远或太近的点。比如我只关心前方5米到20米范围内的障碍物。
- 沿Y轴裁剪:用来限制横向视野。比如在狭窄走廊里,把左右墙壁之外的点切掉,减少计算量。
我记得有一次做室外场景的定位,激光雷达扫到了50米外的树。那些点对定位毫无帮助,反而让匹配算法跑偏。我直接沿X轴设了个30米的阈值,后面的点全切了。效果立竿见影。
组合使用也很常见。比如先沿Z轴去掉地面,再沿X轴限制前方距离。相当于用三个筛子筛一遍。
4.3 代码实现:PCL里怎么用
PCL(Point Cloud Library)里直通滤波的实现非常直接。我直接上代码:
#include <pcl/filters/passthrough.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
// 加载点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("input.pcd", *cloud);
// 创建直通滤波对象
pcl::PassThrough<pcl::PointXYZ> pass;
// 设置输入点云
pass.setInputCloud(cloud);
// 设置滤波轴为Z轴
pass.setFilterFieldName("z");
// 设置范围:保留Z在0.5到2.0之间的点
pass.setFilterLimits(0.5, 2.0);
// 默认保留范围内的点,也可以取反
// pass.setFilterLimitsNegative(true); // 保留范围外的点
// 执行滤波
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
pass.filter(*cloud_filtered);
// 保存结果
pcl::io::savePCDFile("filtered.pcd", *cloud_filtered);
这段代码,你直接复制就能跑。唯一要注意的是setFilterFieldName的参数,可以是"x"、"y"、"z",大小写敏感。
小技巧:如果你想把多个轴组合起来用,那就创建多个PassThrough对象,一个接一个地filter。PCL没有提供一次性多轴滤波的接口,但串起来用效果一样。
4.4 参数调优:别让一刀切坏了事
直通滤波的参数就两个:轴和范围。但调起来还是有讲究的。
| 参数 | 说明 | 调优建议 |
|---|---|---|
| filterFieldName | 滤波轴(x/y/z) | 根据场景选。地面噪声用z,远处噪声用x |
| filterLimits | 范围[min, max] | 别设太紧,留点余量。比如地面高度0.1,设0.15更安全 |
| setFilterLimitsNegative | 是否取反 | 默认false。设为true可以保留范围外的点 |
我曾经犯过一个错。做室内建图时,我把Z轴下限设成了0.0,想着地面点全干掉。结果机器人稍微颠簸一下,激光雷达的Z值就变成了负数,把有用的点也滤掉了。后来我改成0.05,留了点余量,问题就解决了。
避坑指南:直通滤波会改变点云的数量和顺序。如果你后续要做基于索引的操作(比如点云配准时的对应点查找),记得保存原始索引。PCL的PassThrough提供了setKeepOrganized(true)选项,可以保留点云结构,但会把滤掉的点设为NaN。
4.5 知识体系:一张图看懂
下面这张SVG图,把直通滤波的核心逻辑画清楚了。从输入到输出,中间就一个判断:坐标在不在范围内。
你看,整个流程就这么清晰。输入一堆点,经过一个判断框,输出一堆更少的点。没有花里胡哨的东西。
4.6 实际项目中的经验
最后分享一点实战经验。
直通滤波虽然简单,但用好了能省很多事。我做过一个项目,点云数据量特别大,每秒几十万个点。直接做聚类或者分割,CPU直接拉满。后来我先用直通滤波把明显没用的区域切掉,数据量直接降到原来的十分之一。后面的算法跑得飞快。
但也要注意,直通滤波是有损的。切掉的点就再也回不来了。所以调参的时候,宁可范围设大一点,也别切过头。我一般会先看直方图,了解点云在某个轴上的分布,再决定阈值。
嗯,直通滤波就讲这么多。下一刀切哪里,你自己看着办。