欧几里得聚类提取

本教程学习使用pcl::EuclideanClusterExtraction类进行欧几里得聚类提取。

欧几里得聚类原理:

聚类方法需要将一个无组织的点云模型p划分为更小的部分,从而大大减少了p的整体处理时间。

[TencentCloudSDKException] code:FailedOperation.ServiceIsolate message:service is stopped due to arrears, please recharge your account in Tencent Cloud requestId:6a4ffcb9-0124-44df-b52f-bb9ca5c19016

[En]

[TencentCloudSDKException] code:FailedOperation.ServiceIsolate message:service is stopped due to arrears, please recharge your account in Tencent Cloud requestId:baa30f2e-29f0-48d5-8a88-cc9ed1fab83d

[TencentCloudSDKException] code:FailedOperation.ServiceIsolate message:service is stopped due to arrears, please recharge your account in Tencent Cloud requestId:d5d58117-ab11-4376-9aae-c495a9a0d56a

[En]

[TencentCloudSDKException] code:FailedOperation.ServiceIsolate message:service is stopped due to arrears, please recharge your account in Tencent Cloud requestId:d30fc0b5-60d2-4ecb-b65e-0cb9c0a50bf3

假设有一个点云,有一张桌子和上面的物体。我们希望找到并分割位于平面上的单个物体点簇。假设我们使用 Kd 树结构来寻找最近的邻居,那么算法步骤将是:

1、为输入点云数据集p创建一个 Kd 树表示;

2、建立一个空的集群列表c,以及一个需要检查q的点的队列;

3、然后,对于p中的每一点,执行以下步骤:

  • 将点添加到当前队列q;
  • 对于每一个q中的点:
  • 寻找半径为r球面的点邻域集合;
  • 对于每个邻居,检查该点是否已被处理,如果未处理,则将其添加到q;
  • 处理完q中的所有点的列表后,把q添加到群集列表c中,并重置q为空列表

4、当p中的所有点被处理完后并且都已经属于点集群c的一部分,算法停止。

源码:

创建 cluster_extraction.cpp 文件

  1#include
  2#include
  3#include
  4#include
  5#include
  6#include
  7#include
  8#include
  9#include
 10#include
 11#include
 12
 13
 14int
 15main ()
 16{
 17  // Read in the cloud data
 18  pcl::PCDReader reader;
 19  pcl::PointCloud::Ptr cloud (new pcl::PointCloud), cloud_f (new pcl::PointCloud);
 20  reader.read ("table_scene_lms400.pcd", *cloud);
 21  std::cout << "PointCloud before filtering has: " << cloud->size () << " data points." << std::endl; //*
 22
 23  // Create the filtering object: downsample the dataset using a leaf size of 1cm
 24  pcl::VoxelGrid vg;
 25  pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud);
 26  vg.setInputCloud (cloud);
 27  vg.setLeafSize (0.01f, 0.01f, 0.01f);
 28  vg.filter (*cloud_filtered);
 29  std::cout << "PointCloud after filtering has: " << cloud_filtered->size ()  << " data points." << std::endl; //*
 30
 31  // Create the segmentation object for the planar model and set all the parameters
 32  pcl::SACSegmentation seg;
 33  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
 34  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
 35  pcl::PointCloud::Ptr cloud_plane (new pcl::PointCloud ());
 36  pcl::PCDWriter writer;
 37  seg.setOptimizeCoefficients (true);
 38  seg.setModelType (pcl::SACMODEL_PLANE);
 39  seg.setMethodType (pcl::SAC_RANSAC);
 40  seg.setMaxIterations (100);
 41  seg.setDistanceThreshold (0.02);
 42
 43  int nr_points = (int) cloud_filtered->size ();
 44  while (cloud_filtered->size () > 0.3 * nr_points)
 45  {
 46    // Segment the largest planar component from the remaining cloud
 47    seg.setInputCloud (cloud_filtered);
 48    seg.segment (*inliers, *coefficients);
 49    if (inliers->indices.size () == 0)
 50    {
 51      std::cout << "Could not estimate a planar model for the given dataset." << std::endl;
 52      break;
 53    }
 54
 55    // Extract the planar inliers from the input cloud
 56    pcl::ExtractIndices extract;
 57    extract.setInputCloud (cloud_filtered);
 58    extract.setIndices (inliers);
 59    extract.setNegative (false);
 60
 61    // Get the points associated with the planar surface
 62    extract.filter (*cloud_plane);
 63    std::cout << "PointCloud representing the planar component: " << cloud_plane->size () << " data points." << std::endl;
 64
 65    // Remove the planar inliers, extract the rest
 66    extract.setNegative (true);
 67    extract.filter (*cloud_f);
 68    *cloud_filtered = *cloud_f;
 69  }
 70
 71  // Creating the KdTree object for the search method of the extraction
 72  pcl::search::KdTree::Ptr tree (new pcl::search::KdTree);
 73  tree->setInputCloud (cloud_filtered);
 74
 75  std::vector cluster_indices;
 76  pcl::EuclideanClusterExtraction ec;
 77  ec.setClusterTolerance (0.02); // 2cm
 78  ec.setMinClusterSize (100);
 79  ec.setMaxClusterSize (25000);
 80  ec.setSearchMethod (tree);
 81  ec.setInputCloud (cloud_filtered);
 82  ec.extract (cluster_indices);
 83
 84  int j = 0;
 85  for (std::vector::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
 86  {
 87    pcl::PointCloud::Ptr cloud_cluster (new pcl::PointCloud);
 88    for (const auto& idx : it->indices)
 89      cloud_cluster->push_back ((*cloud_filtered)[idx]); //*
 90    cloud_cluster->width = cloud_cluster->size ();
 91    cloud_cluster->height = 1;
 92    cloud_cluster->is_dense = true;
 93
 94    std::cout << "PointCloud representing the Cluster: " << cloud_cluster->size () << " data points." << std::endl;
 95    std::stringstream ss;
 96    ss << "cloud_cluster_" << j << ".pcd";
 97    writer.write (ss.str (), *cloud_cluster, false); //*
 98    j++;
 99  }
100
101  return (0);
102}

说明:

1、相关头文件

  1#include
  2#include
  3#include
  4#include
  5#include
  6#include
  7#include
  8#include
  9#include
 10#include
 11#include

2、创建读取对象,读取点云数据,输出点云信息

 17  // Read in the cloud data
 18  pcl::PCDReader reader;
 19  pcl::PointCloud::Ptr cloud (new pcl::PointCloud), cloud_f (new pcl::PointCloud);
 20  reader.read ("table_scene_lms400.pcd", *cloud);
 21  std::cout << "PointCloud before filtering has: " << cloud->size () << " data points." << std::endl; //*

3、创建体素滤波对象,对点云数据进行下采样

 23  // Create the filtering object: downsample the dataset using a leaf size of 1cm
 24  pcl::VoxelGrid vg;
 25  pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud);
 26  vg.setInputCloud (cloud);
 27  vg.setLeafSize (0.01f, 0.01f, 0.01f);
 28  vg.filter (*cloud_filtered);
 29  std::cout << "PointCloud after filtering has: " << cloud_filtered->size ()  << " data points." << std::endl; //*

4、为平面模型创建分割对象并设置所有参数

 31  // Create the segmentation object for the planar model and set all the parameters
 32  pcl::SACSegmentation seg;
 33  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
 34  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
 35  pcl::PointCloud::Ptr cloud_plane (new pcl::PointCloud ());
 36  pcl::PCDWriter writer;
 37  seg.setOptimizeCoefficients (true);
 38  seg.setModelType (pcl::SACMODEL_PLANE);
 39  seg.setMethodType (pcl::SAC_RANSAC);
 40  seg.setMaxIterations (100);
 41  seg.setDistanceThreshold (0.02);

5、获取平面分割点云

 43  int nr_points = (int) cloud_filtered->size ();
 44  while (cloud_filtered->size () > 0.3 * nr_points)
 45  {
 46    // Segment the largest planar component from the remaining cloud
 47    seg.setInputCloud (cloud_filtered);
 48    seg.segment (*inliers, *coefficients);
 49    if (inliers->indices.size () == 0)
 50    {
 51      std::cout << "Could not estimate a planar model for the given dataset." << std::endl;
 52      break;
 53    }
 54
 55    // Extract the planar inliers from the input cloud
 56    pcl::ExtractIndices extract;
 57    extract.setInputCloud (cloud_filtered);
 58    extract.setIndices (inliers);
 59    extract.setNegative (false);
 60
 61    // Get the points associated with the planar surface
 62    extract.filter (*cloud_plane);
 63    std::cout << "PointCloud representing the planar component: " << cloud_plane->size () << " data points." << std::endl;
 64
 65    // Remove the planar inliers, extract the rest
 66    extract.setNegative (true);
 67    extract.filter (*cloud_f);
 68    *cloud_filtered = *cloud_f;
 69  }

6、在这里,我们为提取算法的搜索方法创建了一个 KdTree 对象。

 71  // Creating the KdTree object for the search method of the extraction
 72  pcl::search::KdTree::Ptr tree (new pcl::search::KdTree);
 73  tree->setInputCloud (cloud_filtered);

7、在这里,我们正在创建一个PointIndices 数组,其中包含vector

  std::vector cluster_indices;

8、因为我们的点云属于 PointXYZ 类型,我们创建了一个点类型为 PointXYZ 的 EuclideanClusterExtraction 对象。我们还设置了提取的参数和变量。小心为 setClusterTolerance()设置正确的值。如果您采用非常小的值,则可能会将实际 对象_视为多个集群。另一方面,如果您将值设置得太高,则可能会发生多个 _对象 被视为一个集群的情况。因此,我们的建议是测试并尝试哪个值适合您的数据集。

我们要求找到的集群必须至少有setMinClusterSize()点和最大setMaxClusterSize()点。

  pcl::EuclideanClusterExtraction ec;
  ec.setClusterTolerance (0.02); // 2cm
  ec.setMinClusterSize (100);
  ec.setMaxClusterSize (25000);
  ec.setSearchMethod (tree);
  ec.setInputCloud (cloud_filtered);
  ec.extract (cluster_indices);

9、现在,我们从点云中提取聚类,并将索引保存在 cluster _ index 中。为了将每个聚类从vector< PointIndices > 中分离出来,我们必须遍历 cluster _ index,为每个条目创建一个新的 PointCloud,并在 PointCloud 中写入当前集群的所有点。

  int j = 0;
  for (std::vector::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
  {
    pcl::PointCloud::Ptr cloud_cluster (new pcl::PointCloud);
    for (const auto& idx : it->indices)
      cloud_cluster->push_back ((*cloud_filtered)[idx]); //*
    cloud_cluster->width = cloud_cluster->size ();
    cloud_cluster->height = 1;
    cloud_cluster->is_dense = true;

编译并且运行:

1、将以下行添加到 CMakeLists.txt

 1cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
 2
 3project(cluster_extraction)
 4
 5find_package(PCL 1.2 REQUIRED)
 6
 7include_directories(${PCL_INCLUDE_DIRS})
 8link_directories(${PCL_LIBRARY_DIRS})
 9add_definitions(${PCL_DEFINITIONS})
10
11add_executable (cluster_extraction cluster_extraction.cpp)
12target_link_libraries (cluster_extraction ${PCL_LIBRARIES})

2、终端运行

$ ./cluster_extraction

3、输出

PointCloud before filtering has: 460400 data points.

PointCloud after filtering has: 41049 data points.

[SACSegmentation::initSACModel] Using a model of type: SACMODEL_PLANE
[SACSegmentation::initSAC] Using a method of type: SAC_RANSAC with a model threshold of 0.020000
[SACSegmentation::initSAC] Setting the maximum number of iterations to 100
PointCloud representing the planar component: 20522 data points.

[SACSegmentation::initSACModel] Using a model of type: SACMODEL_PLANE
[SACSegmentation::initSAC] Using a method of type: SAC_RANSAC with a model threshold of 0.020000
[SACSegmentation::initSAC] Setting the maximum number of iterations to 100
PointCloud representing the planar component: 12429 data points.

PointCloud representing the Cluster: 4883 data points.

PointCloud representing the Cluster: 1386 data points.

PointCloud representing the Cluster: 320 data points.

PointCloud representing the Cluster: 290 data points.

PointCloud representing the Cluster: 120 data points.

欧几里得聚类提取

欧几里得聚类提取

Original: https://blog.csdn.net/m0_50046535/article/details/125491337
Author: 目标成为slam大神
Title: 欧几里得聚类提取

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/561402/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球