PCL点云库——区域增长分割

9 篇文章 2 订阅
3 篇文章 1 订阅

区域增长分割


  区域生长算法是利用了法线、曲率和颜色等信息来判断点云是否应该聚成一类,适用于特征均匀的连通目标。通过设定的约束条件并结合分割数据的融合需求,利用场景中物体的特征将不同的目标物体从场景中分割出来。PCL中调用区域生长分割类pcl::RegionGrowing,实现区域生长分割算法,算法的目标是按照平滑一致性约束条件合并足够近的点,因此算法的输出是一组集群,且每个集群上的点位于同一个光滑表面。该算法是一种基于点的法线角度差的分割,通过比较种子点与其邻域点之间的法线夹角,将小于平滑阈值(人为设定)的作为同一平滑曲面的部分。
  算法步骤:依据点云的曲率值对输入点云进行排序,选择曲率最小的点作为初始种子点,因为该点所在的区域即为最平滑的区域,从最平滑的区域开始生长可减少分割片段的总数,提高分割效率。初始化一个空的种子点序列和空的聚类区域,从排序后的点云中选好初始种子点添加到种子点序列中,并搜索其邻域点,比较每一个邻域点与当前种子点之间的法线夹角,若所得结果小于平滑阈值(SmoothnessThreshold),则将当前点添加到当前区域,若该邻域点曲率小于曲率阈值(CurvatureThreshold,人为设定),则将其加入到种子点序列中,删除当前种子点,循环执行上述步骤,直到种子序列为空。
  以下实例实现了PCL中的区域增长分割,将分割后的点云按不同颜色显示出来,保存了分割后的各片点云与各片点云的质心。

//****区域增长分割****//

#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d.h>
#include <pcl/segmentation/region_growing.h>
#include <pcl/visualization/cloud_viewer.h>
#include <vector>
#include <string>
#include <atlstr.h>//CString头文件
using namespace std;

int
main (int argc, char** argv)
{
	pcl::PCDReader reader;
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	reader.read("Test.pcd", *cloud);

	//设置默认输入参数
	int KN_normal=50; 
	//bool Bool_Cuting=false;
	float SmoothnessThreshold = 2.5, CurvatureThreshold = 20;

	//法线估计
	pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ> > (new pcl::search::KdTree<pcl::PointXYZ>);//创建一个指向kd树搜索对象的共享指针
	pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>);
	pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator;//创建法线估计对象
	normal_estimator.setSearchMethod (tree);//设置搜索方法
	normal_estimator.setInputCloud(cloud);//设置法线估计对象输入点集
	normal_estimator.setKSearch (KN_normal);// 设置用于法向量估计的k近邻数目
	normal_estimator.compute (*normals);//计算并输出法向量
 
	// 区域生长算法的5个参数
	pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;//创建区域生长分割对象
	reg.setMinClusterSize (100);//设置一个聚类需要的最小点数
	reg.setMaxClusterSize (1000000);//设置一个聚类需要的最大点数
	reg.setSearchMethod (tree);//设置搜索方法
	reg.setNumberOfNeighbours (15);//设置搜索的临近点数目
	reg.setInputCloud(cloud);//设置输入点云
	//pcl::IndicesPtr indices(new std::vector <int>);//创建一组索引
	//if(Bool_Cuting)reg.setIndices (indices);//通过输入参数设置,确定是否输入点云索引
	reg.setInputNormals (normals);//设置输入点云的法向量
	reg.setSmoothnessThreshold (SmoothnessThreshold / 180.0 * M_PI);//设置平滑阈值
	reg.setCurvatureThreshold (CurvatureThreshold);//设置曲率阈值
	std::vector <pcl::PointIndices> clusters;
	reg.extract (clusters);//获取聚类的结果,分割结果保存在点云索引的向量中。

	std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> RegionGrow; //用于储存区域增长分割后的点云
	for (std::vector<pcl::PointIndices>::const_iterator it = clusters.begin(); it != clusters.end(); ++it)
	{
		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
		for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); pit++)
			cloud_cluster->points.push_back(cloud->points[*pit]);
		cloud_cluster->width = cloud_cluster->points.size();
		cloud_cluster->height = 1;
		cloud_cluster->is_dense = true;
		RegionGrow.push_back(cloud_cluster);
	}

	//可视化
	pcl::visualization::PCLVisualizer viewer("PCLVisualizer");
	viewer.initCameraParameters();

	int v1(0);
	viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);
	viewer.setBackgroundColor(128.0 / 255.0, 138.0 / 255.0, 135.0 / 255.0, v1);
	viewer.addText("Cloud before segmenting", 10, 10, "v1 test", v1);
	viewer.addPointCloud<pcl::PointXYZ>(cloud, "cloud", v1);

	int v2(0);
	viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);
	viewer.setBackgroundColor(128.0 / 255.0, 138.0 / 255.0, 135.0 / 255.0, v2);
	viewer.addText("Cloud after segmenting", 10, 10, "v2 test", v2);

	ofstream fout; //c++输出文件流,支持输出c++的数据类型,如string
	fout.open("RGCentroid.txt");
	for (int i = 0; i < RegionGrow.size(); i++)
	{
		//显示分割得到的各片点云
		CString cstr;
		cstr.Format(_T("cloud_segmented%d"), i);
		cstr += _T(".pcd");
		string str_filename = CStringA(cstr);
        /*std::string str_filename = "cloud_segmented";
        str_filename += std::to_string(i);
        str_filename += ".pcd";*/	
		//显示分割得到的各片点云 
		pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color(RegionGrow[i], 255 * (1 - i)*(2 - i) / 2, 255 * i*(2 - i), 255 * i*(i - 1) / 2);
		viewer.addPointCloud(RegionGrow[i], color, str_filename, v2);
		//保存分割得到的各片点云
		pcl::io::savePCDFile(str_filename, *RegionGrow[i]);
		//将分割得到的各片点云的质心保存在.txt文件中
		Eigen::Vector4f RGCentroid;
		pcl::compute3DCentroid(*RegionGrow[i], RGCentroid);//计算点云质心
		fout << "Centroid of " << str_filename << ": " << RGCentroid[0] << " " << RGCentroid[1] << " " << RGCentroid[2] << " " << endl;
	}
	fout.close(); //关闭文件。

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

在这里插入图片描述
  保存下来的各片点云与点云质心文件如下所示:
在这里插入图片描述在这里插入图片描述

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值