一、简介
《点云库PCL从入门到精通》P350
二、代码分析
1)加载下采样文件,以点云对象指针的形式进行保存:
// Load input file into a PointCloud<T> with an appropriate type
//将一个xyz点类型的pcd打开并存储到对象PointCloud中
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); //定义点云对象指针用于保存点云文件
pcl::PCLPointCloud2::Ptr cloud_blob(new pcl::PCLPointCloud2); //定义点云对象指针用于加载下采样后的点云
pcl::io::loadPCDFile ("table_scene_lms400_downsampled.pcd", *cloud_blob); //打开下采样文件
pcl::fromPCLPointCloud2(*cloud_blob, *cloud); //将下采样文件作为模板进行保存
//* the data should be available in cloud
2)构建法线估计的对象:
// 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>); //定义kd tree指针
tree->setInputCloud (cloud); //用点云来构建树
n.setInputCloud (cloud); //为法线估计对象输入点云
n.setSearchMethod (tree); //设置法线估计对象的搜索方法
n.setKSearch (20); //设置k搜索的k值为20
n.compute (*normals); //估计法线存储结果到normals中
//* normals should not contain the point normals + surface curvatures
3)将点云与发现进行字段拼接,构成一个有向点云,在有向点云中构建kd tree:
// 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>); //构建一个kd tree对象
tree2->setInputCloud (cloud_with_normals); //将kd tree的输入点云设置为有向点云对象
4)初始化三角化对象,并设置相应的参数:
// Initialize objects
pcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3; //初始化一个贪婪三角化对象
pcl::PolygonMesh triangles; //存储最终三角化的网络模型
// Set the maximum distance between connected points (maximum edge length)
gp3.setSearchRadius (0.025); //设置连接点之间的最大距离(即为三角形最大边长)
// Set typical values for the parameters
gp3.setMu (2.5); //设置样本点搜索其邻近点的最远距离为2.5,为了适应点云密度的变化
gp3.setMaximumNearestNeighbors (100); //设置样本点可搜索的邻域个数为100
gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degrees //设置某点法线方向偏离样本点法线方向的最大角度为45度
gp3.setMinimumAngle(M_PI/18); // 10 degrees //设置三角形化后得到的三角形内角最小角度为10度
gp3.setMaximumAngle(2*M_PI/3); // 120 degrees //设置三角形化后得到的三角形内角最大角度为120度
gp3.setNormalConsistency(false); //设置该参数保证法线朝向一致
// Get result
gp3.setInputCloud (cloud_with_normals); //设置输入点云为有向点云
gp3.setSearchMethod (tree2); //设置搜索方法
gp3.reconstruct (triangles); //重建提取三角化
5)整体代码
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
int main(int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); //智能指针加载点云数据
pcl::PCLPointCloud2::Ptr cloud_blob(new pcl::PCLPointCloud2);
pcl::io::loadPCDFile("table_scene_lms400_downsampled.pcd", *cloud_blob);
pcl::fromPCLPointCloud2(*cloud_blob, *cloud);
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>); //智能指针存储kd tree
tree->setInputCloud(cloud);
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(20);
n.compute(*normals); //执行法线估计
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>); //将点云与法线进行字段拼接
pcl::concatenateFields(*cloud, *normals, *cloud_with_normals);
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.025); //设置两点之间的最近距离
gp3.setMu(2.5);
gp3.setMaximumNearestNeighbors(100); //设置最大近邻点的个数
gp3.setMaximumSurfaceAngle(M_PI / 4); //设置最大搜索角度
gp3.setMinimumAngle(M_PI / 18); //设置最小角度
gp3.setMaximumAngle(2 * M_PI / 3); //设置最大角度
gp3.setNormalConsistency(false); //是否考虑法线
gp3.setInputCloud(cloud_with_normals);
gp3.setSearchMethod(tree2);
gp3.reconstruct(triangles); //利用三角形进行重构
std::vector<int>parts = gp3.getPartIDs(); //贪婪三角形可视化
std::vector<int>states = gp3.getPointStates();
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0);
viewer->addPolygonMesh(triangles, "my");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return(0);
}
三、编译结果