PCL——从点云到网格(三)点云到Mesh

更新时间:2023-07-14 07:56:07 阅读: 评论:0

PCL——从点云到⽹格(三)点云到Mesh
通过之前的两篇⽂章,从得到点云,到对点云的下采样,去离群点。接着就是对点云的平滑,计算法线,最后⽣成Mesh。
点云平滑
平滑也是滤波的⼀种,让点云看起来稍微光滑⼀些。存在⼀些不规则数据,很难⽤前⾯提到过的统计分析等滤波⽅法消除,就需要平滑来处理和修复漏洞。
阿克苏人口平滑操作在配准之后。
我使⽤的平滑的⽅法是重采样,实质上是移动最⼩⼆乘(MLS)。
主要的类是 pcl::MovingLeastSquares ,⽤它进⾏重采样操作。
参数啥的我其实还是不会调,还是⽤的别⼈的东西。
//重采样平滑点云
void SmoothPointcloud(pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud_in, pcl::PointCloud<pcl::Point
XYZRGB>::Ptr & cloud_out)
{
// 对点云重采样
std::cout<<"begin smooth: size "<< cloud_in->size()<< std::endl;
pcl::arch::KdTree<pcl::PointXYZRGB>::Ptr treeSampling(new pcl::arch::KdTree<pcl::PointXYZRGB>);// 创建⽤于最近邻搜索的KD-Tree
pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGB> mls;// 定义最⼩⼆乘实现的对象mls
mls.tSearchMethod(treeSampling);// 设置KD-Tree作为搜索⽅法
mls.tComputeNormals(fal);//设置在最⼩⼆乘计算中是否需要存储计算的法线
mls.tInputCloud(cloud_in);//设置待处理点云
mls.tPolynomialOrder(2);// 拟合2阶多项式拟合
杭州有什么好玩的mls.tPolynomialFit(fal);// 设置为fal可以加速 smooth
mls.tSearchRadius(0.05);// 单位m.设置⽤于拟合的K近邻半径
mls.process(*cloud_out);//输出
std::cout <<"success smooth, size: "<< cloud_out->size()<< std::endl;
}
平滑点云之后,开始下⼀步操作:
点云的法向量计算
由于计算点云的法向量⽽不是Mesh的法向量,因此⽐较⿇烦。⽬前是两种重建算法,使⽤曲⾯重建的⽅法 和 使⽤近似值直接从点云中推断法线。
由于刚刚接触,参考资料中使⽤的是后⼀种⽅法,从该点最近邻计算的协⽅差矩阵的特征向量和特征值的分析,直接调⽤PCL封装好的函数即可。
花的歌曲有哪些pcl::NormalEstimation 估计法线的类
//计算法线
pcl::PointCloud<pcl::Normal>::Ptr CalculateNormal(pcl::PointCloud<pcl::PointXYZRGB>::Ptr &cloud_in)
{
// 法线估计
pcl::StopWatch time;
std::cout <<"begin "<< std::endl;
pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> normalEstimation;//创建法线估计的对象
normalEstimation.tInputCloud(cloud_in);//输⼊点云
pcl::arch::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::arch::KdTree<pcl::PointXYZRGB>);// 创建⽤于最近邻搜索的KD-Tree
normalEstimation.tSearchMethod(tree);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);// 定义输出的点云法线
// K近邻确定⽅法,使⽤k个最近点,或者确定⼀个以r为半径的圆内的点集来确定都可以,两者选1即可
normalEstimation.tKSearch(10);// 使⽤当前点周围最近的10个点
//normalEstimation.tRadiusSearch(0.03);            //对于每⼀个点都⽤半径为3cm的近邻搜索⽅式
std::cout <<"success compute normal,time(s):  "<< TimeSeconds()<< std::endl;
公文模板return normals;
}
这个函数是我写的函数,接受输⼊点云Ptr,返回法向量Ptr。normalEstimation.tKSearch(10) 这个参数对于法向量的估计影响还是⽐较⼤的,不能太⼤,也不能太⼩。
之后在计算好了法向量,就可以得到Mesh了。
贪⼼三⾓化算法得到Mesh
点云构成三⾓⽹格的流程。Mesh存储的信息为:顶点索引,边索引,⾯⽚索引。
⽬前⽹格⽣成分为两⼤类算法,插值法(通过原始数据点得到)和逼近法(⽤分⽚线性曲⾯逼近原始点集)。
礼貌原则pcl::GreedyProjectionTriangulation 贪⼼三⾓化算法计算Mesh,使⽤贪⼼投影三⾓化对有向点云进⾏三⾓化,它更适⽤于采样点云来⾃表⾯连续光滑的曲⾯,并且点云的密度变化⽐较均匀的情况。
流程(参考资料上很详细,PCL都封装好了):
1. 先将点云根据法向量投影到某个⼆维平⾯上(为某⼀个样本三⾓⾯⽚);
培养方案
2. 对该平⾯内的投影后的点云做三⾓化(基于Delaunay三⾓剖分 )得到投影后的点的拓扑连接关系
3. 得到拓扑连接之后各三维点的拓扑链接就出来了,得到了Mesh。
在平滑之后要处理掉 InvalidPoints 否则⽆法进⾏Mesh。
#include<pcl/kdtree/kdtree_flann.h>
#include<pcl/features/normal_3d_omp.h>
#include<pcl/features/normal_3d.h>
#include<pcl/surface/mls.h>//最⼩⼆乘重采样平滑
#include<pcl/surface/poisson.h>//泊松重建
#include<pcl/geometry/polygon_mesh.h>//MESH
#include<pcl/surface/gp3.h>//贪⼼三⾓形
//贪⼼三⾓化算法得到Mesh
pcl::PolygonMesh greedy_traingle_GenerateMesh(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_in, pcl::PointCloud<pcl::Normal>::Ptr normals)
{
pcl::StopWatch time;
std::cout <<"begin  "<< std::endl;
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZRGB>());
SmoothPointcloud(cloud_in, cloud_out);
EraInvalidPoints(cloud_out);
// 将点云位姿、颜⾊、法线信息连接到⼀起
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
pcl::concatenateFields(*cloud_in,*normals,*cloud_with_normals);
//定义搜索树对象
pcl::arch::KdTree<pcl::PointXYZRGBNormal>::Ptr tree2(new pcl::arch::KdTree<pcl::PointXYZRGBNormal>);
tree2->tInputCloud(cloud_with_normals);
// 三⾓化
pcl::GreedyProjectionTriangulation<pcl::PointXYZRGBNormal> gp3;// 定义三⾓化对象
pcl::PolygonMesh triangles;//存储最终三⾓化的⽹络模型
// 设置三⾓化参数
gp3.tSearchRadius(0.1);//设置搜索时的半径,也就是KNN的球半径
gp3.tMu(2.5);//设置样本点搜索其近邻点的最远距离为2.5倍(典型值2.5-3),这样使得算法⾃适应点云密度的变化
gp3.tMaximumNearestNeighbors(100);//设置样本点最多可搜索的邻域个数,典型值是50-100
gp3.tMinimumAngle(M_PI /18);// 设置三⾓化后得到的三⾓形内⾓的最⼩的⾓度为10°猪菜
5月22日gp3.tMaximumAngle(2* M_PI /3);// 设置三⾓化后得到的三⾓形内⾓的最⼤⾓度为120°
gp3.tMaximumSurfaceAngle(M_PI /4);// 设置某点法线⽅向偏离样本点法线的最⼤⾓度45°,如果超过,连接时不考虑该点
gp3.tNormalConsistency(fal);//设置该参数为true保证法线朝向⼀致,设置为fal的话不会进⾏法
线⼀致性检查
gp3.tInputCloud(cloud_with_normals);//设置输⼊点云为有向点云
gp3.tSearchMethod(tree2);//设置搜索⽅式
cloud_with_normals->width = cloud_with_normals->height =0;
std::cout <<"success traingles, time(s) "<< TimeSeconds()<< std::endl;
return triangles;
}
pcl::concatenateFields 的两个输⼊点云的⼤⼩⼀定要是⼀样的(点云个数),否则在处理的时候会报错。
点云到Mesh的流程⼤概就是:
下采样,滤波,平滑,法向量,Mesh
Mesh的效果和点云质量相关。我这⾥⽤的是RGB点云,Mesh⾥⾯就⾃带颜⾊的,因此没有Texture也可以看到颜⾊(否则还得⾃⼰做Texture,UV啥的都不会),如果要导⼊Unity,就得改⼀下输出格式和Shader。
这些流程不是最好的,可以做优化,等我学的多⼀些了。。。应该会做⼀下吧

本文发布于:2023-07-14 07:56:07,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1095777.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:法线   设置   得到   搜索   采样   计算   连接
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图