稀疏离群值的消除基于输入数据集中点到邻居距离的分布的计算。对于每个点,我们计算从它到所有相邻点的平均距离。通过假设结果分布是具有均值和标准差的高斯分布,可以将其平均距离在由全局距离均值和标准差定义的区间之外的所有点视为离群值并从数据集中进行修剪。 下图显示了稀疏离群值分析和删除的效果:原始数据集显示在左侧,结果数据集显示在右侧。数据集图显示了滤波前后每个点的邻域中平均K最近邻距离。
来源:官方文档:https://pcl-tutorials.readthedocs.io/en/latest/statistical_outlier.html#statistical-outlier-removal
一.使用StatisticalOutlierRemoval filter滤波器进行离散点去除
1.1 StatisticalOutlierRemoval filter滤波器作用和功能:
使用统计分析技术,从一个点云数据中集中移除测量噪声点(也就是离群点)比如:激光扫描通常会产生密度不均匀的点云数据集,另外测量中的误差也会产生稀疏的离群点,使效果不好,估计局部点云特征(例如采样点处法向量或曲率变化率)的运算复杂,这会导致错误的数值,反过来就会导致点云配准等后期的处理失败。
解决办法:每个点的邻域进行一个统计分析,并修剪掉一些不符合一定标准的点,稀疏离群点移除方法基于在输入数据中对点到临近点的距离分布的计算,对每一个点,计算它到它的所有临近点的平均距离,假设得到的结果是一个高斯分布,其形状是由均值和标准差决定,平均距离在标准范围之外的点,可以被定义为离群点并可从数据中去除。
1.2 离散点去除的实现原理(来源:http://robot.czxy.com/docs/pcl/chapter02/filtering/):
-->> 其中涉及到的统计学概念-高斯分布-置信度:
https://baike.baidu.com/item/%E7%BD%AE%E4%BF%A1%E5%8C%BA%E9%97%B4/7442583?fr=aladdin
置信区间是指由样本统计量所构造的总体参数的估计区间。在统计学中,一个概率样本的置信区间(Confidence interval)是对这个样本的某个总体参数的区间估计。置信区间展现的是这个参数的真实值有一定概率落在测量结果的周围的程度,其给出的是被测量参数的测量值的可信程度,即前面所要求的“一个概率”。 [1]
置信区间是一种常用的区间估计方法,所谓置信区间就是分别以统计量的置信上限和置信下限为上下界构成的区间 [2] 。对于一组给定的样本数据,其平均值为μ,标准偏差为σ,则其整体数据的平均值的100(1-α)%置信区间为(μ-Ζα/2σ , μ+Ζα/2σ) ,其中α为非置信水平在正态分布内的覆盖面积 ,Ζα/2即为对应的标准分数。 [1]
总结而言,这个方法求出的置信区间的主要作用为:计算出当前点附近的其他点,合并起来的点云的统计学平均坐标值,计算出一个平均的置信区间;那么,如果是非噪声点,其坐标必定落在置信区间内,得以保留;而噪声的坐标将与置信区间偏移较大,将被滤除。
二.使用“离散点去除法” 对点云数据进行滤波
注意,此代码实现原理为:离散点去除的原理:首先计算当前点及周围50个点的均值和标准差,之后设置偏差值(在此例中设置为:和均值相差1个标准差的点将被全部去除),然后执行滤波操作。
2.1 代码实现大致过程:
1.创建带处理点云对象:注意变量格式为:pcl::PCLPointCloud<pcl::PointXYZ>::Ptr
2.创建处理后点云对象:pcl::PCLPointCloud<pcl::PointXYZ>::Ptr
3.将PCD文件导入,并存入带处理点云对象中:使用pcl::PCDreader
4.创建StatisticalOutlierRemoval离散点处理对象,并设置:求取每个点周围多少个点的均值与标准差(此处为50个点)+ 滤波阈值(超出预设标准差多少个单位将被过滤)
5.执行滤波,并存入处理后点云对象中
6.将滤波结束后的点云存储至PCD文件中
#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){
//Step1: 创建带处理及处理后的点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
//Step2: 加载计算机内PCD点云文件,注意,此处读取点云方式与体素滤波不一样,因为点云格式不同
pcl::PCDReader reader;
reader.read<pcl::PointXYZ>("table_scene_lms400.pcd", *cloud);
std::cerr<< "The info of the original PCD file is shown below:"<<std::endl;
std::cerr<< *cloud<<std::endl;
//step3: 创建离散点去除对象,并设置参数,处理原始点云,输出处理后的点云
// 创建过滤器,每个点分析计算时考虑的最近邻居个数为50个(也就是取每个点及其周围50个点,去均值+标准差-》高斯分布);
// 设置标准差阈值为1,这意味着所有距离查询点的平均距离的标准偏差均大于1个标准偏差的所有点都将被标记为离群值并删除。
// 计算输出并将其存储在cloud_filtered中
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
sor.setInputCloud (cloud);
sor.setMeanK(50);
sor.setStddevMulThresh(1.0);
sor.filter(*cloud_filtered);
//Step4:输出点云数据到PCD文件
std::cerr<<"The filtered PCD file info is shown below: "<< std::endl;
std::cerr<< *cloud_filtered <<std::endl;
pcl::PCDWriter writer;
writer.write<pcl::PointXYZ>("table_scene_lms400_inliers.pcd",*cloud_filtered);
//step5: 与第4步相反,将被过滤掉的点显示出来并保存
sor.setNegative (true);
sor.filter(*cloud_filtered);
writer.write<pcl::PointXYZ>("table_scene_lms400_outliers.pcd",*cloud_filtered);
return(0);
}
效果如下: