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

news2025/2/22 10:22:20

一、概述

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算法提取点云建筑物轮廓研究 - 豆丁网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1218289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧城市大脑数据中台解决方案:PPT全套37页,附下载

关键词&#xff1a;智慧城市大脑解决方案&#xff0c;数据中台解决方案&#xff0c;智慧城市建设&#xff0c;数据中台建设&#xff0c;智慧城市大脑建设&#xff0c;数据中台建设架构 一、智慧城市大脑数据中台建设背景 智慧城市大脑数据中台是一个面向城市级数据管理、开发和…

双剑合璧:基于Elasticsearch的两路召回语义检索系统,实现关键字与语义的高效精准匹配

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

传递函数的推导和理解

传递函数的推导和理解 假设有一个线性系统&#xff0c;在一般情况下&#xff0c;它的激励 x ( t ) x(t) x(t)与响应 y ( t ) y(t) y(t)所满足的的关系&#xff0c;可用下列微分方程来表示&#xff1a; a n y ( n ) a n − 1 y ( n − 1 ) a n − 2 y ( n − 2 ) ⋯ a 1 y…

1分钟精准预测未来10天天气,谷歌开源GraphCast

11月15日&#xff0c;谷歌旗下著名AI研究机构Deepmind在官网宣布&#xff0c;开源天气大模型GraphCast&#xff0c;并公布了论文。 据悉&#xff0c;GraphCast可以在1分钟内&#xff0c;精准预测而来全球10天的天气情况&#xff0c;同时可以提前预警大暴雨、大风雪、洪水、高温…

【Linux网络】搭建内外网的网关服务器,实现DNS分离解析与DHCP自动分配

一、实验要求&#xff1a; 二、实验思路剖析&#xff1a; 网关服务器&#xff1a; 客户端准备&#xff1a; 实操&#xff1a; 第一步先安装dhcp服务和bind服务 第二步双网卡&#xff0c;配置网卡的ip地址 第三步&#xff1a;开始配置dhcp 第四步&#xff1a;做dns分离解析…

Vue|props配置

props是Vue中用于传递数据的属性。通过在子组件的选项中定义props属性&#xff0c;可以指定子组件可以接收的数据以及其他配置选项。父组件可以通过在子组件上使用特定的属性来传递数据。 目录 目录 App.vue 什么是App.vue 组件引用 props配置 组件复用 案例1&#xff1a…

吉利银河L6顶配 官方OTA升级降低充电速度

互联网是有记忆的 你宣传充电口 卖出去又更新降低速度 属于诈骗 吉利新车上市两个月官降1w,希望大家引以为戒,可以买,但是刚出别着急做韭菜

AE 的软件、硬件、驱动控制、调试策略(没有算法)

#灵感# AE是个值得推敲再推敲的模块&#xff0c;有意思。 目录 相关的硬件-光圈&#xff1a; 相关的软件-曝光-ISO&#xff1a; ISP中的sensor AE 组成&#xff1a; sensor AE的流程及控制&#xff1a; tuning时AE的一些策略&#xff1a; 相关的硬件-光圈&#xff1a; 光…

网络安全(大厂面试真题集)

前言 随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;想要进入到网络安全行业的人也越来越多。 为了拿到心仪的 Offer 之外&#xff0c;除了学好网络安全知识以外&#xff0c;还要应对好企业的面试。 作为一个安全老鸟&#xff0c;工作这么多年…

t-product的matlab实现

t-product是一个比较好的概念&#xff0c;相对应于矩阵中的乘法。 定义如下 这里的 circ(A),MatVec(b) 的定义分别如下 这么定义的原因是为了映射到FFT域里面去&#xff0c;简化计算。 上面的一段摘录说明&#xff1a;直接按照定义来计算&#xff0c;会耗费大量的计算资源。因…

【2.5w字吐血总结 | 新手必看】全网最详细MySQL笔记

写在前面 鉴于全网MySQL知识点的总结分散难懂、良莠不齐&#xff0c;为了避免初学者少走弯路&#xff0c;更好更快地掌握MySQL知识&#xff0c;博主特地将自己所学的笔记分享出来。 如果想深度理解掌握MySQL&#xff0c;欢迎订阅专栏&#xff1a;MySQL进阶之路【秋说】&#…

adguarg通过dns代理全局过滤广告,全系统操作指南

路由器dns配置 安卓(鸿蒙) 设置>>其他网络与连接>>私人DNS&#xff08;不同手机系统设置名称会有些许出入&#xff0c;但是大差不差&#xff09; &#xff08;左图鸿蒙&#xff09;&#xff1a;将域名m.centos.chat填入手机私人DNS IOS系统 将代理服务器IP&am…

delphi电子处方流转(医院)

【delphi电子处方流转(医院)】支持 就诊登记、电子处方上传预核验、处方处方医保电子签名、电子处方上传、电子处方撤销、电子处方信息查询、电子处方审核结果查询、电子处方取药结果查询、电子处方药品目录查询等功能。

UE4动作游戏实例RPG Action解析四:装备系统

导语: 以加血道具为例,详细分析拆解ActionRPG的装备系统,包含装备系统需求和数据结构设计,以及实现 一、装备系统需求: 装备槽: 已获取装备和未获取装备: 当已经装备一个道具时,再次捡到道具,会把道具放在装备库,不会放在装备槽中, 当没有装备道具时,会拾取道具…

Digicert证书:您的网络安全守护神

在当今数字化的世界中&#xff0c;网络安全已经成为每一个企业和个人必须面对的问题。而Digicert品牌证书&#xff0c;就是您网络安全的最佳选择。它不仅具有强大的安全性和稳定性&#xff0c;还能广泛应用于各种场景&#xff0c;为您提供全方位的保护。 首先&#xff0c;我们要…

Xrdp+内网穿透实现远程访问Linux Kali桌面

XrdpCpolar实现远程访问Linux Kali桌面 文章目录 XrdpCpolar实现远程访问Linux Kali桌面前言1. Kali 安装Xrdp2. 本地远程Kali桌面3. Kali 安装Cpolar 内网穿透4. 配置公网远程地址5. 公网远程Kali桌面连接6. 固定连接公网地址7. 固定地址连接测试 前言 Kali远程桌面的好处在于…

【硬核】把一个MOS管制作成开关电路

你要是想读懂这篇文章&#xff0c;请先去了解MOS管的基础知识&#xff0c;本文是在基础之上做出的一部分扩展&#xff0c;可能有一点点深&#xff0c;请各位同学注意。 本文带你了解MOS管的开通/关断原理&#xff0c;使用PMOS做上管、NMOS做下管都是比较方便&#xff0c;使用PM…

腾讯云服务器新用户专享优惠券,腾讯云新用户代金券领取入口汇总

什么是腾讯云新用户专享优惠券&#xff1f; 腾讯云新用户专享优惠券是腾讯云为新用户提供的一种特别优惠。你可以在购买腾讯云服务器时使用这些优惠券&#xff0c;以更低的价格获得优质的云服务。 为了回馈广大新用户&#xff0c;腾讯云服务器推出了一系列优惠活动&#xff0…

KeyarchOS的CentOS迁移实践:使用操作系统迁移工具X2Keyarch V2.0

KeyarchOS的CentOS迁移实践&#xff1a;使用操作系统迁移工具X2Keyarch V2.0 作者&#xff1a; 猫头虎博主 文章目录 KeyarchOS的CentOS迁移实践&#xff1a;使用操作系统迁移工具X2Keyarch V2.0&#x1f405;摘要引言1. 迁移前的精心准备1.1 系统环境介绍1.2 深度数据验证1.2.…

Linux下好玩有趣的指令(持续更新)

适用于centOS下&#xff0c;别的Linux换个指令就行&#xff0c;内容是一样的 centOS有的指令安装不了&#xff1f;试试拓展yum源&#xff0c;再安装基本就OK啦&#xff01; yum install -y epel-release 下面是作者在centOS环境下亲测可以使用的&#xff0c;如果你是root用户直…