共计 3118 个字符,预计需要花费 8 分钟才能阅读完成。
点云聚类的典型应用场景
点云聚类在三维数据处理中扮演着重要角色,它能够将无序的点云数据分割成有意义的簇或对象。这项技术在多个领域都有广泛应用:

- 自动驾驶:用于道路场景中障碍物的检测和分割,帮助车辆识别行人、车辆和其他障碍物
- 工业检测:在质量控制中识别和分类零件或装配体
- 地形分析:区分地面点、植被和建筑物等地物类别
- 考古学:从扫描数据中分离出不同文物或结构
CloudCompare 中的核心聚类方法
CloudCompare 作为开源点云处理软件,提供了两种主要的聚类算法:欧式聚类和区域生长聚类。让我们深入了解它们的原理和适用场景。
1. 欧式聚类(Euclidean Cluster Extraction)
欧式聚类基于简单的距离阈值原则,将空间中距离相近的点归为同一簇。其核心思想可以用数学公式表示为:
$$\text{Cluster} = {p_i \in P | \text{dist}(p_i, p_j) < \epsilon, \forall p_j \in \text{Cluster}}$$
其中,$\epsilon$ 是距离阈值,$P$ 是点云集合。
适用场景:
- 物体之间有明显的空间分离
- 点云密度相对均匀
- 不需要考虑物体表面特性
优势:
- 计算效率高
- 参数直观(只需设置距离阈值)
- 适合大规模点云
2. 区域生长聚类(Region Growing)
区域生长算法更复杂,它考虑了点的法向量和曲率等几何特征。其聚类条件可以表示为:
$$\text{Cluster} = {p_i \in P | \text{angle}(\vec{n_i}, \vec{n_j}) < \theta \land |c_i – c_j| < \delta}$$
其中,$\vec{n}$ 是法向量,$c$ 是曲率,$\theta$ 和 $\delta$ 是角度和曲率阈值。
适用场景:
- 需要基于表面特性进行分割
- 物体边界不明显但表面特征差异大
- 处理复杂形状物体
优势:
- 能识别具有相似几何特征的区域
- 对物体边界更敏感
劣势:
- 计算成本较高(需要预先计算法向量)
- 参数调优更复杂
代码实现与参数调优
欧式聚类 C ++ 实现(基于 PCL)
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/kdtree/kdtree.h>
void euclideanClusterExtraction(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
// 创建 KD 树加速搜索
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
tree->setInputCloud(cloud);
// 欧式聚类对象
std::vector<pcl::PointIndices> cluster_indices;
pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
// 参数设置
ec.setClusterTolerance(0.02); // 2cm 距离阈值
ec.setMinClusterSize(100); // 最小簇点数
ec.setMaxClusterSize(25000); // 最大簇点数
ec.setSearchMethod(tree);
ec.setInputCloud(cloud);
ec.extract(cluster_indices);
// 处理聚类结果...
}
关键参数说明:
setClusterTolerance():决定两点是否属于同一簇的距离阈值setMinClusterSize():过滤掉过小的噪声簇setMaxClusterSize():防止内存过载
区域生长聚类实现
#include <pcl/segmentation/region_growing.h>
void regionGrowingSegmentation(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
// 计算法向量(区域生长必需)pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
ne.setSearchMethod(tree);
ne.setInputCloud(cloud);
ne.setKSearch(50); // 用于法向量估计的邻近点数
ne.compute(*normals);
// 区域生长聚类
pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;
reg.setMinClusterSize(50);
reg.setMaxClusterSize(10000);
reg.setSearchMethod(tree);
reg.setNumberOfNeighbours(30); // 搜索的邻近点数
reg.setInputCloud(cloud);
reg.setInputNormals(normals);
// 关键角度阈值(单位:弧度)reg.setSmoothnessThreshold(3.0 / 180.0 * M_PI); // 3 度
reg.setCurvatureThreshold(1.0);
std::vector<pcl::PointIndices> clusters;
reg.extract(clusters);
}
调优技巧:
- 法向量计算时,
setKSearch值越大结果越平滑但计算量越大 setSmoothnessThreshold通常设置为 3 -10 度之间- 对于高曲率区域,适当降低
setCurvatureThreshold
性能优化与对比
不同点云密度下的耗时测试
我们在三种点云密度下测试了两种算法的性能(Intel i7-9700K CPU):
| 点云规模 | 欧式聚类(ms) | 区域生长(ms) |
|---|---|---|
| 10,000 | 23 | 156 |
| 100,000 | 89 | 1,245 |
| 1,000,000 | 452 | 12,893 |
内存优化方案
- 降采样预处理:使用 VoxelGrid 滤波减少点数
pcl::VoxelGrid<pcl::PointXYZ> vg; vg.setInputCloud(cloud); vg.setLeafSize(0.01f, 0.01f, 0.01f); // 1cm 立方体 vg.filter(*filtered_cloud); - 分块处理:对超大点云进行空间分块处理
常见问题与解决方案
欧式聚类问题排查
- 过度分割(一个物体被分成多个簇)
- 原因:距离阈值设置过小
-
解决:逐步增大
setClusterTolerance直到效果满意 -
欠分割(不同物体被合并)
- 原因:距离阈值过大
- 解决:减小阈值,或先进行降采样
区域生长问题排查
- 无法分割不同曲面
- 原因:角度阈值设置过大
-
解决:减小
setSmoothnessThreshold -
对噪声敏感
- 原因:法向量估计不准确
- 解决:增加法向量计算的邻近点数(
setKSearch)
未来方向与开放问题
传统聚类方法虽然有效,但面临一些挑战:
- 如何结合深度学习技术(如 PointNet++)提升复杂场景下的聚类精度?
- 对于动态点云(如 LiDAR 连续帧),如何实现时序一致的聚类?
- 在参数自动调优方面,是否有更智能的方法替代手动尝试?
欢迎在评论区分享你在实际项目中的参数调优经验和遇到的特殊案例,共同探讨点云处理的最佳实践。
