欢迎点云相关产学研的学者和团体加入我们。
本小节我们一起学习如何为平面模型上的点集提取其对应的凹多边形的例子,该例首先从点云中提取平面模型,在通过该估计的平面模型系数从滤波后的点云投影一组点集形成点云,最后为投影后的点云计算其对应的二维凸(凹)多边形。
首先,在PCL(Point Cloud Learning)中国协助发行的书[1]提供光盘的第15章例2文件夹中,打开名为concave_hull_2d.cpp的代码文件,同文件夹下可以找到相关的测试点云文件table_scene_mug_stereo_textured.pcd。
本节只给出了创建凹多边形的程序,如果你想要创建凸多边形,只需要把本小节中所有“凹”换成“凸”,包括源文件、文件名和CMakeListss.txt文件。同时还需要将函数setAlpha()注释掉,因为它并不适用于凸多边形算法相关的类。
下面对打开的文件关键语句进行解析。
#include <pcl/ModelCoefficients.h> //采样一致性模型相关类头文件
#include <pcl/io/pcd_io.h> //打开关闭pcd文件的类定义的头文件
#include <pcl/point_types.h> //PCL中所有点类型定义的头文件
#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> //创建凹多边形类定义的头文件
以上代码是与本程序相关的类和函数的头文件声明。
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); //读取点云数据
//建立一个过滤器来消除杂散的NaN
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud (cloud); //设置输入点云
pass.setFilterFieldName ("z"); //设置分割字段为z坐标
pass.setFilterLimits (0, 1.1);//设置分割阈值范围为(0,1.1),将z轴方向超过该范围的点集过滤掉
pass.filter (*cloud_filtered);
std::cerr <<"PointCloud after filtering has: "
<< cloud_filtered->points.size () <<" data points."<< std::endl;
以上代码完成对点云的滤波预处理,提高后续的分割的效果,首先打开点云,然后使用直通滤波处理掉点云中z轴方向上超过(0,1.1)范围的点集,然后打印相关信息输出到标准输出设备上。
pcl::PointIndices::Ptr inliers (new pcl::PointIndices); // inliers指针存储点云分割后的结果
pcl::SACSegmentation<pcl::PointXYZ> seg; //创建分割对象
seg.setOptimizeCoefficients (true); //设置优化系数,该参数为可选设置
//以下四种设置为必须设置,否则算法不能正常工作
seg.setModelType (pcl::SACMODEL_PLANE);//设置分割模型类型为SACMODEL_PLANE,本例中需要使用平面模型
seg.setMethodType (pcl::SAC_RANSAC);//设置采样一致性估计方法模型为SAC_RANSAC
seg.setDistanceThreshold (0.01);//设置距离阈值为0.01,与估计平面模型的距离小于0.01m的点都为内点inliers
seg.setInputCloud (cloud_filtered);//设置输入点云为滤波后点云
seg.segment (*inliers, *coefficients);//成员inliers、coefficients
以上代码创建了分割对象并设置了一些参数,在这个例子里我们使用SACMODEL_PLANE模型来分割点云,用来估计出该模型系数的方法是SAC_RANSAC(随机抽样一致性算法),当调用seg.segment (*inliers, *coefficents)时,分割就执行了,将所有的内点(平面上的点)存储到inliers成员中、将估计的平面模型系数
pcl::ProjectInliers<pcl::PointXYZ> proj; //点云投影滤波对象
proj.setModelType (pcl::SACMODEL_PLANE);//设置投影模型为SACMODEL_PLANE。
proj.setInputCloud (cloud_filtered); //设置输入点云为滤波后的点云cloud_filtered。
proj.setModelCoefficients (coefficients);//将估计得到的平面coefficients参数设置为投影平面模型系数
proj.filter (*cloud_projected); //将滤波后的点云投影到平面模型中得到投影后的点云cloud_projected
以上代码是将上面得到的滤波后的点集投影到平面模型上,并存储投影后的点云数据到cloud_projected对象。创建cloud_projected有两种方法,其中一种方法是直接提取之前得到的内点集合,不过这个例子里我们打算用到之前得到的coefficents参数,建立平面模型后按照coefficents参数对该投影对象进行设置,然后将cloud_filtered投射到coefficients参数确定的平面模型上,就可以产生投影后的点云cloud_projected。
//存储提取多边形上的点
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);
pcl::ConcaveHull<pcl::PointXYZ> chull; //创建多边形提取对象
chull.setInputCloud (cloud_projected); //设置输入点云为投影后点云cloud_projected
chull.setAlpha (0.1); //设置alpha值为0.1
chull.reconstruct (*cloud_hull); //重建提取创建凹多边形
以上代码负责执行ConcaveHull对象的创建和重建获取点云对应的凹多边形边界上的点,后面就是打印出相关信息与存储最终获取的多边形边界点。
未完待续,敬请关注“在平面模型上提取凸(凹)多边形(2)”的编译运行程序的结果等。