当前位置: 首页 > article >正文

1欧几里得聚类提取

欧几里得聚类提取

在本教程中,我们将学习如何使用 class 提取 Euclidean 簇。为了不使 教程中,它的某些元素,例如平面分割算法, 这里就不解释了。请查看 平面模型分割教程 以了解更多信息。pcl::EuclideanClusterExtraction

理论入门

代码

首先,下载数据集 table_scene_lms400.pcd 并将其保存到磁盘的某个位置。

然后,创建一个文件,比如说,在你的收藏夹中 编辑器,并将以下内容放入其中:cluster_extraction.cpp

  1#include <pcl/ModelCoefficients.h>
  2#include <pcl/point_types.h>
  3#include <pcl/io/pcd_io.h>
  4#include <pcl/filters/extract_indices.h>
  5#include <pcl/filters/voxel_grid.h>
  6#include <pcl/features/normal_3d.h>
  7#include <pcl/search/kdtree.h>
  8#include <pcl/sample_consensus/method_types.h>
  9#include <pcl/sample_consensus/model_types.h>
 10#include <pcl/segmentation/sac_segmentation.h>
 11#include <pcl/segmentation/extract_clusters.h>
 12#include <iomanip> // for setw, setfill
 13
 14int 
 15main ()
 16{
 17  // Read in the cloud data
 18  pcl::PCDReader reader;
 19  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>), cloud_f (new pcl::PointCloud<pcl::PointXYZ>);
 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<pcl::PointXYZ> vg;
 25  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
 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<pcl::PointXYZ> seg;
 33  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
 34  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
 35  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane (new pcl::PointCloud<pcl::PointXYZ> ());
 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<pcl::PointXYZ> 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<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
 73  tree->setInputCloud (cloud_filtered);
 74
 75  std::vector<pcl::PointIndices> cluster_indices;
 76  pcl::EuclideanClusterExtraction<pcl::PointXYZ> 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 (const auto& cluster : cluster_indices)
 86  {
 87    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>);
 88    for (const auto& idx : cluster.indices) {
 89      cloud_cluster->push_back((*cloud_filtered)[idx]);
 90    } //*
 91    cloud_cluster->width = cloud_cluster->size ();
 92    cloud_cluster->height = 1;
 93    cloud_cluster->is_dense = true;
 94
 95    std::cout << "PointCloud representing the Cluster: " << cloud_cluster->size () << " data points." << std::endl;
 96    std::stringstream ss;
 97    ss << std::setw(4) << std::setfill('0') << j;
 98    writer.write<pcl::PointXYZ> ("cloud_cluster_" + ss.str () + ".pcd", *cloud_cluster, false); //*
 99    j++;
100  }
101
102  return (0);
103}

解释

现在,让我们逐个分解代码,跳过显而易见的。

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

              .
              .
              .

    while (cloud_filtered->size () > 0.3 * nr_points)
    {

              .
              .
              .

            // Remove the plane inliers, extract the rest
      extract.setNegative (true);
      extract.filter (*cloud_f);
cloud_filtered = cloud_f;
    }

上面的代码已经在其他教程中进行了描述,因此您可以阅读 那里的解释(特别是 Plane model segmentation 和 Extracting indices from a PointCloud)。

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

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

  std::vector<pcl::PointIndices> cluster_indices;

在这里,我们将创建一个 PointIndices 的向量,其中包含 vector<int> 中的实际索引信息。检测到的每个 cluster 保存在此处 - 请注意 cluster_indices 是一个 vector 包含每个检测到的集群的一个 PointIndices 实例。所以 cluster_indices[0] 包含了点云中第一个集群的所有索引。

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

在这里,我们将创建一个具有点类型的 EuclideanClusterExtraction 对象 PointXYZ 的 URL,因为我们的点云是 PointXYZ 类型。我们还将 参数和变量。小心设置正确的 setClusterTolerance() 的值。如果采用非常小的值,则可以 碰巧一个实际的对象可以看作是多个集群。另一方面 如果将该值设置得太高,则可能会发生多个对象被视为一个群集的情况。因此,我们的建议是测试和试用 哪个值适合您的数据集。

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

现在我们从点云中提取集群并将索引保存在 cluster_indices 中。为了将每个集群从 vector<PointIndices 中分离出来>我们必须遍历 cluster_indices,为 每个条目,并将当前集群的所有点写入 PointCloud。

  int j = 0;
  for (const auto& cluster : cluster_indices)
  {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>);
    for (const auto& idx : cluster.indices) {
      cloud_cluster->push_back((*cloud_filtered)[idx]);
    } //*
    cloud_cluster->width = cloud_cluster->size ();
    cloud_cluster->height = 1;
    cloud_cluster->is_dense = true;

编译和运行程序

将以下行添加到您的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})

创建可执行文件后,您可以运行它。只需:

$ ./cluster_extraction

您将看到类似于以下内容的内容:

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.

您还可以查看输出 cloud_cluster_0000.pcd、cloud_cluster_0001.pcd、 cloud_cluster_0002.pcd、cloud_cluster_0003.pcd 和 cloud_cluster_0004.pcd:

$ ./pcl_viewer cloud_cluster_0000.pcd cloud_cluster_0001.pcd cloud_cluster_0002.pcd cloud_cluster_0003.pcd cloud_cluster_0004.pcd

现在,您可以在一个查看器中看到不同的集群。您应该会看到 类似于以下内容:


http://www.kler.cn/news/324099.html

相关文章:

  • WPF入门教学二十二 多线程与异步编程
  • Django——admin创建和使用
  • 【Python游戏开发】扫雷游戏demo
  • Linux云计算 |【第四阶段】RDBMS1-DAY2
  • 使用python获取百度一下,热搜TOP数据详情
  • 什么是聚类?
  • Docker数据卷有哪些常见的驱动类型?
  • K8S真正删除pod
  • SeeClick: Harnessing GUI Grounding for Advanced Visual GUI Agents论文学习
  • socket编程描述tcp的三次握手
  • Postman/Jmeter接口测试
  • MATLAB中的并行计算:提升性能的策略与实践
  • 有关若依菜单管理的改造
  • 动手学深度学习(李沐)PyTorch 第 4 章 多层感知机
  • golang Unicode api接口
  • 【C++】vector 常用成员函数的模拟实现
  • 使用Go语言的互斥锁(Mutex)解决并发问题
  • Goland的使用
  • 青动CRM-仓储云V1.1.2
  • 第十七节 鼠标的操作与相应
  • Three.js粒子系统与特效
  • 16年408-数据结构
  • C0003.用C++开发Qt界面,针对无边框界面,实现界面可任意拖动
  • 单片机配置IO口输出模式(IO口依然可以读取电平变化)
  • 函数内部的 arguments 变量特性,属性,如何将他转换为数组
  • AVL树(平衡二叉树)的介绍以及相关构建
  • Augular 学习步骤建议
  • 并查集 (Union-Find) :从基础到优化
  • C++学习笔记(35)
  • 数组的练习