• [点云分割] 条件欧氏聚类分割


    介绍

    条件欧氏聚类分割是一种基于欧氏距离和条件限制的点云分割方法。它通过计算点云中点与点之间的欧氏距离,并结合一定的条件限制来将点云分割成不同的区域或聚类。

    在条件欧氏聚类分割中,通常会定义以下两个条件来判断两个点是否属于同一个聚类:

    1. 距离条件:两个点之间的欧氏距离是否小于设定的阈值。如果两个点之间的距离小于阈值,则认为它们是相邻的,属于同一个聚类。

    2. 条件限制:除了距离条件外,还可以根据其他的条件来限制聚类的形成。例如,可以限制点的法线方向、颜色、强度等属性的相似性,只有当这些属性满足一定的条件时,两个点才被认为是相邻的,属于同一个聚类。

    条件欧氏聚类分割的步骤通常包括以下几个步骤:

    1. 初始化:设置距离阈值和其他条件限制的参数。

    2. 遍历点云:对于点云中的每个点,依次进行以下操作:

      • 计算当前点与其周围点之间的欧氏距离。

      • 根据距离条件和其他条件限制,判断当前点是否与周围点属于同一个聚类。如果是,则将它们标记为同一个聚类。

      • 继续遍历其他未被标记的点,重复上述操作,直到所有点都被遍历完。

    3. 输出聚类结果:将同一个聚类的点标记为一组,形成不同的聚类簇。

    效果

    代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. typedef pcl::PointXYZI PointTypeIO;
    8. typedef pcl::PointXYZINormal PointTypeFull;
    9. bool enforceIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float /*squared_distance*/)
    10. {
    11. if (std::abs (point_a.intensity - point_b.intensity) < 5.0f)
    12. return (true);
    13. else
    14. return (false);
    15. }
    16. bool enforceNormalOrIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float /*squared_distance*/)
    17. {
    18. // 将点云的法线信息转换未Eigen库的Eigen:vector3f类型
    19. Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap (), point_b_normal = point_b.getNormalVector3fMap ();
    20. // 判断点云A的点云B的强度差是否小于5.0
    21. if (std::abs (point_a.intensity - point_b.intensity) < 5.0f)
    22. return (true);
    23. // 判断点云A和点云B的法线夹角的余弦值是否大于30°对应的余弦值,即判断法线相似性
    24. if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI)))
    25. return (true);
    26. return (false);
    27. }
    28. bool customRegionGrowing (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
    29. {
    30. Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap (), point_b_normal = point_b.getNormalVector3fMap ();
    31. // 根据平方距离的大小,判断生长条件
    32. if (squared_distance < 10000)
    33. {
    34. if (std::abs (point_a.intensity - point_b.intensity) < 8.0f)
    35. return (true);
    36. if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI)))
    37. return (true);
    38. }
    39. else
    40. {
    41. if (std::abs (point_a.intensity - point_b.intensity) < 3.0f)
    42. return (true);
    43. }
    44. return (false);
    45. }
    46. int main ()
    47. {
    48. // Data containers used
    49. pcl::PointCloud::Ptr cloud_in (new pcl::PointCloud), cloud_out (new pcl::PointCloud);
    50. pcl::PointCloud::Ptr cloud_with_normals (new pcl::PointCloud);
    51. pcl::IndicesClustersPtr clusters (new pcl::IndicesClusters), small_clusters (new pcl::IndicesClusters), large_clusters (new pcl::IndicesClusters);
    52. pcl::search::KdTree::Ptr search_tree (new pcl::search::KdTree);
    53. pcl::console::TicToc tt;
    54. // Load the input point cloud
    55. std::cerr << "Loading...\n", tt.tic ();
    56. pcl::io::loadPCDFile ("Statues_4.pcd", *cloud_in);
    57. std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_in->size () << " points\n";
    58. // Downsample the cloud using a Voxel Grid class
    59. std::cerr << "Downsampling...\n", tt.tic ();
    60. pcl::VoxelGrid vg;
    61. vg.setInputCloud (cloud_in);
    62. vg.setLeafSize (80.0, 80.0, 80.0);
    63. vg.setDownsampleAllData (true);
    64. vg.filter (*cloud_out);
    65. std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_out->size () << " points\n";
    66. // Set up a Normal Estimation class and merge data in cloud_with_normals
    67. std::cerr << "Computing normals...\n", tt.tic ();
    68. pcl::copyPointCloud (*cloud_out, *cloud_with_normals);
    69. pcl::NormalEstimation ne;
    70. ne.setInputCloud (cloud_out);
    71. ne.setSearchMethod (search_tree);
    72. ne.setRadiusSearch (300.0);
    73. ne.compute (*cloud_with_normals);
    74. std::cerr << ">> Done: " << tt.toc () << " ms\n";
    75. // Set up a Conditional Euclidean Clustering class
    76. std::cerr << "Segmenting to clusters...\n", tt.tic ();
    77. pcl::ConditionalEuclideanClustering cec (true);
    78. cec.setInputCloud (cloud_with_normals);
    79. cec.setConditionFunction (&customRegionGrowing);
    80. cec.setClusterTolerance (500.0);
    81. cec.setMinClusterSize (cloud_with_normals->size () / 1000);
    82. cec.setMaxClusterSize (cloud_with_normals->size () / 5);
    83. cec.segment (*clusters);
    84. cec.getRemovedClusters (small_clusters, large_clusters);
    85. std::cerr << ">> Done: " << tt.toc () << " ms\n";
    86. // Using the intensity channel for lazy visualization of the output
    87. for (const auto& small_cluster : (*small_clusters))
    88. for (const auto& j : small_cluster.indices)
    89. (*cloud_out)[j].intensity = -2.0;
    90. for (const auto& large_cluster : (*large_clusters))
    91. for (const auto& j : large_cluster.indices)
    92. (*cloud_out)[j].intensity = +10.0;
    93. for (const auto& cluster : (*clusters))
    94. {
    95. int label = rand () % 8;
    96. for (const auto& j : cluster.indices)
    97. (*cloud_out)[j].intensity = label;
    98. }
    99. // Save the output point cloud
    100. std::cerr << "Saving...\n", tt.tic ();
    101. pcl::io::savePCDFile ("output.pcd", *cloud_out);
    102. std::cerr << ">> Done: " << tt.toc () << " ms\n";
    103. return (0);
    104. }

  • 相关阅读:
    ROS之节点管理launch文件
    达梦错误码信息-PRO*C 错误码汇编
    “世界首台USB-C iPhone”被拍卖,目前出价63万人民币
    WPS Office for Linux即将面临开源
    java 企业工程管理系统软件源码 自主研发 工程行业适用
    基于STM32+腾讯云IO+微信小程序设计的混凝土智能养护系统
    ElasticSearch7.3学习(二十六)----搜索(Search)参数总结、结果跳跃(bouncing results)问题解析
    基于antd+vue2来实现一个简单的绘画流程图功能
    SpringBoot 官方文档示例:(54)统一异常处理之@ControllerAdvice注解
    SESSION详解
  • 原文地址:https://blog.csdn.net/weixin_45824067/article/details/134562868