条件欧氏聚类分割是一种基于欧氏距离和条件限制的点云分割方法。它通过计算点云中点与点之间的欧氏距离,并结合一定的条件限制来将点云分割成不同的区域或聚类。
在条件欧氏聚类分割中,通常会定义以下两个条件来判断两个点是否属于同一个聚类:
距离条件:两个点之间的欧氏距离是否小于设定的阈值。如果两个点之间的距离小于阈值,则认为它们是相邻的,属于同一个聚类。
条件限制:除了距离条件外,还可以根据其他的条件来限制聚类的形成。例如,可以限制点的法线方向、颜色、强度等属性的相似性,只有当这些属性满足一定的条件时,两个点才被认为是相邻的,属于同一个聚类。
条件欧氏聚类分割的步骤通常包括以下几个步骤:
初始化:设置距离阈值和其他条件限制的参数。
遍历点云:对于点云中的每个点,依次进行以下操作:
计算当前点与其周围点之间的欧氏距离。
根据距离条件和其他条件限制,判断当前点是否与周围点属于同一个聚类。如果是,则将它们标记为同一个聚类。
继续遍历其他未被标记的点,重复上述操作,直到所有点都被遍历完。
输出聚类结果:将同一个聚类的点标记为一组,形成不同的聚类簇。

- #include
- #include
- #include
-
- #include
- #include
- #include
-
- typedef pcl::PointXYZI PointTypeIO;
- typedef pcl::PointXYZINormal PointTypeFull;
-
- 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);
- else
- return (false);
- }
-
- bool enforceNormalOrIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float /*squared_distance*/)
- {
- // 将点云的法线信息转换未Eigen库的Eigen:vector3f类型
- Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap (), point_b_normal = point_b.getNormalVector3fMap ();
-
- // 判断点云A的点云B的强度差是否小于5.0
- if (std::abs (point_a.intensity - point_b.intensity) < 5.0f)
- return (true);
-
- // 判断点云A和点云B的法线夹角的余弦值是否大于30°对应的余弦值,即判断法线相似性
- if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI)))
- return (true);
- return (false);
- }
-
- bool customRegionGrowing (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 (squared_distance < 10000)
- {
- if (std::abs (point_a.intensity - point_b.intensity) < 8.0f)
- return (true);
- if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI)))
- return (true);
- }
- else
- {
- if (std::abs (point_a.intensity - point_b.intensity) < 3.0f)
- return (true);
- }
- return (false);
- }
-
- int main ()
- {
- // Data containers used
- pcl::PointCloud
::Ptr cloud_in (new pcl::PointCloud) , cloud_out (new pcl::PointCloud) ; - pcl::PointCloud
::Ptr cloud_with_normals (new pcl::PointCloud) ; - pcl::IndicesClustersPtr clusters (new pcl::IndicesClusters), small_clusters (new pcl::IndicesClusters), large_clusters (new pcl::IndicesClusters);
- pcl::search::KdTree
::Ptr search_tree (new pcl::search::KdTree) ; - pcl::console::TicToc tt;
-
- // Load the input point cloud
- std::cerr << "Loading...\n", tt.tic ();
- pcl::io::loadPCDFile ("Statues_4.pcd", *cloud_in);
- std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_in->size () << " points\n";
-
- // Downsample the cloud using a Voxel Grid class
- std::cerr << "Downsampling...\n", tt.tic ();
- pcl::VoxelGrid
vg; - vg.setInputCloud (cloud_in);
- vg.setLeafSize (80.0, 80.0, 80.0);
- vg.setDownsampleAllData (true);
- vg.filter (*cloud_out);
- std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_out->size () << " points\n";
-
- // Set up a Normal Estimation class and merge data in cloud_with_normals
- std::cerr << "Computing normals...\n", tt.tic ();
- pcl::copyPointCloud (*cloud_out, *cloud_with_normals);
- pcl::NormalEstimation
ne; - ne.setInputCloud (cloud_out);
- ne.setSearchMethod (search_tree);
- ne.setRadiusSearch (300.0);
- ne.compute (*cloud_with_normals);
- std::cerr << ">> Done: " << tt.toc () << " ms\n";
-
- // Set up a Conditional Euclidean Clustering class
- std::cerr << "Segmenting to clusters...\n", tt.tic ();
- pcl::ConditionalEuclideanClustering
cec (true) ; - cec.setInputCloud (cloud_with_normals);
- cec.setConditionFunction (&customRegionGrowing);
- cec.setClusterTolerance (500.0);
- cec.setMinClusterSize (cloud_with_normals->size () / 1000);
- cec.setMaxClusterSize (cloud_with_normals->size () / 5);
- cec.segment (*clusters);
- cec.getRemovedClusters (small_clusters, large_clusters);
- std::cerr << ">> Done: " << tt.toc () << " ms\n";
-
- // Using the intensity channel for lazy visualization of the output
- for (const auto& small_cluster : (*small_clusters))
- for (const auto& j : small_cluster.indices)
- (*cloud_out)[j].intensity = -2.0;
- for (const auto& large_cluster : (*large_clusters))
- for (const auto& j : large_cluster.indices)
- (*cloud_out)[j].intensity = +10.0;
- for (const auto& cluster : (*clusters))
- {
- int label = rand () % 8;
- for (const auto& j : cluster.indices)
- (*cloud_out)[j].intensity = label;
- }
-
- // Save the output point cloud
- std::cerr << "Saving...\n", tt.tic ();
- pcl::io::savePCDFile ("output.pcd", *cloud_out);
- std::cerr << ">> Done: " << tt.toc () << " ms\n";
-
- return (0);
- }
-