3. 点云预处理
任务目标
本案例实现点云统计滤波去噪:对输入的带噪声点云,基于每个点与其k近邻的平均距离分布,剔除距离统计特征显著偏离的离群点,输出干净点云并验证滤波效果。
环境依赖
需要 Open3D(≥0.15)与 NumPy。若需可视化,安装 matplotlib。无需ROS或其他重型依赖。
核心实现
import numpy as np
import open3d as o3d
def generate_noisy_pcd(n_points=5000, noise_ratio=0.05, seed=42):
"""生成带离群点的球面点云(含随机离群点)"""
rng = np.random.default_rng(seed)
# 球面主体点
phi = rng.uniform(0, np.pi, n_points)
theta = rng.uniform(0, 2 * np.pi, n_points)
r = 1.0 + 0.02 * rng.standard_normal(n_points) # 轻微径向噪声
x = r * np.sin(phi) * np.cos(theta)
y = r * np.sin(phi) * np.sin(theta)
z = r * np.cos(phi)
clean = np.stack([x, y, z], axis=1)
# 随机离群点(远离球面)
n_outliers = int(n_points * noise_ratio)
outliers = rng.uniform(-3, 3, size=(n_outliers, 3))
points = np.vstack([clean, outliers])
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)
return pcd, n_outliers
def statistical_filter(pcd, nb_neighbors=20, std_ratio=2.0):
"""统计滤波:移除k近邻平均距离超出 mean + std_ratio*std 的点"""
cl, ind = pcd.remove_statistical_outlier(
nb_neighbors=nb_neighbors, std_ratio=std_ratio)
return cl, ind
if __name__ == "__main__":
# 1. 生成带噪点云
pcd, true_outliers = generate_noisy_pcd()
print(f"输入点数: {len(pcd.points)}, 真实离群点数: {true_outliers}")
# 2. 执行统计滤波
filtered_pcd, inlier_indices = statistical_filter(pcd)
# 3. 验证:统计滤波应移除大部分离群点
n_removed = len(pcd.points) - len(filtered_pcd.points)
print(f"滤波后点数: {len(filtered_pcd.points)}, 移除点数: {n_removed}")
# 4. 保存结果(可选)
# o3d.io.write_point_cloud("filtered.pcd", filtered_pcd)
# 5. 可视化对比(取消注释以查看)
# pcd.paint_uniform_color([0.8, 0.2, 0.2]) # 红色=原始
# filtered_pcd.paint_uniform_color([0.2, 0.8, 0.2]) # 绿色=滤波后
# o3d.visualization.draw_geometries([pcd, filtered_pcd])
运行与验证
运行方式:
pip install open3d numpy
python statistical_filter_demo.py
通过条件:
- 程序无报错执行完毕;
- 输出中“移除点数”接近真实离群点数(5000×5%=250),且明显小于总点数;
- 若取消可视化注释,可看到红色点云中远离球面的离群点被绿色滤波点云排除。
预期输出(基于代码逻辑可唯一推出):
输入点数: 5250, 真实离群点数: 250
滤波后点数: ~5000-5100, 移除点数: ~150-250
实际数值因随机种子固定(seed=42)而确定,但Open3D内部实现可能随版本微调,因此以“移除点数接近250且滤波后点云主体完整”为判定标准。
关键说明
remove_statistical_outlier对每个点计算其到k近邻的平均距离,全局均值为μ、标准差为σ,距离超过 μ+std_ratio×σ 的点视为离群点。- 参数
nb_neighbors=20控制邻域大小,std_ratio=2.0为常用阈值;点云越密集,邻域数可适当增大。 - 本案例使用合成球面点云以便定量验证,实际使用时替换为
o3d.io.read_point_cloud("your.pcd")读取真实点云即可。