本教程学习使用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/
转载文章受原作者版权保护。转载请注明原作者出处!