1、简介
1.1 条件欧几里得聚类(Conditional Euclidean Clustering)
本文介绍了如何使用 pcl::ConditionalEuclideanClustering
类:这是一种基于欧几里得距离和用户自定义条件的点云聚类分割算法。
该类使用了与欧几里得聚类提取(Euclidean Cluster Extraction)、**区域生长分割(Region growing segmentation)和基于颜色的区域生长分割(Color-based region growing segmentation)**中相同的贪婪式(greedy-like)/区域生长(region-growing)/洪水填充(flood-filling)方法。与其他类相比,使用该类的优势在于,聚类的约束条件(纯欧几里得距离、平滑度、RGB等)现在可以由用户自定义。然而,它也有一些缺点,例如:没有初始种子系统、无法控制过分割和欠分割,以及在主计算循环中调用条件函数会降低时间效率。
1.2 理论基础
在欧几里得聚类提取和区域生长分割的教程中,已经非常准确地解释了区域生长算法。本教程的补充说明是,现在可以完全自定义用于判断是否将邻近点合并到当前聚类的条件。
随着聚类的增长,算法会评估用户定义的条件,该条件用于判断已经在聚类中的点与附近的候选点之间的关系。候选点(最近邻点)是通过在聚类中每个点周围进行欧几里得半径搜索找到的。对于每个聚类中的点,条件需要至少与其中一个邻近点满足,而不是与所有邻近点都满足。
Conditional Euclidean Clustering
类还可以根据大小约束自动过滤聚类。被分类为过小或过大的聚类仍然可以在之后被检索出来。
- 算法核心:基于欧几里得距离和用户自定义条件进行点云聚类。
- 优势:聚类条件可自定义,灵活性高。
- 缺点:无初始种子系统,无法控制过分割和欠分割,时间效率较低。
- 工作原理:通过区域生长算法,结合欧几里得半径搜索和用户定义的条件来判断点是否属于同一聚类。
- 额外功能:支持根据聚类大小自动过滤,并保留过小或过大的聚类。
2、代码示例
数据集Statues_4.pcd是一个非常大的户外环境数据集,我们的目标是对其中的独立物体进行聚类,并且希望将建筑物与地面分离,尽管它们在欧几里得意义上是相连的。创建conditional_euclidean_clustering.cpp
。
2.1 conditional_euclidean_clustering.cpp
#include <pcl/point_types.h> // PCL点云数据类型
#include <pcl/io/pcd_io.h> // PCL的PCD文件读写
#include <pcl/console/time.h> // 用于计时
#include <pcl/filters/voxel_grid.h> // 体素网格滤波器
#include <pcl/features/normal_3d.h> // 法线估计
#include <pcl/segmentation/conditional_euclidean_clustering.h> // 条件欧几里得聚类
// 定义点类型
typedef pcl::PointXYZI PointTypeIO; // 输入输出点类型,包含XYZ坐标和强度信息
typedef pcl::PointXYZINormal PointTypeFull; // 包含XYZ坐标、强度和法线的点类型
// 自定义条件函数 1:强度相似性
bool enforceIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float /*squared_distance*/)
{
if (std::abs (point_a.intensity - point_b.intensity) < 5.0f)
return (true); // 如果两点强度差小于5,返回true
else
return (false); // 否则返回false
}
// 自定义条件函数 2:法线或强度相似性
bool enforceNormalOrIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float /*squared_distance*/)
{
Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap (), point_b_normal = point_b.getNormalVector3fMap ();
if (std::abs (point_a.intensi