PCL 区域生长分割(Segmentation_RegionGrowing)

PCL专栏目录及须知

注意:区域生长分割,对于分割建筑物或地面的各个平面,有较好的效果。

1.区域生长分割

将具有法线或者曲率相似性的点云集合起来构成一簇聚类点

(1)计算点云法线及曲率。

(2)根据点云的曲率值对输入点云进行排序,选择曲率最小的点作为初始种子点P(曲率最小处即为点云最平滑处)。

(3)搜索P邻域点,比较邻域点与当前种子点之间的法线夹角和曲率差,如果领域点同种子点的法线夹角小于法线阈值、曲率差小于曲率阈值,那么该邻域点同当前点P为一簇点。

(4)对P的所有邻域点执行(3)的搜索步骤,直到无法再往当前点云簇中添加点,记录当前点云簇。

(5)重复步骤(2)-(4),遍历计算所有点云点,得到所有点云簇。

即类似于欧式聚类,从初始点开始摸点云,摸出所有点云簇,只是判断法则从距离阈值变为了法线夹角和曲率差

如下图:

假设我们计算得到的最小曲率初始点P在红色部分中,

1)我们首先通过法线夹角和曲率差,不停摸完附近点云,直到摸无可摸,得到红色簇的点云簇。

2)更换初始点P的位置(红色簇已聚类,被剔除,因此只能在其他点云中得到初始点P)。假设更换后的初始点P在蓝色簇中,再进行1)的步骤,摸出蓝色簇。

3)如此反复,直到得到所有点云点。

2.使用介绍

对于分割建筑物或地面的各个平面,有较好的效果,工作中经常使用。

3.关键函数

(1)法向量夹角的阈值,超过这个夹角,即认为不在一个平面上

segmentation.setSmoothnessThreshold(pcl::deg2rad(3.0));	

(2)曲率的阈值,超过这个阈值,即认为不在一个平面上

segmentation.setCurvatureThreshold(1.0);

4.完整代码

#include <vector>
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/search/kdtree.h>
#include <pcl/common/angles.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/segmentation/region_growing.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>

int main(int )
{
	/****************区域生长分割********************/
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);				// 源点云
	pcl::io::loadPCDFile("D:/code/csdn/data/JZDM.pcd", *cloud);
	pcl::PointCloud<pcl::PointXYZ>::Ptr resultCloud(new pcl::PointCloud<pcl::PointXYZ>);		// 结果点云

	// 区域生长分割
	// 法线和表面曲率估计
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
	pcl::PointCloud <pcl::Normal>::Ptr normals(new pcl::PointCloud <pcl::Normal>);
	pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;
	n.setInputCloud(cloud);
	n.setSearchMethod(tree);
	n.setNumberOfThreads(6);																	// 设置线程数
	n.setKSearch(20);																			// k近邻数目
	n.compute(*normals);

	// 区域生长分割
	pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> segmentation;
	segmentation.setMinClusterSize(50);															// 一簇聚类最小点数
	segmentation.setMaxClusterSize(1000000);													// 一簇聚类最大点数
	segmentation.setSearchMethod(tree);
	segmentation.setNumberOfNeighbours(30);														// K邻域搜索点个数
	segmentation.setInputCloud(cloud);
	segmentation.setInputNormals(normals);
	segmentation.setSmoothnessThreshold(pcl::deg2rad(3.0));										// 法向量夹角的阈值,超过这个夹角,即认为不在一个平面上
	segmentation.setCurvatureThreshold(1.0);													// 曲率的阈值,超过这个阈值,即认为不在一个平面上

	std::vector <pcl::PointIndices> clustersIndices;											// 聚类结果
	segmentation.extract(clustersIndices);

	// 提取聚类后点云
	std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clustreClouds;
	for (size_t i = 0; i < clustersIndices.size(); i++)
	{
		pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTemp(new pcl::PointCloud<pcl::PointXYZ>);
		pcl::copyPointCloud(*cloud, clustersIndices[i], *cloudTemp);
		clustreClouds.push_back(cloudTemp);
	}

	/****************展示********************/
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("EuclideanClusterExtraction"));
	for (size_t i = 0; i < clustreClouds.size(); i++)
	{
		pcl::RGB rgb = pcl::getRandomColor(0, 255);
		viewer->addPointCloud<pcl::PointXYZ>(clustreClouds.at(i), pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>(clustreClouds.at(i), rgb.r, rgb.g, rgb.b), "clustreClouds" + i);
	}

	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}

	return (0);
}

5.结果展示

分割前的点云:

分割后的点云(分割出了各个平面):

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值