基于PCL库的C++ K-Means点云聚类,从已知点开始
基于PCL库的C++ K-Means点云聚类,从已知点开始
本文将介绍如何使用PCL库进行以已知点为起点的K-Means点云聚类,并提供完整的C++代码示例。
1. 简介
K-Means算法是一种常用的聚类算法,它可以将数据集划分到不同的簇中。在点云处理中,K-Means算法可以用于分割不同的物体或识别点云中的不同区域。
本文将介绍如何使用PCL库中的K-Means算法实现点云聚类,并以一个已知点作为聚类起点。
2. 代码示例cpp#include #include <pcl/io/pcd_io.h>#include <pcl/point_types.h>#include <pcl/features/normal_3d.h>#include <pcl/kdtree/kdtree_flann.h>#include <pcl/segmentation/extract_clusters.h>#include <pcl/visualization/cloud_viewer.h>
int main(int argc, char** argv){ // 加载点云数据 pcl::PointCloudpcl::PointXYZ::Ptr cloud(new pcl::PointCloudpcl::PointXYZ); pcl::PCDReader reader; reader.readpcl::PointXYZ('input_cloud.pcd', *cloud);
// 创建法线估计对象 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setInputCloud(cloud);
// 创建一个空的kdtree对象,并把它传递给法线估计对象 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>()); ne.setSearchMethod(tree);
// 容器存储输出的法线 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
// 估计法线 ne.setKSearch(10); // 设置k近邻搜索的数量 ne.compute(*cloud_normals);
// 创建一个空的kd树对象,并把它传递给聚类对象 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>());
// 创建一个向量存储点云索引 std::vector<pcl::PointIndices> cluster_indices;
// 创建欧氏聚类对象 pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec; ec.setClusterTolerance(0.02); // 设置聚类的容差 ec.setMinClusterSize(100); // 设置聚类的最小点数 ec.setMaxClusterSize(25000); // 设置聚类的最大点数 ec.setSearchMethod(kdtree); ec.setInputCloud(cloud); ec.setIndices(cloud_normals);
// **设置已知点作为聚类起点** pcl::PointXYZ known_point(0.0, 0.0, 0.0); // 设置已知点的坐标 std::vector<int> nearest_indices; std::vector<float> nearest_distances; kdtree->nearestKSearch(known_point, 1, nearest_indices, nearest_distances); int start_index = nearest_indices[0]; ec.setClusterStartIndices({start_index}); // 将已知点的索引作为聚类起点
// 执行聚类 ec.extract(cluster_indices);
// 创建可视化对象 pcl::visualization::PCLVisualizer viewer('Cluster viewer');
// 设置背景颜色 viewer.setBackgroundColor(0, 0, 0);
// 设置点云颜色 pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 0, 255, 0); viewer.addPointCloud<pcl::PointXYZ>(cloud, single_color, 'input_cloud');
// 遍历所有聚类 int cluster_id = 0; for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin(); it != cluster_indices.end(); ++it) { // 创建一个新的点云数据对象,用于存储当前聚类的点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cluster_cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 遍历当前聚类的所有点 for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit) { // 将当前点添加到聚类点云数据对象中 cluster_cloud->points.push_back(cloud->points[*pit]); }
// 设置聚类点云数据对象的属性 cluster_cloud->width = cluster_cloud->points.size(); cluster_cloud->height = 1; cluster_cloud->is_dense = true;
// 设置聚类点云数据对象的颜色 pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cluster_color(cluster_cloud, rand() % 255, rand() % 255, rand() % 255); std::string cluster_name = 'cluster_' + std::to_string(cluster_id); viewer.addPointCloud<pcl::PointXYZ>(cluster_cloud, cluster_color, cluster_name);
// 显示当前聚类的点云数据对象 viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, cluster_name);
// 增加聚类ID cluster_id++; }
// 显示点云数据 while (!viewer.wasStopped()) { viewer.spinOnce(); }
return 0;}
3. 代码解释
- 首先,代码加载点云数据并进行法线估计。法线信息可以帮助提高聚类效果。- 然后,代码创建了一个
pcl::EuclideanClusterExtraction对象,并设置了聚类参数,包括容差、最小点数、最大点数等。- 为了以已知点作为聚类起点,代码使用kdtree->nearestKSearch函数找到距离已知点最近的点的索引,并将该索引作为聚类起点传递给ec.setClusterStartIndices函数。- 最后,代码执行聚类并将结果可视化。
4. 总结
本文介绍了如何使用PCL库进行以已知点为起点的K-Means点云聚类,并提供了完整的C++代码示例。您可以根据自己的需求修改代码中的参数,以获得最佳的聚类效果。
希望这篇文章对您有所帮助!
原文地址: https://www.cveoy.top/t/topic/fC5M 著作权归作者所有。请勿转载和采集!