PCL——预处理(滤波)_cbb8234078009的博客-程序员秘密

技术标签: 自动驾驶  pcl  

点云滤波

滤波

在获取点云数据时,由于设备精度、操作者经验、环境因素等带来的影响,点云数据中不可避免的出现了一些噪声点(就是自己用不到的点),我们在处理数据时,需要把这些点去除掉,这个过程叫滤波。
一、pcl中的点云滤波方案
(1)点云数据密度不规则需要平滑
(2)因为遮挡等问题造成离群点需要去除
(3)大量数据需要进行下采样(Downsample)。
(4)噪声数据需要去除。
对应方法如下:
(1)按具体给定的规则限制过滤去除点。
(2)通过常用滤波算法修改点的部分属性。
(3)对数据进行下采样。

直通滤波器

直通滤波器:对于在空间分布有一定空间特征的点云数据,比如使用线结构光扫描的方式采集点云,沿z向分布较广,但x,y向的分布处于有限范围内。此时可使用直通滤波器,确定点云在x或y方向上的范围,可较快剪除离群点,达到第一步粗处理的目的。

#include<iostream>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>  //直通滤波器头文件
using namespace std;
  
int main()
{
    
  ///****************************************************
  /*创建点云数据集。*/
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  cloud->width = 500;
  cloud->height = 1;
  cloud->points.resize(cloud->width*cloud->height);
  std::cout << "创建原始点云数据" << std::endl;
  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);
  }
  
  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;
  }
  std::cout << "原始点云数据点数:" << cloud->points.size()<< std::endl << std::endl;
 
  ///****************************************************
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_after_PassThrough(new pcl::PointCloud<pcl::PointXYZ>);
 
  pcl::PassThrough<pcl::PointXYZ> passthrough;
  passthrough.setInputCloud(cloud);//输入点云
  passthrough.setFilterFieldName("z");//对z轴进行操作
  passthrough.setFilterLimits(0.0, 400.0);//设置直通滤波器操作范围
  //passthrough.setFilterLimitsNegative(true);//true表示保留范围内,false表示保留范围外
  passthrough.filter(*cloud_after_PassThrough);//执行滤波,过滤结果保存在 cloud_after_PassThrough
 
  std::cout << "直通滤波后点云数据点数:" << cloud_after_PassThrough->points.size() << std::endl;
 
 std::cerr<<"cloud afer filtering:"<<std::endl;
 for(size_i=0;i<cloud_after_PassThrough->points.size();++i)
	 {
    
	 	std::cerr<<""<<cloud_after_PassThrough->points[i].x<<" " 
	 	<<cloud_after_PassThrough->points[i].y<<" " 
	 	<<cloud_after_PassThrough->points[i].z<<" " <<std::endl;
	}
}

体素滤波器

体素的概念类似于像素,使用AABB包围盒将点云数据体素化,一般体素越密集的地方信息越多,噪音点及离群点可通过体素网格去除。另一方面如果使用高分辨率相机等设备对点云进行采集,往往点云会较为密集。过多的点云数量会对后续分割工作带来困难。体素滤波器可以达到向下采样同时不破坏点云本身几何结构的功能。

#include<iostream>
#include<pcl/point_types.h>
#include<pcl/filters/voxel_grid.h>  //体素滤波器头文件
using namespace std;
  
int main()
{
    
  ///****************************************************
  /*创建点云数据集。*/
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  cloud->width = 500;
  cloud->height = 1;
  cloud->points.resize(cloud->width*cloud->height);
  std::cout << "创建原始点云数据" << std::endl;
  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);
  }
  
  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;
  }
  std::cout << "原始点云数据点数:" << cloud->points.size()<< std::endl << std::endl;
 
 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_after_voxelgrid(new pcl::PointCloud<pcl::PointXYZ>);//
 
  pcl::VoxelGrid<pcl::PointXYZ> voxelgrid; 
  voxelgrid.setInputCloud(cloud);//输入点云数据
  voxelgrid.setLeafSize(10.0f, 10.0f, 10.0f);//AABB长宽高
  voxelgrid.filter(*cloud_after_voxelgrid);
 
  std::cout << "体素化网格方法后点云数据点数:" << cloud_after_voxelgrid->points.size() << std::endl;
 
 std::cerr<<"cloud afer filtering:"<<std::endl;
 for(size_i=0;i<ccloud_after_voxelgrid->points.size();++i)
	 {
    
	 	std::cerr<<""<<cloud_after_voxelgrid->points[i].x<<" " 
	 	<<cloud_after_voxelgrid->points[i].y<<" " 
	 	<<cloud_after_voxelgrid->points[i].z<<" " <<std::endl;
	}
}

统计滤波器使用(statisticalOutlierRemoval滤波器移除离群点

使用统计分析技术,从一个点云数据中集中移除测量噪声点(也就是离群点)比如:激光扫描通常会产生密度不均匀的点云数据集,另外测量中的误差也会产生稀疏的离群点,使效果不好,估计局部点云特征(例如采样点处法向量或曲率变化率)的运算复杂,这会导致错误的数值,反过来就会导致点云配准等后期的处理失败.

解决办法:每个点的邻域进行一个统计分析,并修剪掉一些不符合一定标准的点,稀疏离群点移除方法基于在输入数据中对点到临近点的距离分布的计算,对每一个点,计算它到它的所有临近点的平均距离,,假设得到的结果是一个高斯分布,其形状是由均值和标准差决定,平均距离在标准范围之外的点,可以被定义为离群点并可从数据中去除。
补充:高斯分布又名正态分布
在这里插入图片描述在这里插入图片描述

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>
 
int main(int argc, char** argv)
{
    
	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>("bunny.pcd", *cloud);//读取需要的文件
 
	std::cout << "Cloud before filtering: " << std::endl;
	std::cout << *cloud << std::endl;
 
	// 创建滤波器,对每个点分析的临近点的个数设置为50 ,并将标准差的倍数设置为1  这意味着如果一
	 //个点的距离超出了平均距离一个标准差以上,则该点被标记为离群点,并将它移除,存储起来
	pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;   //创建滤波器对象
	sor.setInputCloud(cloud);                           //设置待滤波的点云
	sor.setMeanK(50);                               //设置在进行统计时考虑查询点临近点数
	//sor.setStddevMulThresh(1.0);                      //设置判断是否为离群点的阀值
	sor.setStddevMulThresh(0.00034);                      //设置判断是否为离群点的阀值
	sor.filter(*cloud_filtered);                    //存储
 
	std::cerr << "Cloud after filtering: " << std::endl;
	std::cerr << *cloud_filtered << std::endl;
 
	pcl::PCDWriter writer;
	writer.write<pcl::PointXYZ>("test1_inliers.pcd", *cloud_filtered, false);
 
	sor.setNegative(true);
	sor.filter(*cloud_filtered);
	writer.write<pcl::PointXYZ>("test1_outliers.pcd", *cloud_filtered, false);
 
	return (0);
}

条件滤波

条件滤波器通过设定滤波条件进行滤波,有点分段函数的味道,当点云在一定范围则留下,不在则舍弃。

#include<iostream>
#include<pcl/point_types.h>
#include <pcl/filters/conditional_removal.h>    //条件滤波器头文件
using namespace std;
  
int main()
{
    
  ///****************************************************
  /*创建点云数据集。*/
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  cloud->width = 500;
  cloud->height = 1;
  cloud->points.resize(cloud->width*cloud->height);
  std::cout << "创建原始点云数据" << std::endl;
  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);
  }
  
  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;
  }
  std::cout << "原始点云数据点数:" << cloud->points.size()<< std::endl << std::endl;
 
/*条件滤波器*/
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_after_Condition(new pcl::PointCloud<pcl::PointXYZ>);
 
  pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_condition(new pcl::ConditionAnd<pcl::PointXYZ>());
  range_condition->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
    pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::GT, 0.0)));  //GT表示大于等于
  range_condition->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
    pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::LT, 0.8)));  //LT表示小于等于
 
  pcl::ConditionalRemoval<pcl::PointXYZ> condition;
  condition.setCondition(range_condition);
  condition.setInputCloud(cloud);                   //输入点云
  condition.setKeepOrganized(true);
 
  condition.filter(*cloud_after_Condition);
  std::cout << "条件滤波后点云数据点数:" << cloud_after_Condition->points.size() << std::endl;
 
 std::cerr<<"cloud afer filtering:"<<std::endl;
 for(size_i=0;i<cloud_after_Condition->points.size();++i)
	 {
    
	 	std::cerr<<""<<cloud_after_Condition->points[i].x<<" " 
	 	<<cloud_after_Condition->points[i].y<<" " 
	 	<<cloud_after_Condition->points[i].z<<" " <<std::endl;
	}
}

半径滤波

半径滤波器与统计滤波器相比更加简单粗暴。以某点为中心画一个圆计算落在该圆中点的数量,当数量大于给定值时,则保留该点,数量小于给定值则剔除该点。此算法运行速度快,依序迭代留下的点一定是最密集的,但是圆的半径和圆内点的数目都需要人工指定。

#include<iostream>
#include<pcl/point_types.h>
#include <pcl/filters/conditional_removal.h>    //条件滤波器头文件
using namespace std;
  
int main()
{
    
  ///****************************************************
  /*创建点云数据集。*/
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  cloud->width = 500;
  cloud->height = 1;
  cloud->points.resize(cloud->width*cloud->height);
  std::cout << "创建原始点云数据" << std::endl;
  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);
  }
  
  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;
  }
  std::cout << "原始点云数据点数:" << cloud->points.size()<< std::endl << std::endl;
 
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_after_Radius(new pcl::PointCloud<pcl::PointXYZ>);
 
  pcl::RadiusOutlierRemoval<pcl::PointXYZ> radiusoutlier;  //创建滤波器
 
  radiusoutlier.setInputCloud(cloud);    //设置输入点云
  radiusoutlier.setRadiusSearch(100);     //设置半径为100的范围内找临近点
  radiusoutlier.setMinNeighborsInRadius(2); //设置查询点的邻域点集数小于2的删除
                                 
  radiusoutlier.filter(*cloud_after_Radius);
  std::cout << "半径滤波后点云数据点数:" << cloud_after_Radius->points.size() << std::endl;
 std::cerr<<"cloud afer filtering:"<<std::endl;
 for(size_i=0;i<cloud_after_Radius->points.size();++i)
	 {
    
	 	std::cerr<<""<<cloud_after_Radius->points[i].x<<" " 
	 	<<cloud_after_Radius->points[i].y<<" " 
	 	<<cloud_after_Radius->points[i].z<<" " <<std::endl;
	}
}

以上的5种方法是最基本的常用的五种滤波方法,之后遇到更好的方法会补充。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cbb8234078009/article/details/106720617

智能推荐

洛谷4135 作诗(分块)_Michael_GLF的博客-程序员秘密

传送门【题目分析】当你点开这篇博客的时候,请做好心理准备。因为博主是卡常卡过去的+数据很水。虽然题面给你c&amp;lt;=1e5,但亲测达不到(因为我用short暴力碾过去了)所以。。。。。人还是要有梦想的!咳咳,不扯那么多,讲讲我的做法(时间其实消耗在了memset上)跟网上的分块差不多,都是直接暴力维护,每次查询,整块用前缀和,内部直接大力搜。看了看同校AC代码,应该...

Linux文件系统损坏导致不能正常开机_fsck /dev/sda1_F元凯的博客-程序员秘密

在linux中,可能会遇到这样的情况:非正常关机(比如我自己练习的机子,就没有安装不断电系统,很可能跳闸之类的不可预期的情况导致关机,也可能是磁盘使用过渡,导致磁道损坏)后,再次启动的时候,可能会启动失败。失败原因不尽相同,通常不正常的关机,可能造成的问题是文件系统的损坏,以下总结几点解决方案:首先要确定是哪个地方的文件损坏了。因为出错扇区所挂在的目录不同,而处理方式有所不同,总之所有的处理方式...

word-break:break-all 与word-wrap:break-word的区别_赵乘风_i的博客-程序员秘密

word-break:break-allword-wrap:break-word相同之处:都是换行不同:word-wrap :break-word 以单词换行,可能不对齐,会出现空白word-break:break-all 所有都换行,是以div宽度进行换行的,可能会影响单词的完整性如果遇到没有空格全英文,因为没有遇到单词,使用了word-wrap:break-word ,也没有...

ME_DIRECT_INPUT_INFORECORD ME11创建采购信息记录_小懒lan的博客-程序员秘密

MARK 文豪 版本DATA:WA_EINATYPEEINA,WA_EINETYPEEINE,WA_EINA_NEWTYPEEINA,WA_EINE_NEWTYPEEINE.DATA:IT_HEADTYPESTANDARDTABLEOFMESTXH,IT_LINETYPESTANDARDTABLEOFMESTXL.DATA:IT_EINATYPESTANDARDTAB...

Android学习笔记(二)HelloWorld_青人的博客-程序员秘密

1、新建一个名为HelloWorld的Android项目 2、在XML布局文件定义应用程序的用户界面 在activity_hello_world.xml中定义应用程序的用户界面 1)图形化布局,“所见即所得”的拖拽形式 2)xml文件的源码形式 我们可以再控制面板中向程序拖入一个“Button”,然后在此基础上,在源代码界面进行修改。 我们在界面中拖入一个”button”,a

关于Pip和Virtualenv非魔法式的介绍_pip virtualenv_wugang75778218的博客-程序员秘密

关于Pip和Virtualenv非魔法式的介绍python新手需要克服的障碍之一就是弄懂python如何安装包和进行包管理的生态系统。本篇博客是基于对"python程序员训练课程"中的材料希望能向python新的使用者解释pip和virtualenv。前提"python程序员训练课程"是面向已经掌握了一门和多门程序语言的开发者,所以我们认为你应该具有了相当的技术知识,如果你能熟练自如的使用命令行那将会有帮助。下面的例子用了bash,它是Macs和大多数Linux系统的缺省交互shell。但用的命令足够

随便推点

操作系统 第二章 进程通信 线程_Love_Imagine_Dragons的博客-程序员秘密

2.6进程通信进程通信是指进程之间的信息交换。一、低级通信——进程之间的互斥和同步 信号量机制是有效的同步工具,但作为通信工具缺点如下:(1)效率低(通信量少)(2)通信对用户不透明(程序员实现,操作系统只提供共享存储器供代码操作)二、高级进程通信用户直接利用操作系统提供的一组通信命令,高效地传送大量数据的通信方式。操作系统隐藏了进程通信的细节,对用户透明,减少了通信程序编制上的...

Android将Jar放入libs目录下编译报错_app libs添加包后依然报错_HackShendi的博客-程序员秘密

i'm shendi今天写android项目时发生的问题,将jar包放入libs目录下,然后编译报错首先,我将build.gradle中的某一行注释了,这一行会将libs下所有jar自动引入//implementation fileTree(dir: 'libs', include: ['*.jar'])然后我build就没有问题了但是jar包没有被使用然后观察错误信息,往下滑,大致意思就是....要加一段声明java1.8的我Jar使用的是1.8...

Python2.7 爬虫实践:豆瓣电影影评分析_黄大芬的博客-程序员秘密

reference from :hangsegmentfault.com/a/1190000010473819本人先看到以上,觉得挺好玩,所以就跟着原作者的思路在撸一遍代码后来发现了几个问题本人的python 2.7 原作者为python3所以其中的一些funtion/属性 也不支持所以做了一下修改安装必要的lib 之后会有文章进

MAC VSCODE C++ debug环境配置_vscode配置c++ debug mac_Dorabox的博客-程序员秘密

{ "configurations": [ { "name": "Mac", "includePath": [ "${workspaceFolder}/**" ], "defines": [], "macFrameworkPath": [ "/Librar

oracle 扩容undo,【案例】Oracle RAC数据库undo使用率较高的解决思路办法_南门居士-杜锦刚的博客-程序员秘密

天萃荷净Oracle研究中心案例分析:运维DBA反映Oracle数据库undo使用较大,结合案例分析undo使用问题。本站文章除注明转载外,均为本站原创: 转载自love wife &amp; love life —Roger 的Oracle技术博客本文链接地址: about Undo Tablespace used High今天有朋友在问关于undo 使用很高的问题,这个问题其实很常见了,上次也...

Jetson Nano 安装deepStream_jetson nano deepstream_Done___的博客-程序员秘密

查看JetPack的版本使用jtop命令,即可查看nano的相关信息。下载deepstreamdeepstream下载地址官方网站里面有Jetpack对应的deepstream,根据你自己的Jetpack版本去下载对应的deepstream,我这边下载的是deepstream5.1安装依赖项$ sudo apt install \libssl1.0.0 \libgstreamer1.0-0 \gstreamer1.0-tools \gstreamer1.0-plugins-good

推荐文章

热门文章

相关标签