PCL点云滤波

简介: PCL点云滤波

滤波原因

在获取点云数据时,由于设备精度、操作者经验、环境因素等带来的影响,以及电磁波衍射特性、被测物体表面性质变化和数据拼接配准操作过程中的影响,点云数据中将不可避免将出现一些噪声点。实际应用中,除了这些测量随机误差产生的噪声点之外,由于收到外界干扰,如视线遮挡、障碍物等因素的影响,点云数据中往往存在些离主体点云较远的离群点。

在点云处理流程中,滤波处理作为预处理的第一步,对后续(配准、特征提取、曲面重建)处理影响很大。

PCL中点云滤波模块提供了很多灵活实用的滤波处理算法,如双边滤波、高斯滤波、条件滤波、直通滤波、体素滤波等等。

什么情况下需要滤波呢,有以下几种:

  • 点云数据密度不规则需要平滑
  • 因为遮挡等问题造成离群点需要去除
  • 大量数据需要进行下采样
  • 噪音数据需哟去除

下面通过PCL的库 实现 几种 滤波

PCL中的filters模块及类

pcl_filters模块提供对噪声点和离群点去除的具体实现。filters模块用32个类和5个函数实现了对点云数据进行不同的滤波以达到去除不需要点的目的。

可以打开pcl库下面的filters的文件夹,里面是该模块的各个头文件,在使用某个模块时必须要包含该头文件。
例如:
passthrough.h 直通滤波
voxel_grid.h 体素滤波
statistical_outlier_removal.h 离群点滤波
project_inliers.h 投影滤波
在这里插入图片描述

Code

===========================================================

#include <iostream>
#include <ctime>
#include <pcl/point_types.h>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/passthrough.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/project_inliers.h>

需要包含的头文件
里面有上面提到的几种滤波的头文件

格外说明的是,在CMakeList.txt文件中要 find_package 下 filters模块,否则会报错的

# 寻找PCL的库
find_package(PCL REQUIRED COMPONENT common io visualization filters)

===========================================================

    //声明一个点云 指针
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

    //从PCD 中 读取点云
    pcl::io::loadPCDFile ("../wolf.pcd", *cloud);

声明一个点云 指针,然后从PCD 文件中读取

这个点云是从网上找的一个 狼的 点云。 下面的滤波也就从 这 个 上面 演示效果

可以通过 下面指令 看下 原始点云
在这里插入图片描述
这个样子的

===========================================================

直通滤波

直通滤波:对指定的某一纬度 实行 一个 简单 的滤波,即去掉指定范围内部或者外部的点。

    /* 声明 直通滤波 后 的点云 */
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_PassThrough_filtered (new pcl::PointCloud<pcl::PointXYZ>);

    /* 声明直通滤波 的 类实例 */
    pcl::PassThrough< pcl::PointXYZ >  pass;
    /* 设置输入点云 */
    pass.setInputCloud (cloud);
    /* 设置滤波的维度 */
    pass.setFilterFieldName ("z");
    /* 设置滤波的范围 */
    pass.setFilterLimits (-50.0,50.0);
    /* 设置去掉的 是 范围内(true) 还是 范围外(false)   */
    pass.setFilterLimitsNegative (1);
    /* 执行滤波 返回 滤波后 的 点云 */
    pass.filter (*cloud_PassThrough_filtered);

   
    // 显示直通滤波后的点云
    /* 创建显示 类 实例 */
    pcl::visualization::CloudViewer viewer1("Cloud Viewer PassThrough"); 

    /* 显示点云 */
    viewer1.showCloud(cloud_PassThrough_filtered);

        /*持续显示*/
    while (!viewer1.wasStopped ())
    {
    }

总结下代码 实现步骤
1、声明直通滤波 的 类实例
2、设置输入点云
3、设置滤波的维度
4、设置滤波的范围
5、设置去掉的 是 范围内(true) 还是 范围外(false)
6、执行滤波 返回 滤波后 的 点云

然后通过显示 来 看下 滤波后的效果
在这里插入图片描述

//将这个改为0  即 去除 范围外 的 点 的效果
 pass.setFilterLimitsNegative (0);

在这里插入图片描述
下半部分被保存

===========================================================

体素滤波

体素滤波是 体素化网格方法实现下采样,即减少点的数量,并同时保持点云的形状特征,在提高配准、曲面重建、形状识别等算法速度中非常实用。

说直白点就是 一个体素 就是一个小的单元,这个单元里面 原始点云有很多点的话会求 这些 点 的 重心点,然后 在这个单元中 多个点就变成了一个点

    /* 声明 体素滤波 后 的点云 */
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_VoxelGrid_filtered (new pcl::PointCloud<pcl::PointXYZ>);

    /* 声明体素滤波 的 类实例 */
    pcl::VoxelGrid<pcl::PointXYZ> sor;
    /* 设置输入点云 */
    sor.setInputCloud (cloud);
    /* 设置体素滤波的参数 */  //10.1 米的立方体
    sor.setLeafSize (10.1f, 10.1f, 10.1f);
    /* 执行滤波 返回 滤波后 的 点云 */
    sor.filter (*cloud_VoxelGrid_filtered);

        // 显示体素滤波后的点云
    /* 创建显示 类 实例 */
    pcl::visualization::CloudViewer viewer2("Cloud Viewer VoxelGrid"); 

    /* 显示点云 */
    viewer1.showCloud(cloud_VoxelGrid_filtered);

        /*持续显示*/
    while (!viewer1.wasStopped ())
    {
    }

总结下代码 实现步骤
1、声明体素滤波 的 类实例
2、设置输入点云
3、设置体素滤波的参数
4、执行滤波 返回 滤波后 的 点云

然后通过显示 来 看下 滤波后的效果

滤波前
在这里插入图片描述
滤波后
在这里插入图片描述
可以看到点云稀疏了很多,但是外形没有变化。面部细节少了很多

===========================================================

离群点滤波

顾名思义,就是去掉 离 点云群较远的点。

    /* 声明 离群点滤波 后 的点云 */
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_OutRemove_filtered (new pcl::PointCloud<pcl::PointXYZ>);

    /* 声明 离群点滤波 的 类实例 */
    pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor_OutRemove;
    /* 设置输入点云 */
    sor_OutRemove.setInputCloud (cloud);
    /* 设置在进行统计时考虑查询点邻近点数 */
    sor_OutRemove.setMeanK (30);
    /* 设置判断是否为离群点 的 阈值  设置为1的 话 表示为:如果一个点的距离超过平均距离一个标准差以上则为离群点 */
    sor_OutRemove.setStddevMulThresh (1.0);
     /* 执行滤波 返回 滤波后 的 点云 */
    sor_OutRemove.filter (*cloud_OutRemove_filtered);


    /* 打印滤波前后的点数 */
    std::cout<<"size of clound :"<<cloud->points.size()<<"   size of  outremove "<<cloud_OutRemove_filtered->points.size()<<endl;

总结下代码 实现步骤
1、声明 离群点滤波 的 类实例
2、设置输入点云
3、设置在进行统计时考虑查询点邻近点数
4、设置判断是否为离群点 的 阈值 设置为1的 话 表示为:如果一个点的距离超过平均距离一个标准差以上则为离群点
5、执行滤波 返回 滤波后 的 点云

在这里插入图片描述
滤波前3400个点 ,滤波后2702个点

同样和直通滤波类似,可以设置

pass.setFilterLimitsNegative (0);

来返回被滤掉的离群点

===========================================================

投影滤波

通过使用参数化模型,将点投影到参数化模型上。参数化模型通过一组参数来设定,对于平面来说,形式也就是
ax+by+cz+d = 0
在pcl中有特意存储常见模型系数的数据结构

    /* 声明 投影 滤波 后 的点云 */
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected (new pcl::PointCloud<pcl::PointXYZ>);

    /*定义模型 系数 对象 ,并填充 对应 的数据  如果是 平面 ax+by+cz+d = 0  投影到z平面 即 a、b、d 为0  c为1 */
    pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ());
    coefficients->values.resize (4);
    coefficients->values[0] = 0;
    coefficients->values[1] = 0;
    coefficients->values[2] = 1;
    coefficients->values[3] = 0;

    /* 声明 投影滤波 的 类实例  */
    pcl::ProjectInliers<pcl::PointXYZ> proj;
    /* 设置参数化模型的类型 */
    proj.setModelType (pcl::SACMODEL_PLANE);
    /* 设置输入点云 */
    proj.setInputCloud (cloud);
    /* 设置上面填充完的模型 */
    proj.setModelCoefficients (coefficients);
    /*  执行滤波 返回 滤波后 的 点云 */
    proj.filter (*cloud_projected);

总结下代码 实现步骤
1、定义模型 系数 对象 ,并填充 对应 的数据
2、声明 投影滤波 的 类实例
3、设置参数化模型的类型
4、设置输入点云
5、设置上面填充完的模型
6、执行滤波 返回 滤波后 的 点云

上面的模型为平面 模型 方程即为 ax+by+cz+d = 0
设置参数 为 a=b=d = 0 c=1
即投影到z平面

下面时投影的效果
在这里插入图片描述
在这里插入图片描述
被压平了

===========================================================

Result

原始点云
在这里插入图片描述
直通滤波在这里插入图片描述
在这里插入图片描述
体素滤波
在这里插入图片描述
投影滤波
在这里插入图片描述
在这里插入图片描述

相关文章
|
4月前
|
C++
C++ PCL 将一个点云投影到一个由法向量和点确定的平面
C++ PCL 将一个点云投影到一个由法向量和点确定的平面
128 0
|
C++ Python
C++ PCL三维点云物体目标识别
C++ PCL三维点云物体目标识别
859 1
C++ PCL三维点云物体目标识别
|
传感器 编解码 索引
|
编解码 数据可视化 数据挖掘
PCL特征点与配准(1)
关于输入一个具体的物体的点云,从场景中找出与该物体点云相匹配的,这种方法可以用来抓取指定的物体等等,具体的代码的解释如下,需要用到的一些基础的知识,在之前的博客中都有提及,其中用到的一些方法可以翻阅前面的博客,当然有问题可以关注公众号,与众多爱好者一起交流 具体的代码实现 #include #include //点云类型头文件 #include //对应表示两个实体之间的匹配(例如,点,描述符等)。
2473 0
|
数据可视化 算法
PCL点云配准(2)
(1)正态分布变换进行配准(normal Distributions Transform) 介绍关于如何使用正态分布算法来确定两个大型点云之间的刚体变换,正态分布变换算法是一个配准算法,它应用于三维点的统计模型,使用标准最优化技术来确定两个点云间的最优匹配,因为其在配准的过程中不利用对应点的特征计算和匹配,所以时间比其他方法比较快, 对于代码的解析 /* 使用正态分布变换进行配准的实验 。
2320 0
|
存储 算法 数据可视化
PCL点云配准(1)
在逆向工程,计算机视觉,文物数字化等领域中,由于点云的不完整,旋转错位,平移错位等,使得要得到的完整的点云就需要对局部点云进行配准,为了得到被测物体的完整数据模型,需要确定一个合适的坐标系,将从各个视角得到的点集合并到统一的坐标系下形成一个完整的点云,然后就可以方便进行可视化的操作,这就是点云数据的配准。
2597 0
|
算法 数据可视化
PCL法线估计
平面的法线是垂直于它的单位向量。在点云的表面的法线被定义为垂直于与点云表面相切的平面的向量。表面法线也可以计算点云中一点的法线,被认为是一种十分重要的性质。常常在被使用在很多计算机视觉的应用里面,比如可以用来推出光源的位置,通过阴影与其他视觉影响,表面法线的问题可以近似化解为切面的问题,这个切面的问题又会变成最小二乘法拟合平面的问题 解决表面法线估计的问题可以最终化简为对一个协方差矩阵的特征向量和特征值的分析(或者也叫PCA-Principal Component Analysis 主成分分析),这个协方差矩阵是由查询点的最近邻产生的。
1697 0
PCL点云分割(2)
关于点云的分割算是我想做的机械臂抓取中十分重要的俄一部分,所以首先学习如果使用点云库处理我用kinect获取的点云的数据,本例程也是我自己慢慢修改程序并结合官方API 的解说实现的,其中有很多细节如果直接更改源程序,可能会因为数据类型,或者头文件等各种原因编译不过,会导致我们比较难得找出其中的错误,...
1970 0
|
存储 数据挖掘 索引
PCL点云分割(1)
点云分割是根据空间,几何和纹理等特征对点云进行划分,使得同一划分内的点云拥有相似的特征,点云的有效分割往往是许多应用的前提,例如逆向工作,CAD领域对零件的不同扫描表面进行分割,然后才能更好的进行空洞修复曲面重建,特征描述和提取,进而进行基于3D内容的检索,组合重用等。
2079 0
|
机器学习/深度学习 数据可视化 算法
PCL行人检测
首先我们知道Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功,HOG+SVM进行行人检测的方法是法国研究人员Dalal在2005的CVPR上提出的,而如今虽然有很多行人检测算法不断提出,但基本都是以HOG+SVM的思路为主,那么PCL中也是利用这一思想来进行行人的检测, 总体思路: 1、提取正负样本hog特征 2、投入svm分类器训练,得到model 3、由model生成检测子 4、利用检测子检测负样本,得到hardexample 5、提取hardexample的hog特征并结合第一步中的特征一起投入训练,得到最终检测子。
1623 0