PCL点云库学习笔记(3):点云的欧式聚类

初学者笔记:

点云欧式聚类算法流程
(1)点云读入;
(2)体素化下采样(方便处理);
(3)去离散点;
(4)RANSAC算法检测平面,并剔除平面点云;
(5)欧式聚类;
(6)结果的输出和可视化;

点云数据链接:
链接:https://pan.baidu.com/s/1VTVxn3BntbAr9tGHv6L-HA
提取码:u81q

代码:

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL)
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/extract_indices.h>
#include<ctime>
#include<cstdlib>
#include <windows.h>

using namespace pcl;
using namespace std;
typedef PointXYZ PoinT;

int *rand_rgb(){//随机产生颜色
	int *rgb = new int[3];	
	rgb[0] = rand() % 255;
	rgb[1] = rand() % 255;
	rgb[2] = rand() % 255;
	return rgb;
}
int main(){
	//点云的读取*********************************************************
	PointCloud<PoinT>::Ptr cloud(new PointCloud<PoinT>);
	if (io::loadPCDFile("C:\\Users\\Administrator\\Desktop\\desk.pcd", *cloud) == -1)
	{
		PCL_ERROR("read false");
		return 0;
	}
	//体素化下采样******************************************************
	VoxelGrid<PoinT> vox;
	PointCloud<PoinT>::Ptr vox_cloud(new PointCloud<PoinT>);
	vox.setInputCloud(cloud);
	vox.setLeafSize(0.01, 0.01, 0.01);
	vox.filter(*vox_cloud);
	//去除噪声点********************************************************
	StatisticalOutlierRemoval<PoinT>sor;
	PointCloud<PoinT>::Ptr sor_cloud(new PointCloud<PoinT>);
	sor.setMeanK(10);
	sor.setInputCloud(vox_cloud);
	sor.setStddevMulThresh(0.2);
	sor.filter(*sor_cloud);
	//平面分割(RANSAC)********************************************************
	SACSegmentation<PoinT> sac;
	PointIndices::Ptr inliner(new PointIndices);
	ModelCoefficients::Ptr coefficients(new ModelCoefficients);
	PointCloud<PoinT>::Ptr sac_cloud(new PointCloud<PoinT>);
	sac.setInputCloud(sor_cloud);
	sac.setMethodType(SAC_RANSAC);
	sac.setModelType(SACMODEL_PLANE);
	sac.setMaxIterations(100);
	sac.setDistanceThreshold(0.02);
	//提取平面(展示并输出)******************************************************
	PointCloud<PoinT>::Ptr ext_cloud(new PointCloud<PoinT>);
	PointCloud<PoinT>::Ptr ext_cloud_rest(new PointCloud<PoinT>);
	visualization::PCLVisualizer::Ptr viewer(new visualization::PCLVisualizer("3d view"));

	int i = sor_cloud->size(), j = 0;
	ExtractIndices<PoinT>ext;
	srand((unsigned)time(NULL));//刷新时间的种子节点需要放在循环体外面
	while (sor_cloud->size()>i*0.3)//当提取的点数小于总数的3/10时,跳出循环
	{
		ext.setInputCloud(sor_cloud);
		sac.segment(*inliner, *coefficients);
		if (inliner->indices.size()==0)
		{
			break;
		}
		//按照索引提取点云*************
		ext.setIndices(inliner);
		ext.setNegative(false);
		ext.filter(*ext_cloud);
		ext.setNegative(true);
		ext.filter(*ext_cloud_rest);
		//*****************************
		*sor_cloud = *ext_cloud_rest;
		stringstream ss;
		ss <<"C:\\Users\\Administrator\\Desktop\\"<<"ext_plane_clouds" << j << ".pcd";//路径加文件名和后缀
		io::savePCDFileASCII(ss.str(), *ext_cloud);//提取的平面点云写出
		int *rgb = rand_rgb();//随机生成0-255的颜色值
		visualization::PointCloudColorHandlerCustom<PoinT>rgb1(ext_cloud,rgb[0],rgb[1],rgb[2]);//提取的平面不同彩色展示
		delete[]rgb;
		viewer->addPointCloud(ext_cloud, rgb1,ss.str());
		j++;
	}
	viewer->spinOnce(1000);
	//欧式聚类*******************************************************
	vector<PointIndices>ece_inlier;
	search::KdTree<PoinT>::Ptr tree(new search::KdTree<PoinT>);
	EuclideanClusterExtraction<PoinT> ece;
	ece.setInputCloud(sor_cloud);
	ece.setClusterTolerance(0.02);
	ece.setMinClusterSize(100);
	ece.setMaxClusterSize(20000);
	ece.setSearchMethod(tree);
	ece.extract(ece_inlier);
	//聚类结果展示***************************************************
	ext.setInputCloud(sor_cloud);
	visualization::PCLVisualizer::Ptr viewer2(new visualization::PCLVisualizer("Result of EuclideanCluster"));
	srand((unsigned)time(NULL));
	for (int i = 0; i < ece_inlier.size();i++)
	{
		PointCloud<PoinT>::Ptr cloud_copy(new PointCloud<PoinT>);
		vector<int> ece_inlier_ext = ece_inlier[i].indices;
		copyPointCloud(*sor_cloud, ece_inlier_ext, *cloud_copy);//按照索引提取点云数据
		stringstream ss1;
		ss1 <<"C:\\Users\\Administrator\\Desktop\\"<< "EuclideanCluster_clouds" << j<<".pcd";
		io::savePCDFileASCII(ss1.str(), *ext_cloud);//欧式聚类结果写出
		int *rgb1 = rand_rgb();
		visualization::PointCloudColorHandlerCustom<PoinT>rgb2(ext_cloud, rgb1[0], rgb1[1], rgb1[2]);
		delete[]rgb1;
		viewer2->addPointCloud(cloud_copy, rgb2,ss1.str());
		j++;
	}
	viewer2->spin();
	return 0;
}

可视化结果展示:
提取的平面(颜色随机):在这里插入图片描述
欧式聚类的结果(颜色随机):
在这里插入图片描述
写出的点云数据(平面2个,欧式聚类结果5个):
在这里插入图片描述
遇到过error C4996: 'pcl::SAC_SAMPLE_SIZE’编译错误的问题
解决方法参考链接:https://blog.csdn.net/lizhengze1117/article/details/86565100


#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/extract_indices.h>
#include<ctime>
#include<cstdlib>
#include <windows.h>

using namespace pcl;
using namespace std;
typedef PointXYZ PoinT;

int main(){
	//点云的读取*********************************************************
	PointCloud<PoinT>::Ptr cloud(new PointCloud<PoinT>);
	if (io::loadPCDFile("C:\\Users\\admin\\Desktop\\保留的结果.pcd", *cloud) == -1)
	{
		PCL_ERROR("read false");
		return 0;
	}
	//欧式聚类*******************************************************
	vector<PointIndices>ece_inlier;
	search::KdTree<PoinT>::Ptr tree(new search::KdTree<PoinT>);
	EuclideanClusterExtraction<PoinT> ece;
	ece.setInputCloud(cloud);
	ece.setClusterTolerance(1);
	ece.setMinClusterSize(100);
	ece.setMaxClusterSize(20000000000000);
	ece.setSearchMethod(tree);
	ece.extract(ece_inlier);
	//聚类结果展示***************************************************
	PointCloud<PoinT>::Ptr ext_cloud(new PointCloud<PoinT>);
	ExtractIndices<PoinT>ext;
	ext.setInputCloud(cloud);
	visualization::PCLVisualizer::Ptr viewer2(new visualization::PCLVisualizer("Result of EuclideanCluster"));
	srand((unsigned)time(NULL));
	int j = 0;
	vector<unsigned char>color;
	for (int i_segment = 0; i_segment < ece_inlier.size(); i_segment++)
	{
		color.push_back(static_cast<unsigned char>(rand() % 256));
		color.push_back(static_cast<unsigned char>(rand() % 256));
		color.push_back(static_cast<unsigned char>(rand() % 256));
	}
	int color_index = 0;
	PointCloud<PointXYZRGB>::Ptr color_point(new PointCloud<PointXYZRGB>);
	for (int i_seg = 0; i_seg < ece_inlier.size(); i_seg++)
	{
		int clusters_size = ece_inlier[i_seg].indices.size();
		for (int i_idx = 0; i_idx < clusters_size; i_idx++)
		{
			PointXYZRGB point;
			point.x = cloud->points[ece_inlier[i_seg].indices[i_idx]].x;
			point.y = cloud->points[ece_inlier[i_seg].indices[i_idx]].y;
			point.z = cloud->points[ece_inlier[i_seg].indices[i_idx]].z;
			point.r = color[3 * color_index];
			point.g = color[3 * color_index + 1];
			point.b = color[3 * color_index + 2];
			color_point->push_back(point);
		}
		color_index++;
	}
	viewer2->addPointCloud(color_point);
	viewer2->spin();
	return 0;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值