Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/YunLaowang/article/details/87714576
This article is a reference [computer vision] public life number of series: to learn from scratch with SLAM | point cloud to the evolution of the grid , grid point cloud implementation process.
Gridding process
- + Downsampling statistical filtering
sampling point cloud data by reducing the capacity, improve the processing speed; using statistical analysis techniques to remove noise point cloud data set, outliers;
![](https://img-blog.csdnimg.cn/20190219162948879.jpg)
Comparison before and after filtering
- Resampling, the smoothing processing
for smoothing the surface of the object and bug fixes by resampling
![](https://img-blog.csdnimg.cn/20190219162018183.jpg)
Before and after the point cloud smoothing
- Computing surface normals point cloud
computing cloud point normals, position and orientation point cloud and, color, normal information is merged together, constructed with the point cloud.
![](https://img-blog.csdnimg.cn/20190219162752986.jpg)
Point cloud surface normal
- Gridding
using projection greedy triangulation algorithm have to triangulate point clouds, achieve grid sparse point cloud.
![](https://img-blog.csdnimg.cn/20190219163141865.jpg)
Example grid point cloud
Code
/****************************
* 给定稠密的点云,进行如下操作:
* 下采样和滤波、重采样平滑、法线计算,贪心投影网格化。
****************************/
#include <pcl/point_types.h>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/radius_outlier_removal.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/surface/mls.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>
#include <pcl/surface/poisson.h>
typedef pcl::PointXYZ PointT;
int main(int argc, char** argv)
{
// Load input file
pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
pcl::PointCloud<PointT>::Ptr cloud_downSampled(new pcl::PointCloud<PointT>);
pcl::PointCloud<PointT>::Ptr cloud_filtered(new pcl::PointCloud<PointT>);
pcl::PointCloud<PointT>::Ptr cloud_smoothed(new pcl::PointCloud<PointT>);
if (pcl::io::loadPCDFile("fusedCloud.pcd", *cloud) == -1)
{
cout << "could not load the file..." << endl;
}
std::cout << "Orginal points number: " << cloud->points.size() << std::endl;
// 1.下采样,同时保持点云形状特征
pcl::VoxelGrid<PointT> downSampled; // 下采样对象
downSampled.setInputCloud(cloud);
downSampled.setLeafSize(0.01f, 0.01f, 0.01f); // 栅格叶的尺寸
downSampled.filter(*cloud_downSampled);
// 2.统计滤波
pcl::StatisticalOutlierRemoval<PointT> sor; // 滤波对象
sor.setInputCloud(cloud_downSampled);
sor.setMeanK(50);
sor.setStddevMulThresh(1.0); // 设置判定为离群点的阈值
sor.filter(*cloud_filtered);
// 3.对点云重采样,进行平滑
pcl::search::KdTree<PointT>::Ptr treeSampling(new pcl::search::KdTree<PointT>); // 创建用于最近邻搜索的KD-Tree
pcl::MovingLeastSquares<PointT, PointT> mls; // 定义最小二乘实现的对象mls
mls.setComputeNormals(false); // 设置在最小二乘计算中是否需要存储计算的法线
mls.setInputCloud(cloud_filtered); // 设置待处理点云
mls.setPolynomialOrder(2); // 拟合2阶多项式拟合
mls.setPolynomialFit(false); // 设置为false可以 加速 smooth
mls.setSearchMethod(treeSampling); // 设置KD-Tree作为搜索方法
mls.setSearchRadius(0.05); // 单位m.设置用于拟合的K近邻半径
mls.process(*cloud_smoothed); // 输出
// 4.法线估计
pcl::NormalEstimation<PointT, pcl::Normal> normalEstimation; // 创建法线估计的对象
normalEstimation.setInputCloud(cloud_smoothed); // 输入点云
pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>); // 创建用于最近邻搜索的KD-Tree
normalEstimation.setSearchMethod(tree);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>); // 定义输出的点云法线
// K近邻确定方法,使用k个最近点,或者确定一个以r为半径的圆内的点集来确定都可以,两者选1即可
normalEstimation.setKSearch(10); // 使用当前点周围最近的10个点
//normalEstimation.setRadiusSearch(0.03); // 对于每一个点都用半径为3cm的近邻搜索方式
normalEstimation.compute(*normals); // 计算法线
// 5.将点云位姿、颜色、法线信息连接到一起
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields(*cloud_smoothed, *normals, *cloud_with_normals);
// 6.贪心投影三角化
//定义搜索树对象
pcl::search::KdTree<pcl::PointNormal>::Ptr tree2(new pcl::search::KdTree<pcl::PointNormal>);
tree2->setInputCloud(cloud_with_normals);
// 三角化
pcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3; // 定义三角化对象
pcl::PolygonMesh triangles; // 存储最终三角化的网络模型
// 设置三角化参数
gp3.setSearchRadius(0.1); // 设置搜索时的半径,也就是KNN的球半径
gp3.setMu(2.5); // 设置样本点搜索其近邻点的最远距离为2.5倍(典型值2.5-3),这样使得算法自适应点云密度的变化
gp3.setMaximumNearestNeighbors(100); // 设置样本点最多可搜索的邻域个数,典型值是50-100
gp3.setMinimumAngle(M_PI / 18); // 设置三角化后得到的三角形内角的最小的角度为10°
gp3.setMaximumAngle(2 * M_PI / 3); // 设置三角化后得到的三角形内角的最大角度为120°
gp3.setMaximumSurfaceAngle(M_PI / 4); // 设置某点法线方向偏离样本点法线的最大角度45°,如果超过,连接时不考虑该点
gp3.setNormalConsistency(false); // 设置该参数为true保证法线朝向一致,设置为false的话不会进行法线一致性检查
gp3.setInputCloud(cloud_with_normals); // 设置输入点云为有向点云
gp3.setSearchMethod(tree2); // 设置搜索方式
gp3.reconstruct(triangles); // 重建提取三角化
// 7.显示网格化结果
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0); // 设置背景
viewer->addPolygonMesh(triangles, "mesh"); // 网格化点云添加到视窗
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 1;
}
result
![](https://img-blog.csdnimg.cn/20190219165109521.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1l1bkxhb3dhbmc=,size_16,color_FFFFFF,t_70)
- Note:
the desired point cloud number provided the source file [public]: h? ttps: // pan? .baidu.com / s / 1avSGdi4IG3ry3wNCI_jDLQ mention? take? Code: cxjy (Delete to access the "?")