3、直通滤波:原理与实现、在仿真中过滤无效范围数据、代码实战(Python + Open3D)

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

直通滤波,名字听着挺唬人。其实说白了,就是一刀切。

你想象一下,你面前有一堆点云数据。这些数据里,有些点离你太远了,远到根本看不清;有些点又太近了,近到贴在你的传感器镜头上。这些点,对后续处理来说,基本就是噪音。

直通滤波要做的,就是沿着某个坐标轴(比如 X、Y、Z),设定一个范围。在这个范围里的点,我留下;不在这个范围里的,我直接扔掉。

嗯,就这么简单。

我在做自动驾驶仿真的时候,经常遇到这种情况。激光雷达扫出来的点云,动不动就几百米开外。但我的仿真场景,可能就关注车前 50 米内的障碍物。那些远处的点,不仅没用,还会拖慢计算速度。所以,我习惯上来就先做一个直通滤波,把范围卡死。

核心思想: 直通滤波是一种基于坐标轴范围的快速点云裁剪方法。它不关心点的颜色、强度,只看点的空间位置。

3.2 原理:其实就是设定一个“框”

直通滤波的原理,用一句话就能讲清楚:

对于点云中的每一个点,检查它在指定维度上的坐标值。如果这个值在设定的最小值和最大值之间,就保留;否则,就删除。

举个例子。你有一堆点,分布在 X 轴上从 -100 到 100 的位置。你只想保留 X 在 -10 到 10 之间的点。那么直通滤波就会把 X < -10 和 X > 10 的点全部过滤掉。

为什么会这样?因为很多传感器,尤其是激光雷达,边缘区域的数据质量很差。我记得有一次做室内建图仿真,墙壁边缘的点总是飘忽不定。后来发现,是雷达在水平视角边缘的测量误差太大。我用直通滤波把水平角度对应的 X 范围一缩,问题就解决了。

直通滤波可以单独对 X、Y、Z 轴操作,也可以组合使用。比如先过滤 X 轴,再过滤 Y 轴,最后过滤 Z 轴。这样就能得到一个立方体形状的感兴趣区域。

维度 典型应用场景 我常用的范围
X 轴 过滤左右两侧的无效点 -50m ~ 50m
Y 轴 过滤前后方向的远距离点 0m ~ 80m(车前)
Z 轴 过滤地面和过高物体 -1.5m ~ 3.0m

3.3 在仿真中,它为什么这么重要?

仿真环境里,数据往往是“完美”的。但完美不等于有用。

你想想看,仿真场景可能生成一个巨大的城市模型。激光雷达模拟器会忠实地把几公里外的建筑轮廓都扫出来。这些数据,对于验证感知算法来说,完全是多余的。

直通滤波在仿真中的核心作用,我总结为三点:

  • 减少计算量: 去掉无效范围的数据,后续的聚类、分割算法能快不少。我做过测试,一个 100 万点的点云,经过直通滤波后可能只剩 30 万点,处理速度提升 3 倍以上。
  • 提高算法稳定性: 远处的点稀疏且噪声大,容易让算法产生误检。把范围卡死,算法只关注有效区域,误报率明显下降。
  • 模拟真实传感器限制: 真实的激光雷达都有最大探测距离和视场角。仿真中如果不做直通滤波,算法可能会“看到”现实中根本看不到的东西,导致仿真结果过于乐观。

一个小技巧: 在仿真中,我通常会把直通滤波的参数和传感器的型号绑定。比如模拟 Velodyne HDL-64E,我就把 Y 轴范围设为 0~120m;模拟 Livox Horizon,就设为 0~90m。这样仿真结果更贴近实际。

3.4 代码实战:Python + Open3D

光说不练假把式。咱们直接上代码。

Open3D 里实现直通滤波,其实就一行核心函数。但我还是习惯把整个流程写清楚,方便调试。

import open3d as o3d
import numpy as np

# 1. 读取点云数据(这里用 Open3D 自带的示例数据)
print("加载点云数据...")
pcd = o3d.io.read_point_cloud("sample.pcd")
print(f"原始点云点数: {len(pcd.points)}")

# 2. 创建直通滤波器对象
# 我个人习惯先创建一个副本,避免修改原始数据
pcd_filtered = o3d.geometry.PointCloud()
pcd_filtered.points = o3d.utility.Vector3dVector(np.asarray(pcd.points))

# 3. 定义过滤范围
# 这里我过滤 Z 轴,只保留高度在 -0.5 到 1.5 米之间的点
# 这个范围在仿真中常用于过滤地面和低矮障碍物
z_min = -0.5
z_max = 1.5

# 4. 执行直通滤波
# Open3D 的 crop 方法配合 AxisAlignedBoundingBox 可以实现直通滤波效果
bbox = o3d.geometry.AxisAlignedBoundingBox(
    min_bound=(-np.inf, -np.inf, z_min),
    max_bound=(np.inf, np.inf, z_max)
)
pcd_filtered = pcd_filtered.crop(bbox)

print(f"直通滤波后点云点数: {len(pcd_filtered.points)}")

# 5. 可视化对比
# 原始点云用红色,滤波后点云用绿色
pcd.paint_uniform_color([1, 0, 0])  # 红色
pcd_filtered.paint_uniform_color([0, 1, 0])  # 绿色

# 显示在一起,方便对比
o3d.visualization.draw_geometries([pcd, pcd_filtered],
                                  window_name="直通滤波效果对比",
                                  width=800, height=600)

注意: 上面的代码用了 AxisAlignedBoundingBox 来实现直通滤波。这种方法的好处是可以一次性过滤多个维度。如果你只想过滤单个维度,也可以用更直接的方式:遍历点云,手动判断每个点的坐标值。但 Open3D 的 crop 方法效率更高,我推荐用这个。

3.5 我曾经踩过的坑

讲两个我亲身经历的问题,希望能帮你避开。

第一个坑:坐标系搞反了。

有一次我在仿真中过滤点云,明明设了 Y 轴范围 0~50 米,结果点云全没了。查了半天,发现仿真场景的坐标系是 Z 轴朝前,而不是常见的 Y 轴朝前。所以,拿到点云数据后,第一件事就是确认坐标系方向。别想当然。

第二个坑:范围设得太死。

直通滤波虽然好用,但别把范围卡得太极限。比如你设 Z 轴范围 -1.0 到 2.0 米,刚好把车顶切掉一部分。在仿真中,这种边界上的点很容易因为传感器噪声而抖动。我建议留出 10%~20% 的余量,让算法有缓冲空间。

3.6 本章知识体系

下面这张图,是我自己梳理的直通滤波知识结构。你可以对照着回顾一下。

直通滤波知识体系 核心原理 沿坐标轴设定范围 保留范围内点 删除范围外点 减少计算量 提高算法稳定性 模拟真实传感器限制 代码实现 Open3D Python

直通滤波虽然简单,但它是点云预处理的第一道防线。用好了,后面的工作会轻松很多。我个人建议,在仿真验证流程中,把直通滤波作为标准步骤固定下来,不要省略。

可可精品资料库