【PCL自学:Filtering】PCL中的各类滤波器介绍与使用 (持续更新)

PCL_filter模块中各类滤波器目录

一、直通滤波器(PassThrough):用于阈值滤除

1、直通滤波器介绍

直通滤波器(PassThrough),顾名思义就是使用某个阈值 直接过滤掉不符合阈值的滤波器。例如有值范围在1到100的十万个数字,直通滤波器设置阈值为

2、示例代码

首先,在编辑器中创建一个文件,比如pass .cpp,并将以下内容放入其中,代码分析见注释。

#include
#include
#include

int main ()
 {

   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 (auto& point: *cloud)
  {
    point.x = 1024 * rand () / (RAND_MAX + 1.0f);
    point.y = 1024 * rand () / (RAND_MAX + 1.0f);
    point.z = 1024 * rand () / (RAND_MAX + 1.0f);
  }

  std::cerr << "Cloud before filtering: " << std::endl;
  for (const auto& point: *cloud)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                        << point.z << std::endl;

   pcl::PassThrough<pcl::PointXYZ> pass;
   pass.setInputCloud (cloud);
   pass.setFilterFieldName ("z");
   pass.setFilterLimits (580.0, 900);

  pass.filter (*cloud_filtered);

  std::cerr << "Cloud after filtering: " << std::endl;
  for (const auto& point: *cloud_filtered)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                        << point.z << std::endl;

  return (0);
}

过滤效果:绿色为阈值内的满足阈值(580,900)的点,红色为被过滤的点。当setFilterLimitsNegative参数设为True时,则选取( Z

二、体素滤波器(VoxelGrid filter):用于下采样

1、体素滤波器介绍

体素滤波器(VoxelGrid filter),常被用于点云数量的下降,即点云下采样。可类比于图像金字塔下采样。顾名思义,将点云按照空间三维划分体素(空间网格),并使用数学方法将每个体素内的点云替换成一个点,从而减少点云数量。
官方的解释:
体素下降法:将要展示的VoxelGrid类在输入点云数据上创建一个3D体素网格(将体素网格想象为空间中的一组微型3D盒子)。然后,在每个体素(即3D框)中,所有出现的点将被近似(即下采样)到它们的质心。这种方法比用体素中心逼近它们要慢一些,但它能更准确地表示底层表面。

2、示例代码

首先,下载数据集table_scene_lms400.pcd并将其保存到磁盘某处。我这里由于暂时连不上github,使用他人的效果图替代一下。
将如下代码粘贴到编辑器中,并进行编译。

 #include
 #include
 #include
 #include

 int
 main ()
 {
   pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2 ());
  pcl::PCLPointCloud2::Ptr cloud_filtered (new pcl::PCLPointCloud2 ());

  pcl::PCDReader reader;

  reader.read ("table_scene_lms400.pcd", *cloud);

  std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
       << " data points (" << pcl::getFieldsList (*cloud) << ")." << std::endl;

  pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
  sor.setInputCloud (cloud);

   sor.setLeafSize (0.01f, 0.01f, 0.01f);
  sor.filter (*cloud_filtered);

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

  pcl::PCDWriter writer;
  writer.write ("table_scene_lms400_downsampled.pcd", *cloud_filtered,
         Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false);

  return (0);
}

滤波效果如下:
体素滤波前:

【PCL自学:Filtering】PCL中的各类滤波器介绍与使用 (持续更新)
体素滤波后效果:
【PCL自学:Filtering】PCL中的各类滤波器介绍与使用 (持续更新)

三、统计离群滤波器(StatisticalOutlierRemoval filter):用于离群点滤除

1、统计离群滤波器介绍

统计离群滤波器(StatisticalOutlierRemoval filter)常被用于 删除离群点(噪声和杂点),该滤波器使用统计分析技术从点云数据集中去除噪声测量,例如离群值。
1.1背景:
激光扫描通常生成不同点密度的点云数据集。此外,测量误差还会导致稀疏的异常值,从而进一步破坏结果。这使得局部点云特征(如表面法线或曲率变化)的估计变得复杂,从而导致错误的值,进而可能导致点云配准失败。其中一些不规则性可以通过对每个点的邻域进行统计分析来解决,并对那些不符合一定标准的点进行修剪。离群点去除方法是基于计算点到邻点的距离在输入数据集中的分布。对于每一个点,计算它到所有相邻点的平均距离。通过假设得到的 分布是具有均值和标准差的高斯分布,所有的点,其均值距离在由全局距离均值和标准差定义的区间之外,都可以被认为是离群点,并从数据集中进行修剪。
下面的图片展示了离群点分析和去除的效果:左边是原始数据集,右边是生成的数据集。该图显示了滤波前后一个点附近的平均k近邻距离。

【PCL自学:Filtering】PCL中的各类滤波器介绍与使用 (持续更新)

; 2、示例代码

依旧是先从github上下载如下数据集table_scene_lms400_inliers.pcd。然后将如下代码粘贴到编译器中。

#include
#include
#include
#include

 int
 main ()
 {
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);

  pcl::PCDReader reader;

  reader.read<pcl::PointXYZ> ("table_scene_lms400.pcd", *cloud);

  std::cerr << "Cloud before filtering: " << std::endl;
  std::cerr << *cloud << std::endl;

    pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;

  sor.setInputCloud (cloud);
  sor.setMeanK (50);
  sor.setStddevMulThresh (1.0);
  sor.filter (*cloud_filtered);

  std::cerr << "Cloud after filtering: " << std::endl;
  std::cerr << *cloud_filtered << std::endl;

  pcl::PCDWriter writer;
  writer.write<pcl::PointXYZ> ("table_scene_lms400_inliers.pcd", *cloud_filtered, false);

  sor.setNegative (true);
  sor.filter (*cloud_filtered);
  writer.write<pcl::PointXYZ> ("table_scene_lms400_outliers.pcd", *cloud_filtered, false);

  return (0);
}

四、条件和半径滤波器(Conditional or RadiusOutlier ):用于离群点滤除

1、条件和半径滤波器介绍

[1]条件滤波器,顾名思义,就是给滤波器一些条件值,可以是一个也可以是多个,使用条件滤波器可以滤除所有不满足条件的点,常用于离群点滤除。
在示例代码中,我们使用在条件中添加两个比较:大于(GT) 0.0和小于(LT) 0.8。然后使用这个条件构建滤波器。
[2]半径滤波器,顾名思义,给定指定半径,和半径内最少点数进行滤波,例如满足半径0.8内,点数至少为2,即计算每个点半径范围内的点数,少于该点数则被过滤,常用于离群点滤波。
我们来直接看代码:
下图可以帮助我们理解RadiusOutlierRemoval过滤器对象的作用。用户指定了一些邻域点,每个索引必须在指定的半径参数内。例如,如果指定了1个邻点,那么只有黄色的点将从PointCloud中删除。如果指定了2个邻点,那么黄色和绿色的点都将从PointCloud中删除。

【PCL自学:Filtering】PCL中的各类滤波器介绍与使用 (持续更新)

; 2、示例代码

 #include
 #include
 #include
 #include

 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->resize (cloud->width * cloud->height);

  for (auto& point: *cloud)
  {
    point.x = 1024 * rand () / (RAND_MAX + 1.0f);
    point.y = 1024 * rand () / (RAND_MAX + 1.0f);
    point.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);
    outrem.setMinNeighborsInRadius (2);
    outrem.setKeepOrganized(true);

    outrem.filter (*cloud_filtered);
  }

  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)));
    range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
      pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::LT, 0.8)));

    pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
    condrem.setCondition (range_cond);
    condrem.setInputCloud (cloud);
    condrem.setKeepOrganized(true);

    condrem.filter (*cloud_filtered);
  }
  else{
    std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
    exit(0);
  }
  std::cerr << "Cloud before filtering: " << std::endl;
  for (const auto& point: *cloud)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                       << point.z << std::endl;

  std::cerr << "Cloud after filtering: " << std::endl;
  for (const auto& point: *cloud_filtered)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                        << point.z << std::endl;
  return (0);
}

总结:

本文章介绍了直通滤波器,体素滤波器,统计离群滤波器,半径滤波器和条件滤波器的概念和示例代码。但是PCL中还有很多滤波器没有介绍,例如任意多边形内部点云滤除CropHull(多用作编写点云后处理软件使用,用于用户界面交互)。这里的介绍都比较简单,详细的介绍和实验结果可以参考前辈的文章。后期所有内容学习完成后,准备自己写一个点云后处理软件,使用QT+PCL实现各种点云后处理功能,到时候会把编写过程写出一篇博文,敬请期待。

【博主简介】
斯坦福的兔子,男,天津大学机械工程工学硕士。毕业至今从事光学三维成像及点云处理相关工作。因工作中使用的三维处理库为公司内部库,不具有普遍适用性,遂自学开源PCL库及其相关数学知识以备使用。谨此将自学过程与君共享。
博主才疏学浅,尚不具有指导能力,如有问题还请各位在评论处留言供大家共同讨论。
若前辈们有工作机会介绍欢迎私信。

Original: https://blog.csdn.net/weixin_41966507/article/details/122914724
Author: 斯坦福的兔子
Title: 【PCL自学:Filtering】PCL中的各类滤波器介绍与使用 (持续更新)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/559496/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球