PCL中用于点云滤波的一个工具是StatisticalOutlierRemoval

其大致的原理思路是:

1. 对每个点,我们计算它到它的K邻域内所有点的平均距离d。对输入点云中的每个点都进行这样的计算,即每个点都可以求得其对应的d,因此可以得到一个包含各点d值的数组,记为distance。

2. 对于输入点云中的所有点,假设得到distance数组中的各元素构成一个高斯分布,该数组即为一个样本,样本容量为点云包含的点数目。高斯分布曲线的形状由样本的均值和标准差决定,d值在标准范围(由样本的均值和方差定义〉之外的对应点,可被定义为离群点并可从数据集中去除掉。

具体的,下面贴上PCL源码进行分析

//该函数包含了上述算法的主要操作
template <typename PointT> void
pcl::StatisticalOutlierRemoval<PointT>::applyFilterIndices (std::vector<int> &indices)
{// Initialize the search class —— —— 初始化if (!searcher_){if (input_->isOrganized ())searcher_.reset (new pcl::search::OrganizedNeighbor<PointT> ());elsesearcher_.reset (new pcl::search::KdTree<PointT> (false));}searcher_->setInputCloud (input_);// The arrays to be usedstd::vector<int> nn_indices (mean_k_); //mean_k_为定义的K邻域搜索的K值std::vector<float> nn_dists (mean_k_);std::vector<float> distances (indices_->size ());indices.resize (indices_->size ());removed_indices_->resize (indices_->size ());int oii = 0, rii = 0;  // oii = output indices iterator, rii = removed indices iterator// First pass: Compute the mean distances for all points with respect to their k nearest neighborsint valid_distances = 0; //记录共有多少点//下面开始遍历点云中各点,计算各点到其K邻域点的平均距离,每个点的结果放入distance数组中for (int iii = 0; iii < static_cast<int> (indices_->size ()); ++iii)  // iii = input indices iterator{if (!pcl_isfinite (input_->points[(*indices_)[iii]].x) ||!pcl_isfinite (input_->points[(*indices_)[iii]].y) ||!pcl_isfinite (input_->points[(*indices_)[iii]].z)){distances[iii] = 0.0;continue;}// Perform the nearest k search//searcher_->nearestKSearch函数是PCL中定义的K邻域搜索模块中的函数//searcher_->nearestKSearch有四个参数://para1:查找点; para2:搜索范围K+1;//para3:k个邻域点的下标;//para4:k个邻域点到该查找点的距离的平方(是两点之间距离的平方)if (searcher_->nearestKSearch ((*indices_)[iii], mean_k_ + 1, nn_indices, nn_dists) == 0){distances[iii] = 0.0;PCL_WARN ("[pcl::%s::applyFilter] Searching for the closest %d neighbors failed.\n", getClassName ().c_str (), mean_k_);continue;}// Calculate the mean distance to its neighborsdouble dist_sum = 0.0;for (int k = 1; k < mean_k_ + 1; ++k)  // k = 0 is the query pointdist_sum += sqrt (nn_dists[k]);distances[iii] = static_cast<float> (dist_sum / mean_k_);valid_distances++;} //结束循环,得到点云中各点对应的K邻域平均距离// Estimate the mean and the standard deviation of the distance vector//计算distance数组的均值mean和标准偏差stddev——反映了整片点云的性质double sum = 0, sq_sum = 0;for (size_t i = 0; i < distances.size (); ++i){sum += distances[i];sq_sum += distances[i] * distances[i];}double mean = sum / static_cast<double>(valid_distances);double variance = (sq_sum - sum * sum / static_cast<double>(valid_distances)) / (static_cast<double>(valid_distances) - 1);double stddev = sqrt (variance);//基于上述计算得到的整片点云的mean和stddev,设置判断阈值distance_threshold//distance_threshold是用于判断点云中点是否为离群点的阈值double distance_threshold = mean + std_mul_ * stddev;//比较各点的k邻域平均距离与整片点云的distance_threshold,若超过阈值则作为离群点舍弃// Second pass: Classify the points on the computed distance thresholdfor (int iii = 0; iii < static_cast<int> (indices_->size ()); ++iii)  // iii = input indices iterator{// Points having a too high average distance are outliers and are passed to removed indices// Unless negative was set, then it's the opposite conditionif ((!negative_ && distances[iii] > distance_threshold) || (negative_ && distances[iii] <= distance_threshold)){if (extract_removed_indices_)(*removed_indices_)[rii++] = (*indices_)[iii];continue;}// Otherwise it was a normal point for output (inlier)indices[oii++] = (*indices_)[iii];}// Resize the output arraysindices.resize (oii);removed_indices_->resize (rii);
}

通过代码中的细节可以看到,

1. 对每个点,计算它到它的K邻域内所有点的平均距离d,最终放到数组distance中;

2. 数组distance所构成的样本,其mean均值计算方式就是简单的元素相加除以样本数量

3. 数组distance所构成的样本,其stddev标准偏差(standard deviation)计算方式是:

for (size_t i = 0; i < distances.size (); ++i){sum += distances[i];sq_sum += distances[i] * distances[i];}
double variance = (sq_sum - sum * sum / static_cast<double>(valid_distances)) / (static_cast<double>(valid_distances) - 1);double stddev = sqrt (variance);

4. 作为离群点判断的阈值distance_threshold,其计算方式是:

double distance_threshold = mean + std_mul_ * stddev;

其中,std_mul_是一个标准偏差的倍乘参数,用于调整阈值大小,在使用PCL的StatisticalOutlierRemoval类时,该参数std_mul_由用户设置

5.关于std_mul_的选取:由于只有当某个点的K邻域平均距离大于该阈值distance_threshold 时才会被认定为离群点,而且distance_threshold = mean + std_mul_ * stddev。又因为对于同一片点云,其mean和stddev是不变的,因此std_mul_ 的大小决定了滤波的效果。

std_mul_越小,则distance_threshold 越小,则过滤效果越明显(大于阈值的点被过滤)

反之,std_mul_越大,则distance_threshold 越大,则过滤效果越不明显

至于选取std_mul_时是否需要考虑其对应的几何意义,本人认为不需要,只需要遵循上面规律,根据滤波测试结果对std_mul_参数调试选择最合适的即可,似乎不好根据几何意义选取std_mul_的值。

在上述分析后,进行一个实际的测试。使用PCL的StatisticalOutlierRemoval类的代码如下(需要使用头文件:#include <pcl/filters/statistical_outlier_removal.h>):

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;   //创建滤波器对象
sor.setInputCloud(cloud);                           //设置待滤波的点云
sor.setMeanK(50);                               //设置在进行统计时考虑的临近点个数
sor.setStddevMulThresh(1.0);                      //设置判断是否为离群点的阀值,用来倍乘标准差,也就是上面的std_mul
sor.filter(*cloud_filtered);                    //滤波结果存储到cloud_filtered

对输入的一片点云进行滤波,设置std_mul_值分别为2.0,1.0,结果如下:

std_mul_=2.0时,初始点有14722个,过滤后还剩14043个,滤掉了679个,占原有点的4.6%;

std_mul_=1.0时,过滤后还剩13125个,滤掉了1597个,占原有点的10.8%;

最后,对PCL的StatisticalOutlierRemoval类进行了简单分析:

该滤波方法的实质为,对查找点到其K邻域点的平均距离这一值进行判断。判断的依据(即阈值)与全局点的分布相关,但是对于一片点云来说,该阈值是固定不变的。因此,某查找点的邻域点分布情况,就决定了它是否容易被认定为离群点。

因此,容易被该方法认定为离群点过滤掉的点,一般是以下几类点:

1. 相对孤单的离群点,由于是离群的,其K邻域的平均距离会比较大,因此会被认定为离群点——这是滤波算法想要的结果。但是,有的情况是这样的,离群的这些点具有聚集性,例如一大片平面点外,有一小簇(不只有几个点)噪声点,为了将这部分离群点去除,需要设置的K邻域搜索范围K足够大(应该要比这一簇噪声点的包含点数尽量大一些),这样就可以去除这部分离群点。不过随之带来的问题是,K搜索范围增大会减慢运行速度。

2. 边缘点。边缘点的K邻域不像非边缘点,其K近邻点的平均距离肯定是要大一些的,因此上述PCL的StatisticalOutlierRemoval类在过滤离群点时,也会将点云的边缘的点过滤一部分——这是算法所不想要的结果。

所以,该方法存在一些弊端,一是对于离群点具有小范围聚集的情况,算法为保证过滤效果需要更大的耗时;二是在过滤离群点的同时,会把边界点过滤。

PCL滤波工具之StatisticalOutlierRemoval深度分析相关推荐

  1. 点云库PCL学习笔记 -- 点云滤波Filtering -- 3. StatisticalOutlierRemoval 统计滤波器

    点云库PCL学习笔记 -- 点云滤波Filtering -- 3.StatisticalOutlierRemoval 统计滤波器 StatisticalOutlierRemoval 统计滤波器相关简介 ...

  2. envi 文件 生成mat_JVM 内存分析工具 MAT 的深度讲解与实践——入门篇

    1. MAT 工具简介 MAT(全名:Memory Analyzer Tool),是一款快速便捷且功能强大丰富的 JVM 堆内存离线分析工具.其通过展现 JVM 异常时所记录的运行时堆转储快照(Hea ...

  3. 泛工具产品深度分析 #1 独立产品周刊

    这个专题每期会对几款特定类型的产品做一些深度分析,主要是我对一些产品的观察和分析.主要关注产品的市场/品类/定位/趋势/变现模式/推广玩法等,覆盖国内外移动应用,可能也会做一些Web端的产品分析.为独 ...

  4. get这款工具,不会机器学习也能轻松搞定深度分析

    机器学习是一门多学科交叉专业,涵盖概率论知识.统计学知识.近似理论知识和复杂算法知识.机器学习算法是一类从数据中自动分析获得规律,并利用规律对未知数据进行预测的算法.通过计算机对数据的处理和对算法的运 ...

  5. 2022-2028年中国交通建设PPP模式深度分析及发展战略研究报告(全卷)

    [报告类型]产业研究 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了PPP模式行业相关概述.中国PPP模式行业运行环境.分析了中国PPP ...

  6. io获取 pcl_点云数据可视化之PCL滤波学习

    PCL滤波概述 在获取点云数据时 ,由于设备精度,操作者经验环境因素带来的影响,以及电磁波的衍射特性,被测物体表面性质变化和数据拼接配准操作过程的影响,点云数据中将不可避免的出现一些噪声.在点云处理流 ...

  7. 文本深度表示模型Word2Vec 简介 Word2vec 是 Google 在 2013 年年中开源的一款将词表征为实数值向量的高效工具, 其利用深度学习的思想,可以通过训练,把对文本内容的处理简

    文本深度表示模型Word2Vec 简介 Word2vec 是 Google 在 2013 年年中开源的一款将词表征为实数值向量的高效工具, 其利用深度学习的思想,可以通过训练,把对文本内容的处理简化为 ...

  8. linux hashmap,Java中对HashMap的深度分析与比较

    Java中对HashMap的深度分析与比较 在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键.由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问 ...

  9. Toast源码深度分析

    目录介绍 1.最简单的创建方法 1.1 Toast构造方法 1.2 最简单的创建 1.3 简单改造避免重复创建 1.4 为何会出现内存泄漏 1.5 吐司是系统级别的 2.源码分析 2.1 Toast( ...

最新文章

  1. 实时监控fps的linux代码,GitHub - Forec/monitor-recorder: Monitor (实时视频监控、运动检测视频记录)...
  2. jQuery Event对象的属性和方法
  3. 客户端与服务器持续同步解析(轮询,comet,WebSocket)
  4. FPGA模拟串口发送功能的Verilog代码
  5. javascript提取标签之间的信息
  6. python3.0与2.0,python3.0与python2.0有哪些不同
  7. 简单的数据增强代码(C++与opencv)
  8. 测试服务器IO和网速的脚本
  9. 【uiautomator】运行命令
  10. Mr.J--JS学习(继承模式发展史)
  11. STM32 输入捕获功能
  12. 域名型通配符ssl证书_西部数码使用指南:申请了主域名SSL证书,是否还需要申请www域名的...
  13. 力扣题目——637. 二叉树的层平均值
  14. PHP使用 uEditor富文本编辑器
  15. PHPCMS2008调用Uchome系统[空间之星]GET语句
  16. pringboot+校园健身互助平台 毕业设计-附源码221540S
  17. 技术图文:基于“科比投篮”数据集学Pandas
  18. Hbase下载、安装流程
  19. 如何制作linux安装光盘,新手看招 如何制作Linux系统的安装光盘?
  20. 守望轮回谷等待服务器响应,《守望轮回谷》即将接班自走棋?Dota2新地图再次掀起热潮...

热门文章

  1. HackTheBox - Brainfuck Write Up
  2. 百田游戏策划面试经验
  3. Linux的判断两个字符串是否相等
  4. 移动应用进入碎片化时代
  5. SnmpTrap测试与学习
  6. win10计算机本地连接属性在哪里,Win10系统怎么打开本地连接属性
  7. 基于数据挖掘的客户流失分析案例
  8. 微信公众号调起扫一扫扫码
  9. iOS 播放沙盒视频
  10. MySQL参数优化:back_log