用pcl读ply文件_PCL滤波介绍(3)

c645e94c02e635f664a2be70969b0e08.png

(1)从一个点云中提取索引(2019-12-23 这里说明一个这种提取索引的方法还是特别有用的,并且在较大的工程项目中,避免了过多的数据字段的复制等操作。本章给出基本实例,欢迎关注公众号,参与交流和分享)

如何使用一个,基于某一分割算法提取点云中的一个子集。

代码解析

#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>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/extract_indices.h>

int
main (int argc, char** argv)
{  

  /**********************************************************************************************************
   从输入的.PCD 文件载入数据后,创建一个VOxelGrid滤波器对数据进行下采样,在这里进行下才样是为了加速处理过程,
   越少的点意味着分割循环中处理起来越快
   **********************************************************************************************************/

  pcl::PCLPointCloud2::Ptr cloud_blob (new pcl::PCLPointCloud2), cloud_filtered_blob (new pcl::PCLPointCloud2);//申明滤波前后的点云
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>), cloud_p (new pcl::PointCloud<pcl::PointXYZ>), cloud_f (new pcl::PointCloud<pcl::PointXYZ>);

  // 读取PCD文件
  pcl::PCDReader reader;
  reader.read ("table_scene_lms400.pcd", *cloud_blob);
   //统计滤波前的点云个数
  std::cerr << "PointCloud before filtering: " << cloud_blob->width * cloud_blob->height << " data points." << std::endl;

  // 创建体素栅格下采样: 下采样的大小为1cm
  pcl::VoxelGrid<pcl::PCLPointCloud2> sor;  //体素栅格下采样对象
  sor.setInputCloud (cloud_blob);             //原始点云
  sor.setLeafSize (0.01f, 0.01f, 0.01f);    // 设置采样体素大小
  sor.filter (*cloud_filtered_blob);        //保存

  // 转换为模板点云
  pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered);

  std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points." << std::endl;

  // 保存下采样后的点云
  pcl::PCDWriter writer;
  writer.write<pcl::PointXYZ> ("table_scene_lms400_downsampled.pcd", *cloud_filtered, false);
 
  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.setMaxIterations (1000);                            //设置最大迭代次数
  seg.setDistanceThreshold (0.01);                      //判断是否为模型内点的距离阀值

  // 设置ExtractIndices的实际参数
  pcl::ExtractIndices<pcl::PointXYZ> extract;        //创建点云提取对象

  int i = 0, nr_points = (int) cloud_filtered->points.size ();
  // While 30% of the original cloud is still there
  while (cloud_filtered->points.size () > 0.3 * nr_points)
  {
    // 为了处理点云包含的多个模型,在一个循环中执行该过程并在每次模型被提取后,保存剩余的点进行迭代
    seg.setInputCloud (cloud_filtered);
    seg.segment (*inliers, *coefficients);
    if (inliers->indices.size () == 0)
    {
      std::cerr << "Could not estimate a planar model for the given dataset." << std::endl;
      break;
    }

    // Extract the inliers
    extract.setInputCloud (cloud_filtered);
    extract.setIndices (inliers);
    extract.setNegative (false);
    extract.filter (*cloud_p);
    std::cerr << "PointCloud representing the planar component: " << cloud_p->width * cloud_p->height << " data points." << std::endl;

    std::stringstream ss;
    ss << "table_scene_lms400_plane_" << i << ".pcd";
    writer.write<pcl::PointXYZ> (ss.str (), *cloud_p, false);

    // Create the filtering object
    extract.setNegative (true);
    extract.filter (*cloud_f);
    cloud_filtered.swap (cloud_f);
    i++;
  }

  return (0);
}

结果:

61fc200d62382277aed335b4e39b5f7e.png

显示出来:

bc31d62de844fc6314f34a91691ea213.png

图1 原始点云图像

be79cac93093fb40277a269e40e5471e.png

6deb1eb3adbc251ba2ec3323c915af9e.png

37ae43bc0bd625f5f45a5c56a8bba435.png

(modify 2019-12-23 这里我们知道了如果提取平面,如果我们只需要保留点云去平面的部分,应该调用哪个函数,你知道吗?)

(2)使用ConditionalRemoval 或RadiusOutlinerRemoval移除离群点

如何在滤波模块使用几种不同的方法移除离群点,对于ConditionalRemoval滤波器,可以一次删除满足对输入的点云设定的一个或多个条件指标的所有的数据点,RadiusOutlinerRemoval滤波器,它可以删除在输入点云一定范围内没有至少达到足够多近邻的所有数据点。

关于RadiusOutlinerRemoval的理解,在点云数据中,设定每个点一定范围内周围至少有足够多的近邻,不满足就会被删除

关于ConditionalRemoval 这个滤波器删除点云中不符合用户指定的一个或者多个条件的数据点

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/radius_outlier_removal.h>
#include <pcl/filters/conditional_removal.h>

int
 main (int argc, char** argv)
{
  if (argc != 2)  //确保输入的参数
  {
    std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
    exit(0);
  }
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);

  //填充点云
  cloud->width  = 5;
  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 = 1024 * rand () / (RAND_MAX + 1.0f);
  }

  if (strcmp(argv[1], "-r") == 0){
    pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;  //创建滤波器
 
    outrem.setInputCloud(cloud);    //设置输入点云
    outrem.setRadiusSearch(0.8);     //设置半径为0.8的范围内找临近点
    outrem.setMinNeighborsInRadius (2); //设置查询点的邻域点集数小于2的删除
    // apply filter
    outrem.filter (*cloud_filtered);     //执行条件滤波   在半径为0.8 在此半径内必须要有两个邻居点,此点才会保存
  }
  else if (strcmp(argv[1], "-c") == 0){
    //创建条件限定的下的滤波器
    pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond (new
      pcl::ConditionAnd<pcl::PointXYZ> ());   //创建条件定义对象
      //为条件定义对象添加比较算子
    range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
      pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::GT, 0.0)));   //添加在Z字段上大于0的比较算子

    range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
      pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::LT, 0.8)));   //添加在Z字段上小于0.8的比较算子
    // 创建滤波器并用条件定义对象初始化
    pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
    condrem.setCondition (range_cond);               
    condrem.setInputCloud (cloud);                   //输入点云
    condrem.setKeepOrganized(true);               //设置保持点云的结构
    // 执行滤波
    condrem.filter (*cloud_filtered);  //大于0.0小于0.8这两个条件用于建立滤波器
  }
  else{
    std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
    exit(0);
  }
  std::cerr << "Cloud before filtering: " << 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;
  // display pointcloud after filtering
  std::cerr << "Cloud after filtering: " << std::endl;
  for (size_t i = 0; i < cloud_filtered->points.size (); ++i)
    std::cerr << "    " << cloud_filtered->points[i].x << " "
                        << cloud_filtered->points[i].y << " "
                        << cloud_filtered->points[i].z << std::endl;
  return (0);
}

编译运行的结果为

fba3bb7041db7204e7b99bbf23d4d1ec.png

从中可以看出ConditionalRemoval 或RadiusOutlinerRemoval的区别

RadiusOutlinerRemoval比较适合去除单个的离群点 ConditionalRemoval 比较灵活,可以根据用户设置的条件灵活过滤

文章中如有问题可以留言交流,可扫描二维码,关注微信公众号,共同学习交流

3a81bc49a849b31986617709e0c386c7.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值