直通滤波(PassThrough):原理与参数调优
直通滤波,说白了就是「一刀切」。
你设定一个范围,比如 x 轴从 0 到 5 米,那么在这个范围之外的点,全部砍掉。就这么简单粗暴。但你别小看它,我做过那么多点云项目,直通滤波几乎是每次预处理的第一步。为什么?因为激光雷达扫出来的数据,有一大半都是没用的背景。
原理:一维范围裁剪
直通滤波的核心逻辑其实就一句话:对指定维度,保留区间内的点,删除区间外的点。
你想想看,点云里的每个点都有 (x, y, z) 坐标。我们只需要指定一个轴,比如 z 轴,然后设一个下限和上限。所有 z 值小于下限或大于上限的点,直接扔掉。剩下的点,就是你要的。
嗯,这里要注意:直通滤波只对单个轴操作。如果你想同时过滤 x 和 y,那就得调两次。不过 PCL 里可以链式调用,写起来不麻烦。
保留条件:axis_min ≤ point.axis ≤ axis_max
删除条件:point.axis < axis_min 或 point.axis > axis_max
参数调优:三个轴的范围怎么定?
我个人习惯,先看场景再设参数。比如你放了一个 Velodyne 在车顶,地面高度大概是 -1.5 米,车顶高度 2 米。那 z 轴范围就可以设成 -1.5 到 2.0。但如果你在室内,地面是 0,天花板是 3 米,那范围就变了。
调参没有万能公式,但有经验法则:
| 参数 | 说明 | 调优建议 |
|---|---|---|
| filter_field_name | 指定过滤轴(x/y/z) | 根据目标物体分布选轴。去除地面用 z,去除左右墙壁用 x 或 y |
| filter_limit_min | 下限值 | 先看直方图,取目标点云的最低值再留 0.1 米余量 |
| filter_limit_max | 上限值 | 同理,取最高值加 0.1 米余量 |
| setFilterLimitsNegative | 是否取反(保留区间外) | 默认 false。设为 true 时,保留区间外的点,用于去除特定区域 |
实战案例:去除背景点云
我记得有一次做室内机器人定位,激光雷达放在机器人顶部。扫描出来的点云里,天花板和地板占了将近 60% 的点。这些点对定位毫无帮助,反而增加计算量。直通滤波就是干这个的。
下面是一个完整的 C++ 示例,用 PCL 库实现:
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/io/pcd_io.h>
int main() {
// 1. 加载原始点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("room_scan.pcd", *cloud);
std::cout << "原始点数: " << cloud->size() << std::endl;
// 2. 创建直通滤波对象
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud(cloud);
// 3. 过滤 z 轴:去除天花板和地板
pass.setFilterFieldName("z");
pass.setFilterLimits(0.2, 2.5); // 保留 0.2m 到 2.5m 之间的点
// pass.setFilterLimitsNegative(true); // 如果设为 true,则保留 0.2m 以下和 2.5m 以上的点
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_z(new pcl::PointCloud<pcl::PointXYZ>);
pass.filter(*cloud_filtered_z);
std::cout << "z轴过滤后: " << cloud_filtered_z->size() << std::endl;
// 4. 再过滤 x 轴:去除左右墙壁
pass.setInputCloud(cloud_filtered_z);
pass.setFilterFieldName("x");
pass.setFilterLimits(-3.0, 3.0); // 保留 -3m 到 3m 之间的点
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_x(new pcl::PointCloud<pcl::PointXYZ>);
pass.filter(*cloud_filtered_x);
std::cout << "x轴过滤后: " << cloud_filtered_x->size() << std::endl;
// 5. 保存结果
pcl::io::savePCDFile("room_filtered.pcd", *cloud_filtered_x);
return 0;
}
这段代码做了两件事:先砍掉天花板和地板(z 轴),再砍掉左右墙壁(x 轴)。最终留下的就是机器人周围的障碍物点云。
直通滤波的适用场景
- 去除固定背景:比如天花板、地板、墙壁、地面
- 提取感兴趣区域:比如只保留前方 10 米内的点云
- 预处理降采样:在体素滤波之前,先砍掉无用区域,减少计算量
但直通滤波也有局限。它只能做矩形裁剪,不能做圆形或任意形状。如果你需要更复杂的空间裁剪,那就得上条件滤波或区域生长分割了。
知识体系图
下面这张图帮你理清直通滤波在整个点云处理流程中的位置:
从图上可以看得很清楚:直通滤波就是一条直线流程。输入原始点云,选轴、设范围、执行裁剪,输出过滤后的点云。没有复杂的数学,没有迭代计算,就是纯粹的「切一刀」。
但这一刀切得好不好,直接决定后续处理的效率。我见过有人上来就做体素滤波,结果体素滤波把背景和前景一起降采样了,后面分割根本分不开。先做直通滤波砍掉背景,再做体素滤波降采样,顺序对了,效果天差地别。
好了,直通滤波就讲这么多。记住一句话:先砍背景,再谈其他。
可可精品资料库