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

一、概述

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.hqwc.cn/news/186226.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「Verilog学习笔记」用3-8译码器实现全减器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 首先列出3-8译码器和全减器的真值表 全减器真值表如下 3-8译码器真值表如下 timescale 1ns/1nsmodule decoder_38(input E ,input A0 …

这几个站点,有点优秀

中国大学慕课网 网址&#xff1a;https://www.icourse163.org/ 大学生们这个白嫖网站咱一定不能错过&#xff0c;与全国801所高效合作&#xff0c;里面都是不同专业的精品课程&#xff0c;关键是它们都是免费的&#xff01;报名学习&#xff0c;就等着知识装满脑袋吧&#xff0…

leetcode算法之位运算

目录 1.判断字符是否唯一2.丢失的数字3.两整数之和4.只出现一次的数字II5.消失的两个数字6.位1的个数7.比特位计数8.汉明距离 1.判断字符是否唯一 判断字符是否唯一 class Solution { public:bool isUnique(string astr) {//利用鸽巢原理做优化if(astr.size()>26) return…

1694. 重新格式化电话号码

1694. 重新格式化电话号码 Java&#xff1a;while 切糖果 class Solution {public String reformatNumber(String number) {StringBuilder sb new StringBuilder();for (int i 0; i < number.length(); i) {char ch number.charAt(i);if (Character.isDigit(ch)) {sb.a…

粉够荣获淘宝联盟理事会常务理事,共绘联盟生态新篇章

淘宝联盟区域理事会于2021年成立&#xff0c;首届成立成都、广州、武汉&#xff0c;服务近2000个领军淘宝客企业&#xff0c;作为区域生态与官方交流重要枢纽&#xff0c;理事会举办近百场交流分享会&#xff0c;带动淘客跨域跨业态交流成长。 2023年9月7日第二届淘宝联盟理事…

总结 CNN 模型:将焦点转移到基于注意力的架构

一、说明 在计算机视觉时代&#xff0c;卷积神经网络&#xff08;CNN&#xff09;几十年来一直是主导范式。直到 2021 年 Vision Transformers (ViTs) 出现&#xff0c;这个领域才开始发生变化。现在&#xff0c;是时候采用受 Transformer 架构启发的基于注意力的模型了&#x…

vue3+ts扩展全局属性

在使用vue3 ts配置全局变量&#xff0c;需要添加一下扩展 文档 https://cn.vuejs.org/guide/reusability/plugins.html

栈与队列练习题

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

购买阿里云服务器需要多少钱?活动价3000元-5000元的阿里云服务器汇总

购买阿里云服务器需要多少钱&#xff1f;如果我们只有3000元-5000元的预算可以购买什么实例规格和配置的阿里云服务器呢&#xff1f;因为阿里云服务器价格是由实例规格、配置、带宽等众多配置决定的&#xff0c;所以&#xff0c;目前阿里云活动中的价格在3000元-5000元的云服务…

redis常见问题及解决方案

缓存预热 定义 缓存预热是一种优化方案&#xff0c;它可以提高用户的使用体验。 缓存预热是指在系统启动的时候&#xff0c;先把查询结果预存到缓存中&#xff0c;以便用户后面查询时可以直接从缓存中读取&#xff0c;节省用户等待时间 实现思路 把需要缓存的方法写在初始化方…

在计算机领域如神一般存在的人都有哪些?

✍️作者简介&#xff1a;沫小北/码农小北&#xff08;专注于Android、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a;沫小北/码农小北 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&…

AD教程 (十七)3D模型的创建和导入

AD教程 &#xff08;十七&#xff09;3D模型的创建和导入 对于设计者来讲&#xff0c;现在3DPCB比较流行&#xff0c;3DPCB&#xff0c;除了美观之外&#xff0c;做3D的最终的一个目的&#xff0c;是为了去核对结构&#xff0c;就是我们去做了这么一个PCB之后&#xff0c;如果说…