直通滤波:点云处理的第一道门槛

说实话,直通滤波(PassThrough)是我在点云处理里用得最多的一个滤波器。为什么?因为它简单、快、有效。你想想看,很多时候我们拿到的点云数据,范围特别大——比如一个激光雷达扫一圈,能扫到几十米甚至上百米。但真正有用的区域,可能就那么一小块。

直通滤波干的事,说白了就是「切一刀」。沿着某个坐标轴,设定一个范围,范围内的点留下,范围外的点扔掉。就这么简单。

原理:一刀切的艺术

直通滤波的原理,用一句话就能讲清楚:指定一个维度(x、y、z),设定一个区间[min, max],保留区间内的点,删除区间外的点。

举个例子。你有一堆点云数据,代表一个房间里的物体。你只关心地面以上1米到2米之间的区域。那好,沿着z轴设一个区间[1.0, 2.0],所有z坐标在这个范围内的点留下,其他的扔掉。

为什么会这样?因为激光雷达扫出来的点,每个点都有三维坐标(x, y, z)。我们只需要判断每个点的坐标是否在指定范围内,是就保留,不是就丢弃。计算量极小,速度极快。

核心公式:对于点P(x, y, z),在维度d上设定区间[min, max],若P.d ∈ [min, max],则保留,否则丢弃。

我在项目中遇到过一种情况:一个AGV小车在仓库里跑,激光雷达装在车顶。雷达能扫到天花板,也能扫到地面。但导航只需要地面附近的点。用直通滤波沿z轴切一刀,保留[0.2, 1.5]米的点,天花板和地面的噪声瞬间就没了。

代码实现:三行搞定

PCL(Point Cloud Library)里已经封装好了直通滤波。代码量很少,我直接贴出来。

#include <pcl/filters/passthrough.h>

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

// 设置输入点云
pass.setInputCloud(cloud);

// 设置滤波维度为z轴
pass.setFilterFieldName("z");

// 设置范围:保留z在0.2到1.5之间的点
pass.setFilterLimits(0.2, 1.5);

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

嗯,这里要注意。setFilterLimits的两个参数,第一个是下限,第二个是上限。默认是保留区间内的点。如果你想保留区间外的点,可以调用setFilterLimitsNegative(true)。

Python版本也差不多,用pypcl或者open3d都能实现。我习惯用open3d,代码更简洁:

import open3d as o3d
import numpy as np

# 读取点云
pcd = o3d.io.read_point_cloud("scene.pcd")

# 获取点坐标
points = np.asarray(pcd.points)

# 直通滤波:保留z在0.2到1.5之间的点
mask = (points[:, 2] >= 0.2) & (points[:, 2] <= 1.5)
filtered_points = points[mask]

# 更新点云
pcd.points = o3d.utility.Vector3dVector(filtered_points)

你看,Python版本其实就是用了一个布尔索引。一行代码搞定滤波。但要注意,open3d的这种方式会丢失点云的其他属性(比如颜色、法向量)。如果你需要保留这些属性,建议用PCL的Python绑定。

参数调节技巧:别小看这几个参数

直通滤波的参数很少,就三个:维度、下限、上限。但调好它们,需要一点经验。

参数 说明 调节建议
维度 选择x、y、z中的哪一个轴 根据场景选择。地面滤波用z,走廊滤波用x或y
下限 保留点的最小坐标值 先看数据分布,再设值。别拍脑袋
上限 保留点的最大坐标值 同理,看数据分布。留一点余量

我个人习惯的做法是:先用可视化工具看一眼点云的整体分布。比如用PCL的CloudViewer或者open3d的draw_geometries。看看点云在z轴上的范围是多少。然后根据需求,设定一个稍微宽松一点的区间。

举个例子。你看到点云在z轴上的分布是[-0.5, 3.0],你想保留地面以上0.2米到1.5米的区域。那下限设0.2,上限设1.5。但如果你发现有些有用的点刚好在1.5米附近,可以稍微放宽到1.6米。

小技巧:如果你不确定范围,可以先设一个很宽的区间,然后逐步缩小。每次缩小后看一眼结果,直到满意为止。这叫「由粗到精」的调参策略。

在机器人导航中的应用

直通滤波在机器人导航里,几乎是标配。为什么?因为导航算法(比如2D SLAM、路径规划)通常只需要2D信息,或者只需要特定高度范围内的点。

我做过一个项目,用激光雷达做室内导航。雷达装在机器人顶部,高度约0.5米。雷达扫一圈,能扫到地面、墙壁、桌子腿、人的腿。但导航只需要地面的轮廓和障碍物的位置。

怎么处理?两步走:

  1. z轴直通滤波:保留[0.1, 0.8]米的点。这样地面点(z≈0)被去掉,天花板点(z>1.5)也被去掉。剩下的是墙壁、桌子腿、人腿这些障碍物。
  2. 投影到2D:把剩下的点投影到x-y平面,生成2D占据栅格地图。

你看,直通滤波在这里起到了「去噪」和「降维」的双重作用。没有它,导航算法会被地面点和天花板点干扰,根本跑不起来。

避坑指南:我曾经在一个项目中,把直通滤波的范围设得太窄,结果把机器人自身的轮子点也滤掉了。后来发现,机器人的轮子高度刚好在0.05米左右,而我设的下限是0.1米。嗯,从那以后,我每次设范围都会留一点余量,至少±0.05米。

知识体系图

下面这张图,帮你理清直通滤波在整个点云处理流程中的位置。

直通滤波知识体系 原始点云 直通滤波 选择维度 → 设定范围 滤波后点云 应用场景 机器人导航 去除地面/天花板点 目标检测 提取ROI区域 三维重建 裁剪无效区域

从这张图你能看到,直通滤波是整个点云预处理流程中非常基础的一环。它不复杂,但用好了,能解决很多实际问题。

最后说一句。直通滤波虽然简单,但千万别小看它。我见过不少新手,一上来就用复杂的滤波器(比如统计滤波、体素滤波),结果参数调不好,效果还不如一个简单的直通滤波。记住:能用简单方法解决的问题,就别用复杂的。

可可精品资料库