2. 点云预处理

任务目标

原始点云数据通常包含数十万至上百万个点,直接处理会带来巨大的计算开销。本案例实现体素滤波(Voxel Grid Filter):将三维空间划分为固定尺寸的立方体(体素),每个体素内保留所有点的重心(或中心),从而在保持物体整体形状特征的前提下显著减少点数。

环境依赖

需要 Open3D(推荐 0.17+)与 NumPy。若已有PCL环境,也可参考代码逻辑自行移植。

pip install open3d numpy

关键完整代码

import open3d as o3d
import numpy as np

def voxel_downsample(pcd, voxel_size=0.01):
    """
    对点云进行体素下采样
    :param pcd: open3d.geometry.PointCloud
    :param voxel_size: 体素边长(米)
    :return: 下采样后的点云
    """
    if voxel_size <= 0:
        raise ValueError("voxel_size 必须为正数")
    return pcd.voxel_down_sample(voxel_size)

def compute_centroid(pcd):
    """计算点云质心,用于验证形状保持"""
    points = np.asarray(pcd.points)
    return points.mean(axis=0)

if __name__ == "__main__":
    # 1. 生成或读取点云(此处用随机点云模拟,实际可替换为 pcd = o3d.io.read_point_cloud("scene.pcd"))
    print("生成模拟点云...")
    points = np.random.uniform(-0.5, 0.5, size=(200000, 3))
    # 加入一个平面结构,便于验证形状保持
    x, y = np.meshgrid(np.linspace(-0.5, 0.5, 200), np.linspace(-0.5, 0.5, 200))
    plane = np.stack([x.ravel(), y.ravel(), np.zeros_like(x.ravel())], axis=1)
    all_points = np.vstack([points, plane])
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(all_points)
    print(f"原始点数: {len(pcd.points)}")

    # 2. 体素滤波
    voxel_size = 0.05
    downsampled = voxel_downsample(pcd, voxel_size)
    print(f"滤波后点数: {len(downsampled.points)}")

    # 3. 验证:质心偏移应很小(形状保持)
    centroid_before = compute_centroid(pcd)
    centroid_after = compute_centroid(downsampled)
    shift = np.linalg.norm(centroid_after - centroid_before)
    print(f"质心偏移: {shift:.6f} m")

    # 4. 保存结果(可选)
    # o3d.io.write_point_cloud("downsampled.pcd", downsampled)
    print("体素滤波完成")

运行与验证

运行方式:将上述代码保存为 voxel_filter.py,在终端执行:

python voxel_filter.py

通过条件:

  1. 程序无报错退出,输出“体素滤波完成”;
  2. 滤波后点数显著小于原始点数(本例中原始约 240,000 点,voxel_size=0.05 时通常降至数千点级别);
  3. 质心偏移量小于体素边长的一半(即 < 0.025 m),说明整体形状特征得到保持。

若使用真实点云文件,将读取代码替换为 o3d.io.read_point_cloud("your_file.pcd") 即可,验证逻辑不变。

常见问题

  • 点数不降反升? 检查 voxel_size 是否过小(如小于点云平均间距),适当增大体素尺寸。
  • 形状细节丢失严重? 减小 voxel_size 可在点数与精度间权衡。
  • 体素内点云颜色/法线丢失? Open3D 的 voxel_down_sample 默认不保留颜色与法线,如需保留请使用 voxel_down_sample_and_trace 或自行实现带属性聚合的版本。