2. 直通滤波:原理与实现、基于坐标轴的裁剪、在道路场景中的应用

2.1 直通滤波到底在干什么?

直通滤波,名字听着挺唬人,其实原理特别简单。

说白了,就是一刀切。

你想象一下,你面前有一堆散乱的点云数据。这些点分布在三维空间里,有X、Y、Z三个坐标值。直通滤波做的事情就是:指定一个坐标轴,设定一个范围,在这个范围之外的点,全部砍掉。

比如我只想要Z轴在-1米到1米之间的点,那其他高度的点,统统不要。就这么直接。

核心思想: 沿着某个坐标轴方向,设置一个「通过」的区间。区间内的点保留,区间外的点剔除。

我在做车载激光雷达项目时,经常用这招。为什么呢?因为原始点云数据量太大了,动不动几十万个点。直接处理太慢。先用直通滤波把明显没用的区域切掉,后续算法跑起来就快多了。

2.2 原理与实现:代码怎么写?

直通滤波的实现,本质上就是一个循环判断。遍历每个点,检查它的某个坐标值是否在阈值范围内。

我个人习惯用PCL库来做,它已经封装好了。但为了让你理解本质,我先给你看一个最朴素的实现思路:

// 伪代码:直通滤波核心逻辑
function passthrough_filter(point_cloud, axis, min_limit, max_limit):
    filtered_cloud = empty_cloud
    
    for each point in point_cloud:
        // 根据axis选择对应的坐标值
        if axis == 'x':
            value = point.x
        else if axis == 'y':
            value = point.y
        else if axis == 'z':
            value = point.z
        
        // 判断是否在范围内
        if value >= min_limit and value <= max_limit:
            filtered_cloud.add(point)
    
    return filtered_cloud

你看,逻辑就这么几行。但实际工程中,有几个坑需要注意。

避坑指南: 我曾经在项目里直接用PCL的直通滤波,没注意坐标系方向。结果把路面点全切掉了,留下了一堆空中飞行的噪点。后来才发现,我的激光雷达坐标系Z轴朝上,但我设的阈值是反的。所以,一定要先搞清楚你的传感器坐标系定义。

下面是PCL库中直通滤波的标准用法:

#include <pcl/filters/passthrough.h>

// 创建点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

// 假设cloud已经加载了数据

// 创建直通滤波对象
pcl::PassThrough<pcl::PointXYZ> pass;

pass.setInputCloud(cloud);           // 设置输入点云
pass.setFilterFieldName("z");        // 设置滤波轴:z轴
pass.setFilterLimits(-1.5, 0.5);     // 设置范围:-1.5米到0.5米
// pass.setFilterLimitsNegative(true); // 可选:取反,保留范围外的点

pass.filter(*cloud_filtered);        // 执行滤波

这里有个小技巧:setFilterLimitsNegative这个参数,默认是false。如果设为true,就变成了「保留范围之外的点」。我在做障碍物检测时,有时候需要剔除地面附近的点,就会用这个取反功能。

2.3 基于坐标轴的裁剪:不只是切一刀

直通滤波可以沿着X、Y、Z三个轴分别切。但实际应用中,我们经常需要组合使用。

举个例子。你想想看,一个道路场景,我们通常只关心前方一定范围内的障碍物。太远的点没用,太高的点可能是树冠或天桥,太低的是地面。

所以,常见的做法是:先沿Z轴切掉地面和天空,再沿Y轴切掉左右两侧的建筑物,最后沿X轴切掉太远的点。

这就相当于用三个平面,在三维空间里切出一个长方体区域。这个长方体,就是我们的感兴趣区域(ROI)。

我的经验: 多轴组合滤波时,顺序很重要。我一般先切Z轴,因为地面点和天空点数量最多,先去掉它们能大幅减少后续计算量。然后再切Y轴和X轴。这个顺序不是绝对的,但你可以试试,效果确实不一样。

下面是一个多轴组合滤波的代码示例:

// 第一步:Z轴滤波 - 去掉地面和天空
pcl::PassThrough<pcl::PointXYZ> pass_z;
pass_z.setInputCloud(cloud);
pass_z.setFilterFieldName("z");
pass_z.setFilterLimits(-1.0, 2.5);  // 保留高度-1米到2.5米的点
pass_z.filter(*cloud_filtered_z);

// 第二步:Y轴滤波 - 去掉左右两侧
pcl::PassThrough<pcl::PointXYZ> pass_y;
pass_y.setInputCloud(cloud_filtered_z);
pass_y.setFilterFieldName("y");
pass_y.setFilterLimits(-10.0, 10.0); // 保留左右各10米内的点
pass_y.filter(*cloud_filtered_y);

// 第三步:X轴滤波 - 去掉太远的点
pcl::PassThrough<pcl::PointXYZ> pass_x;
pass_x.setInputCloud(cloud_filtered_y);
pass_x.setFilterFieldName("x");
pass_x.setFilterLimits(0.0, 50.0);   // 保留前方0到50米的点
pass_x.filter(*cloud_filtered);

2.4 在道路场景中的应用:实战案例

好了,理论讲完了,咱们来看一个真实的道路场景应用。

我记得有一次做城市道路的自动驾驶项目。车辆在城市里跑,周围环境特别复杂。有行人、自行车、其他车辆、路边的树木、路灯杆、还有远处的建筑物。

原始点云数据长这样:

  • 总点数:约12万个
  • 范围:X轴 -50米到100米,Y轴 -40米到40米,Z轴 -2米到30米
  • 包含大量地面点、远处建筑物点、天空中的噪点

直接做障碍物检测?太慢了,而且误检率很高。我的做法是先用直通滤波做预处理。

第一步:确定ROI范围

根据车辆行驶场景,我设定了以下阈值:

坐标轴 最小值 最大值 说明
X(前进方向) -5米 60米 车后方5米到前方60米
Y(左右方向) -15米 15米 左右各15米,覆盖3-4个车道
Z(高度方向) -1.5米 3.0米 地面以下1.5米到车顶以上

第二步:执行滤波

按照刚才说的顺序,先Z后Y再X。滤波完成后,点云数量从12万降到了约3万个。减少了75%的数据量。

第三步:效果验证

滤波后的点云,只保留了道路范围内的障碍物点。远处的建筑物、天空中的噪点、大部分地面点都被去掉了。后续的聚类和障碍物检测,速度明显提升,误检率也降低了。

关键数据: 在这个项目中,直通滤波让后续算法的处理时间从120ms降到了35ms,帧率从8fps提升到了28fps。效果非常明显。

2.5 知识体系总览

为了让你更直观地理解本章的内容结构,我画了一张图:

直通滤波知识体系 核心原理 沿坐标轴设定范围,一刀切 原理与实现 遍历判断 + PCL封装 基于坐标轴的裁剪 多轴组合 + ROI提取 道路场景应用 预处理 + 降噪 + 提速 实现细节 • 单轴滤波:X/Y/Z • 阈值设定:min/max • 取反功能:保留外部 • 代码实现:PCL库 • 避坑:坐标系方向 裁剪策略 • 单轴裁剪:简单快速 • 多轴组合:长方体ROI • 滤波顺序:Z→Y→X • 参数调优:经验值 • 性能优化:减少数据量 实战案例 • 城市道路场景 • ROI设定:X/Y/Z阈值 • 数据量:12万→3万 • 处理时间:120ms→35ms • 帧率提升:8fps→28fps

2.6 一些补充建议

最后,再分享几个我在实际项目中积累的小经验:

  • 阈值不要设得太死。道路场景中,车辆会有颠簸,激光雷达也会有安装误差。留一点余量,比如Z轴下限设成-1.5米而不是-1.0米,能避免把有用的点切掉。
  • 先做直通滤波,再做其他滤波。比如体素滤波(降采样)或统计滤波(去噪点)。直通滤波能快速减少数据量,为后续处理减轻负担。
  • 调试时可视化很重要。我每次调参都会把滤波前后的点云显示出来,肉眼看一下效果。光看数字有时候会骗人。

一个小技巧: 如果你不确定阈值该设多少,可以先采集一段数据,用可视化工具看一下点云在三个轴上的分布范围。比如用PCL的CloudViewer,或者直接用Python的open3d。看一眼,心里就有数了。

嗯,直通滤波的内容就这些。它虽然简单,但用好了,能解决很多实际问题。下次你处理点云数据时,不妨先想想:能不能用直通滤波先切一刀?

可可精品资料库