在PCL中如何实现平面模型分割[转]
首先,在PCL(Point Cloud Learning)中国协助发行的书[1]提供光盘的第14章例1文件夹中,打开名为planar_segmentation.cpp的代码文件。
解释说明
下面我们对上面打开的文件关键语句进行解析,下面语句为头文件包含语句,包含的头文件中声明了实例中使用到的采样一致性类及相关的模型参数定义。
#include //随机参数估计方法头文件
#include //模型定义头文件
#include //基于采样一致性分割的类的头文件
更多关于其它采样一致性模型和鲁棒性随机参数估计方法的实现,请参考采样一致性。
//填充点云数据,设置点云宽度为15,高度为1,即为无序点云
cloud.width = 15;
cloud.height = 1;
cloud.points.resize (cloud.width * cloud.height);
//生成数据,采用随机数填充点云的x,y坐标,但都处在z为1的平面上
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;
}
//设置几个局外点,即重新设置几个点的z值,使其偏离z为1的平面
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;
创建点云数据然后在屏幕上打印这些点的坐标值,为了达到本实验的目的,在数据中手动添加几个局外点,并设置它们的z值不为1,即不在z=1所在的平面上的点作为局外点,在z=1平面上的点作为局内点。
//创建分割时所需要的模型系数对象coefficients及存储内点的点索引集合对象inliers。
pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
//创建分割对象
pcl::SACSegmentation seg;
//可选择配置,设置模型系数需要优化
seg.setOptimizeCoefficients (true);
//必须配置,设置分割的模型类型、所用的随机参数估计方法、距离阈值、输入点云
seg.setModelType (pcl::SACMODEL_PLANE);
seg.setMethodType (pcl::SAC_RANSAC);
seg.setDistanceThreshold (0.01);
seg.setInputCloud (cloud.makeShared ());
//引发分割实现,并存储分割结果到点集合inliers及存储平面模型的系数coefficients
seg.segment (*inliers, *coefficients);
创建随机采样一致性分割对象,设置模型类型和随机采样一致性方法类型,并设定“距离阈值”,距离阈值决定了点被认为是局内点时必须满足的条件,距离阈值表示点到估计模型的距离最大值,本例中,使用RANSAC方法(pcl::SAC_RANSAC)作为选择的鲁棒估计方法,距离阈值是0.01米,即只要点到z=1平面距离小于该阈值的点都作为内点看待,而大于该阈值的则看做外点。
//打印出估计的平面模型参数。
std::cerr << "Model coefficients: " << coefficients->values[0] << " "
<values[1] << " "
<values[2] << " "
<values[3] << std::endl;
此段代码用来打印出估算的平面模型的参数(以 形式),详细请参考采样一致性。
编译并运行该程序
利用光盘提供的CMakeLists.txt文件,在cmake中建立工程文件,并生成相应的可执行文件。生成可执行文件之后,在cmd中键入以下命令:
->planar_segmentation.exe
运行之后将看到如图1所示的结果,开始打印的数据为有手动添加的点云数据,并非都处在z为1的平面上,通过分割对象的处理后,提取出所有内点,即过滤掉z不等于1的点集。
以下是源码,免得再去找了,其实网上都有的。
#include "stdafx.h"
#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> cloud;
// Fill in the cloud data
cloud.width = 15;
cloud.height = 1;
cloud.points.resize (cloud.width * cloud.height);
// Generate the data
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;
}
// Set a few outliers
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;
pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
// Create the segmentation object
pcl::SACSegmentation<pcl::PointXYZ> seg;
// Optional
seg.setOptimizeCoefficients (true);
// Mandatory
seg.setModelType (pcl::SACMODEL_PLANE);
seg.setMethodType (pcl::SAC_RANSAC);
seg.setDistanceThreshold (0.01);
seg.setInputCloud (cloud.makeShared ());
seg.segment (*inliers, *coefficients);
if (inliers->indices.size () == 0)
{
PCL_ERROR ("Could 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;
std::cerr << "Model inliers: " << inliers->indices.size () << 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);
}