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

news/2024/5/20 10:15:48 标签: 聚类, 数据挖掘, 机器学习

介绍

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

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

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

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

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

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

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

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

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

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

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

效果

代码

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#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;
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<PointTypeIO>::Ptr cloud_in (new pcl::PointCloud<PointTypeIO>), cloud_out (new pcl::PointCloud<PointTypeIO>);
    pcl::PointCloud<PointTypeFull>::Ptr cloud_with_normals (new pcl::PointCloud<PointTypeFull>);
    pcl::IndicesClustersPtr clusters (new pcl::IndicesClusters), small_clusters (new pcl::IndicesClusters), large_clusters (new pcl::IndicesClusters);
    pcl::search::KdTree<PointTypeIO>::Ptr search_tree (new pcl::search::KdTree<PointTypeIO>);
    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<PointTypeIO> 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<PointTypeIO, PointTypeFull> 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<PointTypeFull> 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);
}


http://www.niftyadmin.cn/n/5204217.html

相关文章

第三阶段学习beiqi3

滑行回馈力矩给定修改力矩 if(1 Vehicle_cmd.cmdmode.data.slip_feedback_flag)//滑行回馈{motor_regen_power EV_MCU_Para.field.Motor_regen_power_slip_level;//滑行固定功率在 10kw *****11.22 这里除去2 5kw motor_regen_trq_lmt _IQmpyI32(motor_regen_power, 9550)…

Linux程序之可变参数选项那些事!

一、linux应用程序如何接收参数&#xff1f; 1. argc、argv Linux应用程序执行时&#xff0c;我们往往通过命令行带入参数给程序&#xff0c;比如 ls /dev/ -l 其中参数 /dev/ 、-l都是作为参数传递给命令 ls 应用程序又是如何接收这些参数的&#xff1f; 通常应用程序都…

Web前端—移动Web第四天(vw适配方案、vw和vh的基本使用、综合案例-酷我音乐)

版本说明 当前版本号[20231122]。 版本修改说明20231122初版 目录 文章目录 版本说明目录移动 Web 第四天01-vw适配方案vw和vh基本使用vw布局vh布局混用问题 02-综合案例-酷我音乐准备工作头部布局头部内容搜索区域banner 区域标题公共样式排行榜内容推荐歌单布局推荐歌单内…

vue实现爱心形状的复选框

目录 HTML代码&#xff1a; CSS代码&#xff1a; Vue代码&#xff1a; 这个例子使用了CSS来创建一个爱心形状的复选框&#xff0c;并使用Vue来控制其选中状态。点击复选框时&#xff0c;将调用toggleChecked方法来切换checked属性的值&#xff0c;以控制复选框的状态。 以下…

Java继承中的属性名相同但是类型不同的情况

如果子类出现一个属性与父类的属性名一样,那么父类的属性将会被隐藏(java官方文档) 在继承当中,子类继承父类的属性和继承方法的方式上有所差别: 父类属性不可被重写,只会被调用,父类方法可以被重写,也可以被调用 当子类中存在和父类同名属性,父类属性会隐藏起来,在多态的情…

thinkphp文件夹生成zip压缩包

一、准备工作&#xff0c;使用phpinfo()查看有没有zip扩展 <?php echo phpinfo(); ?>Thinkphp使用PHP自带的ZipArchive压缩文件或文件夹 显示enabled 说明已经配置好 如果没有安装扩展的&#xff0c;请参照以下方法&#xff1a; 1、下载对应版本的扩展包&#xff1a…

头发的方向图(2D和3D)与合成

首先&#xff0c;我们从一个不受光照限制的环境中拍摄一组输入图像&#xff0c;这些图像包含了头发的不同视角和姿态。我们对这些图像进行半自动的分割&#xff0c;将头发从背景中分离出来&#xff0c;然后使用PMVS &#xff0c;一种先进的多视角立体算法&#xff0c;来重建一个…

笔试题之指针结合数组的精讲2

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…