PCL 提取点云边界轮廓-AC方法、平面轮廓

34 篇文章 26 订阅

一、概述

PCL点云边界特征检测 (附完整代码 C++)_pcl计算点云特征值_McQueen_LT的博客-CSDN博客

在点云的边界特征检测(网格模型的边界特征检测已经是一个确定性问题了,见 网格模型边界检测)方面,PCL中有一个针对点云边界的可以称作为是s t a t e − o f − t h e − a r t state-of-the-artstate−of−the−art的方法,这个方法出自 D e t e c t i n g   H o l e s   i n   P o i n t   S e t   S u r f a c e s Detecting\space Holes\space in\space Point\space Set\space SurfacesDetecting Holes in Point Set Surfaces这篇论文,叫做 A n g l e   C r i t e r i o n Angle\ CriterionAngle Criterion,简称 A C ACAC。这篇论文中还提出了另一种检测边界的方法是H a l f d i s c   C r i t e r i o n Halfdisc\ CriterionHalfdisc Criterion,H d C HdCHdC。目前PCL中应该只集成了A C ACAC,因为这个方法确实比H d C HdCHdC好,已经够用了。这两种方法的思路都非常简单,但是却非常有效,而往往流传下来的经典方法都是这种简单有效的方法。

二、AC方法步骤讲解

 

三、AC方法代码

原始点云:

计算步骤

1、计算点云的法向量

2、计算点云的边界

3、显示

代码


int PointCloudBoundary2(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{

	// 1 计算法向量
	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::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
	normalEstimation.setInputCloud(cloud);
	normalEstimation.setSearchMethod(tree);
	normalEstimation.setRadiusSearch(0.02);  // 法向量的半径
	normalEstimation.compute(*normals);

	/*pcl计算边界*/
	pcl::PointCloud<pcl::Boundary>::Ptr boundaries(new pcl::PointCloud<pcl::Boundary>); //声明一个boundary类指针,作为返回值
	boundaries->resize(cloud->size()); //初始化大小
	pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> boundary_estimation; //声明一个BoundaryEstimation类
	boundary_estimation.setInputCloud(cloud); //设置输入点云
	boundary_estimation.setInputNormals(normals); //设置输入法线
	pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree_ptr(new pcl::search::KdTree<pcl::PointXYZ>);
	boundary_estimation.setSearchMethod(kdtree_ptr); //设置搜寻k近邻的方式
	boundary_estimation.setKSearch(30); //设置k近邻数量
	boundary_estimation.setAngleThreshold(M_PI * 0.6); //设置角度阈值,大于阈值为边界
	boundary_estimation.compute(*boundaries); //计算点云边界,结果保存在boundaries中
	
	cout << "边界点云的点数   :  "<< boundaries->size()<< endl;


	/*可视化*/
	pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_visual(new pcl::PointCloud<pcl::PointXYZRGB>);
	pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_boundary(new pcl::PointCloud<pcl::PointXYZRGB>);
	cloud_visual->resize(cloud->size());
	for (size_t i = 0; i < cloud->size(); i++)
	{
		cloud_visual->points[i].x = cloud->points[i].x;
		cloud_visual->points[i].y = cloud->points[i].y;
		cloud_visual->points[i].z = cloud->points[i].z;
		if (boundaries->points[i].boundary_point != 0)
		{
			cloud_visual->points[i].r = 255;
			cloud_visual->points[i].g = 0;
			cloud_visual->points[i].b = 0;
			cloud_boundary->push_back(cloud_visual->points[i]);
		}
		else
		{
			cloud_visual->points[i].r = 255;
			cloud_visual->points[i].g = 255;
			cloud_visual->points[i].b = 255;
		}
	}
	pcl::io::savePCDFileBinaryCompressed("D:\\work\\Pointclouds\\clouds\\all.pcd", *cloud_visual);
	pcl::io::savePCDFileBinaryCompressed("D:\\work\\Pointclouds\\clouds\\boundaries.pcd", *cloud_boundary);
	return 0;
}

显示

	boundary_estimation.setKSearch(30); //设置k近邻数量
	boundary_estimation.setAngleThreshold(M_PI * 0.6); //设置角度阈值,大于阈值为边界
	boundary_estimation.compute(*boundaries); //计算点云边界,结果保存在boundaries中


M_PI*0.6 

M_PI*0.8

四、平面轮廓

原始点云:

步骤:

1、采用RANSAC提取平面

2、提取平面

代码:


int PointCloudBoundary2(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{

	// 1 计算法向量
	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::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
	normalEstimation.setInputCloud(cloud);
	normalEstimation.setSearchMethod(tree);
	normalEstimation.setRadiusSearch(0.02);  // 法向量的半径
	normalEstimation.compute(*normals);

	/*pcl计算边界*/
	pcl::PointCloud<pcl::Boundary>::Ptr boundaries(new pcl::PointCloud<pcl::Boundary>); //声明一个boundary类指针,作为返回值
	boundaries->resize(cloud->size()); //初始化大小
	pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> boundary_estimation; //声明一个BoundaryEstimation类
	boundary_estimation.setInputCloud(cloud); //设置输入点云
	boundary_estimation.setInputNormals(normals); //设置输入法线
	pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree_ptr(new pcl::search::KdTree<pcl::PointXYZ>);
	boundary_estimation.setSearchMethod(kdtree_ptr); //设置搜寻k近邻的方式
	boundary_estimation.setKSearch(30); //设置k近邻数量
	boundary_estimation.setAngleThreshold(M_PI * 0.8); //设置角度阈值,大于阈值为边界
	boundary_estimation.compute(*boundaries); //计算点云边界,结果保存在boundaries中
	
	cout << "边界点云的点数   :  "<< boundaries->size()<< endl;


	/*可视化*/
	pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_visual(new pcl::PointCloud<pcl::PointXYZRGB>);
	pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_boundary(new pcl::PointCloud<pcl::PointXYZRGB>);
	cloud_visual->resize(cloud->size());
	for (size_t i = 0; i < cloud->size(); i++)
	{
		cloud_visual->points[i].x = cloud->points[i].x;
		cloud_visual->points[i].y = cloud->points[i].y;
		cloud_visual->points[i].z = cloud->points[i].z;
		if (boundaries->points[i].boundary_point != 0)
		{
			cloud_visual->points[i].r = 255;
			cloud_visual->points[i].g = 0;
			cloud_visual->points[i].b = 0;
			cloud_boundary->push_back(cloud_visual->points[i]);
		}
		else
		{
			cloud_visual->points[i].r = 255;
			cloud_visual->points[i].g = 255;
			cloud_visual->points[i].b = 255;
		}
	}
	pcl::io::savePCDFileBinaryCompressed("D:\\work\\Pointclouds\\clouds\\all22.pcd", *cloud_visual);
	pcl::io::savePCDFileBinaryCompressed("D:\\work\\Pointclouds\\clouds\\boundaries222.pcd", *cloud_boundary);
	return 0;
}
/// <summary>
///   先提取点云的平面然后在进行边界林廓
/// </summary>
/// <param name="cloud"></param>
/// <returns></returns>
int  PlaneCloudContour(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{

	// 0 计算法向量
	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::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
	normalEstimation.setInputCloud(cloud);
	normalEstimation.setSearchMethod(tree);
	normalEstimation.setRadiusSearch(0.02);  // 法向量的半径
	normalEstimation.compute(*normals);


	 // 1 提出出平面 
		// 提取平面点云的索引
	pcl::PointIndices::Ptr  index_plane(new pcl::PointIndices);
	pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> sacSegmentationFromNormals;
	pcl::ModelCoefficients::Ptr mdelCoefficients_plane(new pcl::ModelCoefficients);
	sacSegmentationFromNormals.setInputCloud(cloud);
	sacSegmentationFromNormals.setOptimizeCoefficients(true);//设置对估计的模型系数需要进行优化
	sacSegmentationFromNormals.setModelType(pcl::SACMODEL_NORMAL_PLANE); //设置分割模型
	sacSegmentationFromNormals.setNormalDistanceWeight(0.1);//设置表面法线权重系数
	sacSegmentationFromNormals.setMethodType(pcl::SAC_RANSAC);//设置采用RANSAC作为算法的参数估计方法
	sacSegmentationFromNormals.setMaxIterations(500); //设置迭代的最大次数
	sacSegmentationFromNormals.setDistanceThreshold(0.05); //设置内点到模型的距离允许最大值
	sacSegmentationFromNormals.setInputCloud(cloud);
  	sacSegmentationFromNormals.setInputNormals(normals);
	sacSegmentationFromNormals.segment(*index_plane, *mdelCoefficients_plane);
	std::cerr << "Plane coefficients: " << *mdelCoefficients_plane << std::endl;

	 // 点云提取
	pcl::ExtractIndices<pcl::PointXYZ> extractIndices;
	pcl::PointCloud<pcl::PointXYZ>::Ptr  cloud_p(new pcl::PointCloud<pcl::PointXYZ>);
	extractIndices.setInputCloud(cloud);
	extractIndices.setIndices(index_plane);
	extractIndices.setNegative(false);
	extractIndices.filter(*cloud_p);
	pcl::io::savePCDFileBinaryCompressed("D:\\work\\Pointclouds\\clouds\\planeCloud.pcd",*cloud_p);
	 // 2  
	PointCloudBoundary2(cloud_p);
	return 0;
}

 结果:

平面点云的轮廓线计算-alpha shapes算法原理和实现_α-shape算法-CSDN博客

双阈值Alpha Shapes算法提取点云建筑物轮廓研究 - 豆丁网

  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于PCL(Point Cloud Library)的点云边界提取可以通过以下步骤实现: 首先,需要加载点云数据,可以从文件中加载或者实时采集。 其次,利用PCL中的NormalEstimation类估计点云数据的法向量。法向量是计算边界的重要依据,能够帮助确定点云中的表面变化。 然后,使用PCL中的BoundaryEstimation类来估计点云边界。该类会根据法向量和点云数据的几何信息来确定点云边界点,生成一个包含边界点索引的输出向量。 最后,可以根据边界点的索引,从原始点云数据中提取边界点的信息,包括坐标和其他属性。 以下是一个简单的C++代码示例,演示了如何使用PCL进行点云边界提取: ```cpp #include <pcl/point_cloud.h> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d.h> #include <pcl/features/boundary.h> int main () { // 读取点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile ("cloud.pcd", *cloud); // 估计法向量 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setInputCloud (cloud); pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ()); ne.setSearchMethod (tree); pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>); ne.setKSearch (20); ne.compute (*normals); // 边界提取 pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> est; pcl::PointCloud<pcl::Boundary> boundaries; est.setInputCloud (cloud); est.setInputNormals (normals); est.setRadiusSearch (0.02); est.setAngleThreshold (M_PI/4); est.setSearchMethod (tree); est.compute (boundaries); // 提取边界点 for (size_t i = 0; i < boundaries.points.size (); ++i) { if (boundaries.points[i].boundary_point) std::cout << "边界点索引: " << i << " - " << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z << std::endl; } return (0); } ``` 这段代码首先加载了一个点云数据文件"cloud.pcd",然后进行法向量估计和边界提取,最后输出了边界点的坐标信息。通过这个代码示例,可以实现基于PCL的点云边界提取功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值