2. 点云体素下采样

任务目标

读取一份点云数据,通过体素滤波器(VoxelGrid)进行下采样,在保持物体整体形状特征的前提下显著降低点云密度,并输出下采样前后的点云数量及可视化对比结果。

环境依赖

需要安装 open3d 和 numpy。若本地无现成点云文件,可使用 Open3D 内置的示例数据(如 fragment.ply)或随机生成一份点云作为输入。

关键完整代码

import open3d as o3d
import numpy as np

# 1. 加载点云(若文件不存在则生成随机点云用于演示)
pcd_path = "fragment.ply"
try:
    pcd = o3d.io.read_point_cloud(pcd_path)
    if pcd.is_empty():
        raise FileNotFoundError
except Exception:
    # 生成一个包含曲面结构的随机点云(球面采样 + 噪声)
    print("未找到点云文件,生成随机球面点云作为输入...")
    theta = np.random.uniform(0, np.pi, 5000)
    phi = np.random.uniform(0, 2 * np.pi, 5000)
    r = 1.0
    x = r * np.sin(theta) * np.cos(phi)
    y = r * np.sin(theta) * np.sin(phi)
    z = r * np.cos(theta)
    points = np.column_stack((x, y, z))
    points += np.random.normal(0, 0.02, points.shape)  # 添加轻微噪声
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(points)

print(f"原始点云点数: {len(pcd.points)}")

# 2. 体素下采样
voxel_size = 0.05  # 体素边长,可根据点云尺度调整
downsampled = pcd.voxel_down_sample(voxel_size)
print(f"下采样后点数: {len(downsampled.points)}")

# 3. 可视化对比(左:原始,右:下采样)
pcd.paint_uniform_color([0.8, 0.2, 0.2])      # 原始点云红色
downsampled.paint_uniform_color([0.1, 0.6, 0.9])  # 下采样蓝色
o3d.visualization.draw_geometries([pcd, downsampled],
                                  window_name="Voxel Downsample",
                                  width=1200, height=600)

运行与验证

  1. 将上述代码保存为 voxel_downsample.py,在终端执行 python voxel_downsample.py。
  2. 程序会打印下采样前后的点数,并弹出可视化窗口,左右分别显示原始点云(红色)与下采样结果(蓝色)。
  3. 通过条件:下采样后点数明显少于原始点数(通常减少 50% 以上);可视化中物体轮廓与主要几何特征保持完整,没有出现大面积空洞或形状畸变。

体素大小调整建议

voxel_size 决定下采样强度:值越大,保留的点越少,细节丢失越多。若点云坐标范围在 0~1 之间,0.05 是较稳妥的起始值;若点云尺度更大(如范围 0~100),可尝试 voxel_size=1.0 或更大。实际使用时,建议先观察点云坐标范围,再设置约为最大尺寸的 1/100~1/50 作为体素边长。

原始点云(密集) 点数:N(例如 5000) 体素下采样后(稀疏) 点数:M(M ≪ N,例如 800)

上图示意了体素下采样的核心思想:将空间划分为固定大小的立方体网格(体素),每个体素内只保留一个代表点(通常为该体素内所有点的重心),从而用稀疏均匀的点云近似原始密集点云。