共计 1417 个字符,预计需要花费 4 分钟才能阅读完成。
为什么需要点云聚类?
刚接触 3D 点云处理时,我面对的第一个挑战就是:如何让无序的点数据变得有意义?原始点云往往存在两个头疼的问题:

- 噪声干扰:激光雷达或深度相机采集时,会混入漂浮物、反射误差产生的离群点
- 密度不均:近处物体点云密集,远处物体稀疏,传统分割方法难以适应
比如用 RGB- D 相机扫描房间,墙面上的装饰画和真实墙面会混在一起,这时候就需要聚类算法帮我们区分不同物体。
算法选型:没有最好只有最适合
试过几种主流算法后,总结出这份对比表:
| 算法类型 | 时间复杂度 | 噪声敏感度 | 适用场景 |
|---|---|---|---|
| DBSCAN | O(nlogn) | 低 | 不规则形状,密度不均 |
| 欧式聚类 | O(n) | 中 | 均匀密度,快速实现 |
| K-means | O(nkt) | 高 | 已知聚类数量,球形分布 |
实际体验:处理室内场景时 DBSCAN 效果最好,因为家具形状各异且点云密度变化大。而 K -means 在分割篮球这种规则物体时反而更高效。
手把手 Open3D 实现
准备工作
import open3d as o3d
import numpy as np
# 加载示例点云(实际替换为你的 pcd 文件)bunny = o3d.data.BunnyMesh().path
pcd = o3d.io.read_point_cloud(bunny)
预处理:给数据 ” 瘦身 ”
-
降采样:用体素网格过滤,既减少数据量又保持形状特征
voxel_size = 0.01 # 根据点云尺度调整 pcd = pcd.voxel_down_sample(voxel_size) -
去噪:统计离群点移除比半径滤波更智能
# 取 50 个最近邻点,标准差乘数为 2.0 pcd, _ = pcd.remove_statistical_outlier(nb_neighbors=50, std_ratio=2.0)
核心聚类
# 关键参数说明:eps 是邻域半径,min_points 是最小聚类点数
labels = np.array(pcd.cluster_dbscan(eps=0.05, min_points=10, print_progress=True))
# 可视化:给每个聚类随机颜色
max_label = labels.max()
colors = np.random.rand(max_label + 1, 3)
colors[labels < 0] = 0 # 噪声点设为黑色
pcd.colors = o3d.utility.Vector3dVector(colors[labels])
o3d.visualization.draw_geometries([pcd])
躲坑指南(血泪经验)
- 参数动态调整:
- 先计算点云平均间距作为 eps 参考值
-
使用
o3d.geometry.PointCloud.compute_nearest_neighbor_distance()辅助分析 -
内存优化:
- 超过 100 万点时先用
uniform_down_sample快速降采样 -
开启 OpenMP 多线程:
export OMP_NUM_THREADS=8 -
效果评估:
- 计算轮廓系数:
from sklearn.metrics import silhouette_score - 可视化时按聚类大小排序,优先检查小聚类是否合理
进阶挑战
试着用 PCL 实现相同功能时,发现两个有趣现象:
- PCL 的欧式聚类比 Open3D 快 2 - 3 倍(因为用了更底层的优化)
- 但 Open3D 的 Python API 调试更方便,适合快速验证算法
建议先掌握 Open3D 的工作流,再过渡到 PCL 追求性能。完整代码已放在 GitHub(假装有链接),下次我们聊聊如何用聚类结果做物体识别!
正文完
发表至: 未分类
近三天内
