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图,把直通滤波的核心逻辑画清楚了。从输入到输出,中间就一个判断:坐标在不在范围内。

原始点云 直通滤波 沿指定轴 判断坐标范围 滤波后点云 关键参数 轴(x/y/z) | 范围[min, max] | 是否取反

你看,整个流程就这么清晰。输入一堆点,经过一个判断框,输出一堆更少的点。没有花里胡哨的东西。

4.6 实际项目中的经验

最后分享一点实战经验。

直通滤波虽然简单,但用好了能省很多事。我做过一个项目,点云数据量特别大,每秒几十万个点。直接做聚类或者分割,CPU直接拉满。后来我先用直通滤波把明显没用的区域切掉,数据量直接降到原来的十分之一。后面的算法跑得飞快。

但也要注意,直通滤波是有损的。切掉的点就再也回不来了。所以调参的时候,宁可范围设大一点,也别切过头。我一般会先看直方图,了解点云在某个轴上的分布,再决定阈值。

嗯,直通滤波就讲这么多。下一刀切哪里,你自己看着办。

可可精品资料库