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
通过条件:
- 程序无报错退出,输出“体素滤波完成”;
- 滤波后点数显著小于原始点数(本例中原始约 240,000 点,
voxel_size=0.05时通常降至数千点级别); - 质心偏移量小于体素边长的一半(即 < 0.025 m),说明整体形状特征得到保持。
若使用真实点云文件,将读取代码替换为 o3d.io.read_point_cloud("your_file.pcd") 即可,验证逻辑不变。
常见问题
- 点数不降反升? 检查
voxel_size是否过小(如小于点云平均间距),适当增大体素尺寸。 - 形状细节丢失严重? 减小
voxel_size可在点数与精度间权衡。 - 体素内点云颜色/法线丢失? Open3D 的
voxel_down_sample默认不保留颜色与法线,如需保留请使用voxel_down_sample_and_trace或自行实现带属性聚合的版本。