一、简介
在平面模型上构建凸(凹)多边形,首先从点云中提取平面模型,在通过该估计的平面模型系数从滤波后的点云投影一组点集形成点云,最后为投影后的点云计算其对应的二维凸(凹多边形)。
二、代码分析
1)构建直通滤波器,对点云进行滤波处理,提高后续的分割的效果,然后打印相关信息输出到标准输出设备上:
reader.read ("table_scene_mug_stereo_textured.pcd", *cloud);//读取点云数据
// Build a filter to remove spurious NaNs
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;
2)创建分割对象并设置一些参数,使用SACMODEL_PLANE模型来分割点云,用来估计出该模型系数的方法是SAC_RANSAC(随机抽样一致性算法),当调用seg.segment(*inliers, *coefficents)时,分割就执行了,将所有的内点存储到inliers成员中、将屏幕估计的平面模型系数(ax + by + cz = d)存储到coefficient成员中:
pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers (new pcl::PointIndices);//inliers指针存储点云分割后的结果
// Create the segmentation object
pcl::SACSegmentation<pcl::PointXYZ> seg;//创建分割对象
// Optional
seg.setOptimizeCoefficients (true);//设置优化系数,该参数是可选设置
// Mandatory
seg.setModelType (pcl::SACMODEL_PLANE);//设置分割模型类型为SACMODEL_PLANE,本例中需要使用平面模型
seg.setMethodType (pcl::SAC_RANSAC);//设置采样一致性估计方法模型为SAC_RANSC
seg.setDistanceThreshold (0.01);//设置距离阈值为0.01,与孤寂平面模型的距离小于0.01m的点都为内点
seg.setInputCloud (cloud_filtered);//设置输入点云为滤波后点云
seg.segment (*inliers, *coefficients);//成员inliers、coefficients
std::cerr << "PointCloud after segmentation has: "
<< inliers->indices.size () << " inliers." << std::endl;
3)将上面得到的滤波后的点集投影到平面模型上,并存储投影后的点云数据到cloud_projected对象。创建cloud_projected有两种方法,其中一种方法是直接提取之前得到的内点集合,不过这个例子里我们打算用之前得到的coefficients参数,建立平面模型后按照coefficients参数对该投影对象进行设置,然后将cloud_filtered投射到coefficients参数确定的平面模型上,就可以产生投影后的点云cloud_projected:
// Project the model inliers
pcl::ProjectInliers<pcl::PointXYZ> proj;//点云投影滤波对象
proj.setModelType (pcl::SACMODEL_PLANE);//设置投影模型为SACMODEL_PLANE
proj.setInputCloud (cloud_filtered);//设置输入点云为滤波后的点云
proj.setModelCoefficients (coefficients);//将估计得到的平面coefficients参数设置为投影平面模型系数
proj.filter (*cloud_projected);//将滤波后的点云投影到平面模型中得到投影后的点云
std::cerr << "PointCloud after projection has: "
<< cloud_projected->points.size () << " data points." << std::endl;
4)执行ConcaveHull对象的创建和重建获取点云对应的凹多边形边界上的点:
// Create a Concave Hull representation of the projected inliers
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);
pcl::ConcaveHull<pcl::PointXYZ> chull;//创建多边形提取对象
chull.setInputCloud (cloud_projected);//设置输入点云为投影后的点云
chull.setAlpha (0.1);//设置alpha的值为0.1
chull.reconstruct (*cloud_hull);//重建提取创建凹多边形
std::cerr << "Concave hull has: " << cloud_hull->points.size ()
<< " data points." << std::endl;
5)整体代码:
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#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>
int main(int argc, char** argv)
{
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);
pcl::PassThrough<pcl::PointXYZ> pass; //进行直通滤波
pass.setInputCloud(cloud); //输入滤波点云
pass.setFilterFieldName("z"); //设置滤波字段
pass.setFilterLimits(0, 1.1); //设置滤波范围
pass.filter(*cloud_filtered);
std::cerr << "PointCloud after filtering has:" << cloud_filtered->points.size() << " data points." << std::endl;
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients); //加载模型参数
pcl::PointIndices::Ptr inliers(new pcl::PointIndices); //设置内点指针
pcl::SACSegmentation<pcl::PointXYZ> seg; //根据模型参数完成滤波
seg.setOptimizeCoefficients(true); //设置优化系数,该参数是可选设置
seg.setModelType(pcl::SACMODEL_PLANE); //设置分割模型
seg.setMethodType(pcl::SAC_RANSAC); //设置分割方法为随机一致性
seg.setDistanceThreshold(0.01); //设置距离阈值0.01
seg.setInputCloud(cloud_filtered); //设置输入点云为过滤后的点云
seg.segment(*inliers, *coefficients); //根据模型参数分割内点
std::cerr << "PointCloud after segmentation has " << inliers->indices.size() << " inliers." << std::endl;
pcl::ProjectInliers<pcl::PointXYZ> proj; //创建点云投影滤波对象
proj.setModelType(pcl::SACMODEL_PLANE); //设置投影模型为平面
proj.setInputCloud(cloud_filtered); //设置输入点云为滤波后的点云
proj.setModelCoefficients(coefficients); //根据参数估计设置投影平面
proj.filter(*cloud_projected); //将滤波后的点云投影到平面模型
std::cerr << "PointCloud after projection has " << cloud_projected->points.size() << " data points." << std::endl;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ConcaveHull<pcl::PointXYZ>chull; //创建多边形提取对象
chull.setInputCloud(cloud_projected); //设置输入点云为投影后的点云
chull.setAlpha(0.1); //设置alpha的值为0.1
chull.reconstruct(*cloud_hull); //重建提取创建凹多边形
std::cerr << "Concave hull has: " << cloud_hull->points.size() << " data points." << std::endl;
pcl::PCDWriter writer;
writer.write("table_scene_mug_stereo_textured_hull.pcd", *cloud_hull, false);
return(0);
}
三、编译结果
1)原始点云可视化结果:
2)重建后点云可视化结果: