pcl--第十节 点云曲面重建

曲面重建技术在逆向工程、数据可视化、机器视觉、虚拟现实、医疗技术等领域中得到了广泛的应用 。 例如,在汽车、航空等工业领域中,复杂外形产品的设计仍需要根据手工模型,采用逆向工程的手段建立产品的数字化模型,根据测量数据建立人体以及骨骼和器官的计算机模型,在医学、定制生产等方面都有重要意义 。

除了上述传统的行业,随着新兴的廉价 RGBD 获取设备在数字娱乐行业的病毒式扩展,使得更多人开始使用点云来处理对象并进行工程应用 。 根据重建曲面和数据点云之间的关系,可将曲面重建分为两大类:插值法和逼近法。前者得到的重建曲面完全通过原始数据点,而后者则是用分片线性曲面或其他形式的曲面来逼近原始数据点,从而使得得到的重建曲面是原始点集的一个逼近曲面。

关联知识:

Search、KdTree、Octree

基于多项式重构的平滑和法线估计¶

本教程说明如何使用移动最小二乘(MLS)曲面重构方法来平滑和重采样噪声数据。

使用统计分析很难消除某些数据不规则性(由较小的距离测量误差引起)。要创建完整的模型,必须考虑光滑的表面以及数据中的遮挡。在无法获取其他扫描的情况下,一种解决方案是使用重采样算法,该算法尝试通过周围数据点之间的高阶多项式插值来重新创建表面的缺失部分。通过执行重采样,可以纠正这些小的错误,并且可以将多个扫描记录在一起执行平滑操作合并成同一个点云。

_images/resampling_1.jpg

在上图的左侧,我们在包含两个配准点云的数据集中看到了配准后的效果及表面法线估计。由于对齐错误,所产生的法线有噪声。在右侧,使用移动最小二乘法对表面法线估计进行平滑处理后,在同一数据集中看到了该效果。绘制每个点的曲率,作为重新采样前后特征值关系的度量,我们得到:

_images/resampling_2.jpg

 

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
//#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/surface/mls.h>
#include <pcl/search/kdtree.h>
int
main ()
{// Load input file into a PointCloud<T> with an appropriate typepcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ> ());// Load bun0.pcd -- should be available with the PCL archive in test pcl::io::loadPCDFile ("table_scene_lms400_downsampled.pcd", *cloud);// Create a KD-Tree//pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>()); // kd树对象// Output has the PointNormal type in order to store the normals calculated by MLSpcl::PointCloud<pcl::PointNormal> mls_points;// Init object (second point type is for the normals, even if unused)pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls;mls.setComputeNormals (true);// Set parametersmls.setInputCloud (cloud);mls.setPolynomialOrder (2);mls.setSearchMethod (tree);mls.setSearchRadius (0.03);// Reconstructmls.process (mls_points);// Save outputpcl::io::savePCDFile ("table_scene_lms400_downsampled-mls.pcd", mls_points);
}

右边是重建后,会发现比左边更平整

在平面模型上提取凸(凹)多边形

学习如何为平面模型上的点集提取其对应的凹多边形的例子,该例首先从点云中提取平面模型,再通过该估计的平面模型系数从滤波后的点云投影一组点集形成点云,最后为投影后的点云计算其对应的二维凸(凹)多边形。

#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/project_inliers.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/surface/convex_hull.h>intmain ()
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>), cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>), cloud_projected (new pcl::PointCloud<pcl::PointXYZ>);pcl::PCDReader reader;reader.read ("table_scene_mug_stereo_textured.pcd", *cloud);// Build a filter to remove spurious NaNs and scene backgroundpcl::PassThrough<pcl::PointXYZ> pass;pass.setInputCloud (cloud);pass.setFilterFieldName ("z");pass.setFilterLimits (0, 1.1);pass.filter (*cloud_filtered);std::cerr << "PointCloud after filtering has: " << cloud_filtered->size () << " data points." << std::endl;pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);pcl::PointIndices::Ptr inliers (new pcl::PointIndices);// Create the segmentation objectpcl::SACSegmentation<pcl::PointXYZ> seg;// Optionalseg.setOptimizeCoefficients (true);// Mandatoryseg.setModelType (pcl::SACMODEL_PLANE);seg.setMethodType (pcl::SAC_RANSAC);seg.setDistanceThreshold (0.01);seg.setInputCloud (cloud_filtered);seg.segment (*inliers, *coefficients);// Project the model inlierspcl::ProjectInliers<pcl::PointXYZ> proj;proj.setModelType (pcl::SACMODEL_PLANE);proj.setInputCloud (cloud_filtered);proj.setIndices (inliers);proj.setModelCoefficients (coefficients);proj.filter (*cloud_projected);// Create a Convex Hull representation of the projected inlierspcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);pcl::ConvexHull<pcl::PointXYZ> chull;chull.setInputCloud (cloud_projected);chull.reconstruct (*cloud_hull);std::cerr << "Convex hull has: " << cloud_hull->size () << " data points." << std::endl;pcl::PCDWriter writer;writer.write ("table_scene_mug_stereo_textured_hull.pcd", *cloud_hull, false);return (0);
}

#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/project_inliers.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/surface/concave_hull.h>int
main ()
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>), cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>), cloud_projected (new pcl::PointCloud<pcl::PointXYZ>);pcl::PCDReader reader;reader.read ("table_scene_mug_stereo_textured.pcd", *cloud);// Build a filter to remove spurious NaNs and scene backgroundpcl::PassThrough<pcl::PointXYZ> pass;pass.setInputCloud (cloud);pass.setFilterFieldName ("z");pass.setFilterLimits (0, 1.1);pass.filter (*cloud_filtered);std::cerr << "PointCloud after filtering has: "<< cloud_filtered->size () << " data points." << std::endl;pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);pcl::PointIndices::Ptr inliers (new pcl::PointIndices);// Create the segmentation objectpcl::SACSegmentation<pcl::PointXYZ> seg;// Optionalseg.setOptimizeCoefficients (true);// Mandatoryseg.setModelType (pcl::SACMODEL_PLANE);seg.setMethodType (pcl::SAC_RANSAC);seg.setDistanceThreshold (0.01);seg.setInputCloud (cloud_filtered);seg.segment (*inliers, *coefficients);std::cerr << "PointCloud after segmentation has: "<< inliers->indices.size () << " inliers." << std::endl;// Project the model inlierspcl::ProjectInliers<pcl::PointXYZ> proj;proj.setModelType (pcl::SACMODEL_PLANE);// proj.setIndices (inliers);proj.setInputCloud (cloud_filtered);proj.setModelCoefficients (coefficients);proj.filter (*cloud_projected);std::cerr << "PointCloud after projection has: "<< cloud_projected->size () << " data points." << std::endl;// Create a Concave Hull representation of the projected inlierspcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);pcl::ConcaveHull<pcl::PointXYZ> chull;chull.setInputCloud (cloud_projected);chull.setAlpha (0.1);chull.reconstruct (*cloud_hull);std::cerr << "Concave hull has: " << cloud_hull->size ()<< " data points." << std::endl;pcl::PCDWriter writer;writer.write ("table_scene_mug_stereo_textured_hull.pcd", *cloud_hull, false);return (0);
}

 无序点云的快速三角化

本小节介绍了怎样使用贪婪投影三角化算法对有向点云进行三角化,具体方法是先将有向点云投影到某一局部二维坐标平面内,再在坐标平面内进行平面内的三角化,再根据平面内三位点的拓扑连接关系获得一个三角网格曲面模型。贪婪投影三角化算法原理是处理一系列可以使网格“生长扩大”的点(边缘点)延伸这些点直到所有符合几何正确性和拓扑正确性的点都被连上。该算法的优点是可以处理来自一个或者多个扫描仪扫描得到并且有多个连接处的散乱点云。但该算法也有一定的局限性,它更适用于采样点云来自于表面连续光滑的曲面且点云密度
变化比较均匀的情况。该算法的三角化过程是局部进行的,首先沿着一点的法线将该点投影到局部二维坐标平面内并连接其他悬空点,然后再进行下一点。所以这里设置如下参数:

  1. 函数 SetMaximumNearestNeighbors(unsigned)和 SetMu(double),这两个函数的作用是控制搜索邻域大小。前者定义了可搜索的邻域个数,后者规定了被样本点搜索其邻近点的最远距离(是为了适应点云密度的变化),特征值一般是 50~100和2.5~3(或者15每栅格)。
  2. 函数SetSearchRadius(double),该函数设置了三角化后得到的每个三角形的最大可能边长。
  3. 函数SetMinimumAngle(double)和 SetMaximumAngle(double),这两个函数是三角化后每个三角形的最大角和最小角。两者至少要符合一个,典型值分别是10和120°(弧度)。
  4. 函数 SetMaximumSurfaceAgle(double)和 SetNormalConsistency(bool),这两个函数是为了处理边缘或者角很尖锐以及一个表面的两边非常靠近的情况。为了处理这些特殊情况,函数SetMaximumSurfaceAgle(double)规定如果某点法线方向的偏离超过指定角度(注:大多数表面法线估计方法可以估计出连续变化的表面法线方向,即使在尖锐的边缘条件下),该点就不连接到样本点上。该角度是通过计算法向线段(忽略法线方向)之间的角度。函数SetNormalConsistency(bool)保证法线朝向,如果法线方向一致性标识没有设定,就不能保证估计出的法线都可以始终朝向一致。第一个函数特征值为45(弧度)第二个函数默认值为false。
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/search/kdtree.h> // for KdTree
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/surface/organized_fast_mesh.h>
int
main ()
{// Load input file into a PointCloud<T> with an appropriate typepcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);pcl::PCLPointCloud2 cloud_blob;pcl::io::loadPCDFile ("bunny.pcd", cloud_blob);pcl::fromPCLPointCloud2 (cloud_blob, *cloud);//* the data should be available in cloud// Normal estimation*pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);tree->setInputCloud (cloud);n.setInputCloud (cloud);n.setSearchMethod (tree);n.setKSearch (20);n.compute (*normals);//* normals should not contain the point normals + surface curvatures// Concatenate the XYZ and normal fields*pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals (new pcl::PointCloud<pcl::PointNormal>);pcl::concatenateFields (*cloud, *normals, *cloud_with_normals);//* cloud_with_normals = cloud + normals// Create search tree*pcl::search::KdTree<pcl::PointNormal>::Ptr tree2 (new pcl::search::KdTree<pcl::PointNormal>);tree2->setInputCloud (cloud_with_normals);// Initialize objectspcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3;pcl::PolygonMesh triangles;// Set the maximum distance between connected points (maximum edge length)gp3.setSearchRadius (0.02);// Set typical values for the parametersgp3.setMu (2.5);gp3.setMaximumNearestNeighbors (100);gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degreesgp3.setMinimumAngle(M_PI/18); // 10 degreesgp3.setMaximumAngle(2*M_PI/3); // 120 degreesgp3.setNormalConsistency(false);// Get resultgp3.setInputCloud (cloud_with_normals);gp3.setSearchMethod (tree2);gp3.reconstruct (triangles);// Additional vertex informationstd::vector<int> parts = gp3.getPartIDs();std::vector<int> states = gp3.getPointStates();// Finishpcl::visualization::PCLVisualizer viewer("Triangulation");viewer.setBackgroundColor(0.0, 0.0, 0.0);viewer.addPointCloud<pcl::PointXYZ>(cloud, "input_cloud");viewer.addPolygonMesh(triangles, "triangles", 0);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "input_cloud");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0.0, 1.0, 0.0, "triangles");viewer.spin();return (0);
}

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

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

相关文章

Eclipse ABAP ADT 集成详细安装教程

最近看到网上有个源码使用CDS做的&#xff0c;然后看了一下原来还可以用eclipse&#xff0c;趁热打铁&#xff0c;试了一把&#xff0c;最后成功了&#xff0c;中间可能会有一些报错&#xff0c;可以自己慢慢解决&#xff0c;大概就是这样的。 SAP的开发&#xff0c;有三种开发…

基于YOLOv8模型的条形码二维码检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的条形码二维码检测系统可用于日常生活中检测与定位条形码与二维码目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测…

机器学习笔记:概念对比——损失函数,代价函数,目标函数

损失函数 Loss Function 通常是针对单个训练样本而言 给定一个模型输出 和一个真实值y &#xff0c;损失函数是 代价函数 Cost Function 通常是针对整个训练集&#xff08;或者在使用 mini-batch gradient descent 时一个 mini-batch&#xff09;的总损失 目标函数 Objec…

ultraEdit正则匹配多行(xml用)

在ultraEdit中&#xff0c;我想选取<channel到</channel>之间的多行&#xff08;进行删除&#xff09;。在perl模式下&#xff0c;命令为“<channel[\s\S]?</channel>”。下面是xml文件&#xff1a; <!--This XML file does not appear to have any sty…

MySQL数据库 -- 入门篇

1. MySQL概述 1.1 数据库相关概念 三个概念&#xff1a;数据库、数据库管理系统、SQL。 目前主流的关系型数据库管理系统的市场占有率排名如下&#xff1a; Oracle&#xff1a;大型的收费数据库&#xff0c;Oracle公司产品&#xff0c;价格昂贵。MySQL&#xff1a;开源免费…

linux 设置打开文件数

可以使用下面的文件进行设置 /etc/security/limits.d/90-nproc.conf 先来看/etc/security/limits.d/90-nproc.conf 配置文件&#xff1a; [root ~]# cat /etc/security/limits.d/90-nproc.conf # Default limit for number of users processes to prevent # accidental fork…

HCIE-容器docker

1、安装配置操作系统&#xff0c;使用CentOS stream 8镜像 之前&#xff1a;RHEL 8.4 发布了&#xff0c;CentOS紧随其后&#xff0c;发布CentOS 8.4 之后&#xff1a;CentOS 走在前面&#xff0c;成为RHEL上游&#xff0c;再去发布RHEL 制作模板&#xff0c;模板配置要求&…

tomcat架构概览

https://blog.csdn.net/ldw201510803006/article/details/119880100 前言 Tomcat 要实现 2 个核心功能&#xff1a; 处理 Socket 连接&#xff0c;负责网络字节流与 Request 和 Response 对象的转化。加载和管理 Servlet&#xff0c;以及具体处理 Request 请求。 因此 Tomc…

Flink--4、DateStream API(执行环境、源算子、基本转换算子)

星光下的赶路人star的个人主页 注意力的集中&#xff0c;意象的孤立绝缘&#xff0c;便是美感的态度的最大特点 文章目录 1、DataStream API1.1 执行环境&#xff08;Execution Environment&#xff09;1.1.1 创建执行环境 1.2 执行模式&#xff08;Execution Mode&#xff09;…

uni-app实现web-view图片长按下载

<template><view><web-view :webview-styles"webviewStyles" :src"webUrl"></web-view></view> </template> uniapp的web-view中图片无法长按保存&#xff0c;IOS下是正常的&#xff0c;但是Android下长按无反应 解…

大模型训练显存优化推理加速方案

当前的深度学习框架大都采用的都是fp32来进行权重参数的存储&#xff0c;比如Python float的类型为双精度浮点数fp64&#xff0c;pytorch Tensor的默认类型为单精度浮点数fp32。随着模型越来越大&#xff0c;加速训练模型的需求就产生了。在深度学习模型中使用fp32主要存在几个…

Prometheus+Grafana可视化监控【Redis状态】

文章目录 一、安装Docker二、安装Redis数据库(Docker容器方式)三、安装Prometheus四、安装Grafana五、Pronetheus和Grafana相关联六、安装redis_exporter七、Grafana添加Redis监控模板 一、安装Docker 注意&#xff1a;我这里使用之前写好脚本进行安装Docker&#xff0c;如果已…