点云的网格化【Win10+VS2015】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YunLaowang/article/details/87714576

本文为参考【计算机视觉life】公众号的系列文章:从零开始一起学习SLAM | 点云到网格的进化,实现的点云网格化过程。

网格化流程

  1. 下采样+统计滤波
    通过下采样减少点云数据容量、提高处理速度;使用统计分析技术,去除点云数据集中的噪声、离群点;
滤波前后对比
  1. 重采样,平滑处理
    通过重采样对物体表面进行平滑处理和漏洞修复
点云平滑前后
  1. 计算点云表面法线
    计算点云法线,并将点云位姿、颜色、法线信息合并到一起,构建有向点云。
点云表面法线
  1. 网格化
    使用贪心投影三角化算法对有向点云进行三角化,实现稀疏点云的网格化。
点云网格化示例

代码

/****************************
 * 给定稠密的点云,进行如下操作:
 * 		下采样和滤波、重采样平滑、法线计算,贪心投影网格化。
****************************/
#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;
}

结果

  • 备注:
    所需点云源文件【公众号提供】:h?ttps://pan?.baidu.com/s/1avSGdi4IG3ry3wNCI_jDLQ 提?取?码:cxjy(删除"?"即可访问)

猜你喜欢

转载自blog.csdn.net/YunLaowang/article/details/87714576