一、简介
PCL中Segementation库提供了点云分割的基础数据结构和部分通用的分割算法,目前实现的算法主要是基于聚类分割思想和基于随机采样一致性的分割算法,这些算法适用于将由多个空间分布独立的区域组成的点云分割成格子独立的点云子集,或者提取出特定的模型的点云数据,以便后续处理。
二、代码分析
1)创建点云数据然后再屏幕上打印这些点的坐标值,为了达到本教程的目的,在数据中手动添加几个局外点,并设置它们的z值不为1,即不在z = 1所在的平面上的点作为局外点,在z = 1平面上的点作为局内点:
pcl::PointCloud<pcl::PointXYZ> cloud;
//填充点云数据
cloud.width = 15;
cloud.height = 1;
cloud.points.resize (cloud.width * cloud.height);
//生成数据
for (size_t i = 0; i < cloud.points.size (); ++i)
{
cloud.points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud.points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud.points[i].z = 1.0;
}
//设置几个局外点
cloud.points[0].z = 2.0;
cloud.points[3].z = -2.0;
cloud.points[6].z = 4.0;
std::cerr << "Point cloud data: " << cloud.points.size () <<" points" << std::endl;
for (size_t i = 0; i < cloud.points.size (); ++i)
std::cerr << " " << cloud.points[i].x << " "
<< cloud.points[i].y << " "
<< cloud.points[i].z << std::endl;
2)创建随机采样一致性分割对象,设置模型类型和随机采样一致性方法类型,并设定“距离阈值”,距离与之决定了点被认为是局内点时必须满足的条件,距离与之表示点到估计模型的距离最大值。在本例中,使用RANSAC方法作为选择的鲁棒估计方法,距离阈值为0.01米,即只要点到z = 1平面距离小于该阈值的点作为内点看待,大于该阈值的则看作外点:
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);
seg.setInputCloud (cloud.makeShared ());
seg.segment (*inliers, *coefficients);
3)用代码打印出估算的平面模型的参数:
std::cerr << "Model coefficients: " << coefficients->values[0] << " "
<<coefficients->values[1] << " "
<<coefficients->values[2] << " "
<<coefficients->values[3] <<std::endl;
4)整体代码如下:
#include <iostream>
#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/segmentation/sac_segmentation.h>
int main(int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); //智能指针初始化点云
cloud->width = 15;
cloud->height = 1;
cloud->points.resize(cloud->width * cloud->height);
for (size_t i = 0;i < cloud->points.size();++i)
{
cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].z = 1.0;
}
cloud->points[0].z = 2.0; //手动设置离群点
cloud->points[3].z = -2.0;
cloud->points[6].z = 4.0;
std::cerr << "Point cloud data:" << cloud->points.size() << "points" << std::endl; //输出当前点云中的点的信息
for (size_t i = 0;i < cloud->points.size();++i)
std::cerr << "Clouds data:" << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z << 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); //设定距离阈值,小于该阈值则为局内点,大于该阈值则为局外点
seg.setInputCloud(cloud);
seg.segment(*inliers, *coefficients);
if (inliers->indices.size() == 0)
{
PCL_ERROR("Cloud not estimate a planar model for the given dataset.");
return(-1);
}
std::cerr << "Model coefficients:" << coefficients->values[0] << " " << coefficients->values[1] << " " << coefficients->values[2] << " " << coefficients->values[3] << " " << std::endl;
for (size_t i = 0;i < inliers->indices.size();++i)
std::cerr << inliers->indices[i] << " " << cloud->points[inliers->indices[i]].x << " " << cloud->points[inliers->indices[i]].y << " " << cloud->points[inliers->indices[i]].z << " " << std::endl;
return (0);
}
三、编译结果