PCL---欧氏聚类分割

基本思想

对空间某点P,通过KD-Tree近邻搜索算法查找k个距离p最近的点,这些点中距离小于设定阈值的便聚类到集合a中。如果Q中元素的数目不在增加,整个聚类过程便结束;否则须在集合Q中选取p点以外的点,重复上述过程,直到Q中元素的数目不在增加为止。

流程图

在这里插入图片描述

完整代码

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/extract_indices.h>       // 根据索引提取点云
#include <pcl/filters/voxel_grid.h>            // 体素滤波
#include <pcl/kdtree/kdtree.h>                 // kd树
#include <pcl/sample_consensus/method_types.h> // 采样方法
#include <pcl/sample_consensus/model_types.h>  // 采样模型
#include <pcl/ModelCoefficients.h>             // 模型系数
#include <pcl/segmentation/sac_segmentation.h> // 随机采样分割
#include <pcl/segmentation/extract_clusters.h> // 欧式聚类分割
#include <pcl/visualization/pcl_visualizer.h> 
#include <boost/thread/thread.hpp>

using namespace std;

int
main(int argc, char** argv)
{
	//--------------------------读取桌面场景点云---------------------------------
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::io::loadPCDFile<pcl::PointXYZ>("table_scene_lms400.pcd", *cloud);
	cout << "读取点云: " << cloud->points.size() << " 个." << endl;

	//---------------------------体素滤波下采样----------------------------------
	pcl::VoxelGrid<pcl::PointXYZ> vg;
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
	vg.setInputCloud(cloud);
	vg.setLeafSize(0.01f, 0.01f, 0.01f);
	vg.filter(*cloud_filtered);
	cout << "体素滤波后还有: " << cloud_filtered->points.size() << " 个." << endl;

	//--------------------创建平面模型分割的对象并设置参数-----------------------
	pcl::SACSegmentation<pcl::PointXYZ> seg;
	pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
	pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane(new pcl::PointCloud<pcl::PointXYZ>);
	seg.setOptimizeCoefficients(true);
	seg.setModelType(pcl::SACMODEL_PLANE);    // 分割模型,平面模型
	seg.setMethodType(pcl::SAC_RANSAC);       // 参数估计方法,随机采样一致性 
	seg.setMaxIterations(100);                // 最大的迭代的次数
	seg.setDistanceThreshold(0.02);           // 设置符合模型的内点阈值

	// -------------模型分割,直到剩余点云数量在30%以上,确保模型点云较好----------
	int i = 0, nr_points = (int)cloud_filtered->points.size();// 下采样前点云数量
	while (cloud_filtered->points.size() > 0.3 * nr_points)

	{
		seg.setInputCloud(cloud_filtered);
		seg.segment(*inliers, *coefficients);// 分割
		if (inliers->indices.size() == 0)
		{
			cout << "Could not estimate a planar model for the given dataset." << endl;
			break;
		}
		//---------------------------根据索引提取点云-------------------------------
		pcl::ExtractIndices<pcl::PointXYZ> extract;
		extract.setInputCloud(cloud_filtered);
		extract.setIndices(inliers);         // 提取符合平面模型的内点
		extract.setNegative(false);
		//--------------------------平面模型内点------------------------------------
		extract.filter(*cloud_plane);
		cout << "平面模型: " << cloud_plane->points.size() << "个点." << endl;
		//-------------------移去平面局内点,提取剩余点云---------------------------
		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_f(new pcl::PointCloud<pcl::PointXYZ>);
		extract.setNegative(true);
		extract.filter(*cloud_f);
		*cloud_filtered = *cloud_f;         // 剩余点云
	}

	// --------------桌子平面上的点云团, 使用欧式聚类的算法对点云聚类分割----------
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
	tree->setInputCloud(cloud_filtered);              // 桌子平面上其他的点云
	vector<pcl::PointIndices> cluster_indices;        // 点云团索引
	pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;// 欧式聚类对象
	ec.setClusterTolerance(0.02);                     // 设置近邻搜索的搜索半径为2cm
	ec.setMinClusterSize(100);                        // 设置一个聚类需要的最少的点数目为100
	ec.setMaxClusterSize(25000);                      // 设置一个聚类需要的最大点数目为25000
	ec.setSearchMethod(tree);                         // 设置点云的搜索机制
	ec.setInputCloud(cloud_filtered);
	ec.extract(cluster_indices);                      // 从点云中提取聚类,并将点云索引保存在cluster_indices中
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster_all(new pcl::PointCloud<pcl::PointXYZ>);
	//------------迭代访问点云索引cluster_indices,直到分割处所有聚类---------------
	int j = 0;
	for (vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin(); it != cluster_indices.end(); ++it)
	{
		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
		//创建新的点云数据集cloud_cluster,将所有当前聚类写入到点云数据集中
		for (vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit)
			cloud_cluster->points.push_back(cloud_filtered->points[*pit]); //获取每一个点云团的点

		cloud_cluster->width = cloud_cluster->points.size();
		cloud_cluster->height = 1;
		cloud_cluster->is_dense = true;

		cout << "PointCloud representing the Cluster: " << cloud_cluster->points.size() << " data points." << endl;
		stringstream ss;
		ss << "cloud_cluster_" << j << ".pcd";
		pcl::PCDWriter writer;
		writer.write<pcl::PointXYZ>(ss.str(), *cloud_cluster, false);
		j++;

		*cloud_cluster_all += *cloud_cluster;
	}
	pcl::io::savePCDFileASCII("cloud_cluster_all.pcd", *cloud_cluster_all);

	//------------------------点云显示------------------------------------
	pcl::visualization::PCLVisualizer viewer("3D Viewer");
	viewer.setBackgroundColor(0, 0, 0);
	//viewer.addCoordinateSystem (1.0);
	viewer.initCameraParameters();
	//--------------------平面上的点云 红色------------------------------
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_plane_handler(cloud_plane, 255, 0, 0);
	viewer.addPointCloud(cloud_plane, cloud_plane_handler, "plan point");
	viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "plan point");

	//--------------------平面外的点云 绿色------------------------------
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_cluster_handler(cloud_cluster_all, 0, 255, 0);
	viewer.addPointCloud(cloud_cluster_all, cloud_cluster_handler, "cloud_cluster point");
	viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud_cluster point");

	while (!viewer.wasStopped()) {
		viewer.spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}
	return (0);
}


结果展示

在这里插入图片描述

获取pcd文件

链接:https://pan.baidu.com/s/1ZcaI4tbeSKHmMDvIg0isYA
提取码:Bing
复制这段内容后打开百度网盘手机App,操作更方便哦

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
点云k-means聚类是一种应用于点云数据的聚类算法,可以通过将点云数据划分为不同的簇来实现数据的分类和分割PCL(点云库)是一个用于点云处理的开源库,其中包含了用于点云k-means聚类的Python模块。 点云k-means聚类的过程如下:首先,选取合适数量(k)的初始聚类中心点。然后,将每个点与聚类中心点进行距离计算,并将其分配给离其最近的中心点所对应的聚类。接着,根据每个聚类中的点重新计算其聚类中心点。重复以上两个步骤,直到聚类中心点的位置不再变化或者达到预定的迭代次数为止。 使用PCL库的Python模块,在进行点云k-means聚类时,首先需要导入相关的模块和数据。然后,通过调用PCL库中的聚类算法函数,传入点云数据和所需的聚类数量k。接着,可以设置聚类算法的参数,如迭代次数、收敛阈值等。最后,调用聚类算法函数来执行点云k-means聚类,并获取聚类的结果。 在得到点云k-means聚类的结果后,可以对每个聚类进行进一步的操作,如可视化显示每个聚类的点云数据、计算每个聚类的质心或其他统计量等。此外,可以根据具体的需求调整聚类算法的参数,以获得更好的聚类效果。 总而言之,点云k-means聚类是一种有效的点云数据处理方法,可通过使用PCL库的Python模块来实现。该方法可以对点云数据进行分类和分割,从而对点云数据进行更深入的分析和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bingo-yy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值