噪声点与离群点。在获取点云数据时,由于设备精度、操作者经验、环境因素等带来的影响,以及电磁波衍射特性、被测物体表面性质变化和数据拼接配准操作过程的影响,点云数据中将不可避免地出现一些噪声点,属于随机误差。除此之外,由于受到外界干扰如视线遮挡,障碍物等因素的影响,点云数据中往往存在着一些距离主题点云较远的离散点,即离群点。
**点云处理中滤波目的。**滤波处理作为点云处理的第一步,对后续处理有很重要。只有在滤波处理流程中将噪声点、离群点、空洞、数据压缩等按照后续处理定制,才能更好地进行配准、特征提取、曲面重建、可视化等后续应用处理。点云数据集中每一个点表达一定的信息量,某个区域点越密集有用的信息量越大。孤立的离群点信息量较小,其表达的信息量可以忽略不计。
对于在空间分布有一定空间特征的点云数据,比如使用线结构光扫描的方式采集点云,沿z向分布较广,但x,y向的分布处于有限范围内。此时可使用直通滤波器,确定点云在x或y方向上的范围,可较快剪除离群点,达到第一步粗处理的目的。
体素的概念类似于像素,使用AABB包围盒将点云数据体素化,一般体素越密集的地方信息越多,噪音点及离群点可通过体素网格去除。另一方面如果使用高分辨率相机等设备对点云进行采集,往往点云会较为密集。过多的点云数量会对后续分割工作带来困难。体素滤波器可以达到向下采样同时不破坏点云本身几何结构的功能。
考虑到离群点的特征,则可以定义某处点云小于某个密度,既点云无效。计算每个点到其最近的k个点平均距离。则点云中所有点的距离应构成高斯分布。给定均值与方差,可剔除3∑之外的点。
条件滤波器通过设定滤波条件进行滤波,有点分段函数的味道,当点云在一定范围则留下,不在则舍弃。
半径滤波器与统计滤波器相比更加简单粗暴。以某点为中心画一个圆计算落在该圆中点的数量,当数量大于给定值时,则保留该点,数量小于给定值则剔除该点。此算法运行速度快,依序迭代留下的点一定是最密集的,但是圆的半径和圆内点的数目都需要人工指定。
双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点 。双边滤波器的好处是可以做边缘保存。先简要介绍图像的双边滤波:
该算法是针对图像的空间域(spatial domain)和像素范围域(range domain),所以在设计的时候就会有两个权重,Ws和Wr,那么公式就可以简单的理解为:
p为当前点,之所以是向量,因为有时候图像不只是灰度图像,也有三色图像,所以用向量表示p的多维空间,I则为图像,Ip就是表示图像I的p点,S为p的邻域集,q是邻域中的一个点,BF则为输出的图像。
,
σs和σc分别为空域滤波权值函数的标准差和像素相关性权值函数的标准差。
双边滤波的权重是ws和wr的乘积。对于ws来说,这就是普通的高斯滤波函数,其代入的坐标,sigmas是程序输入值,该函数是在空间临近度上计算的。而wr是计算像素值相似度(颜色空间)。
当图像在变化程度平缓的区域时,邻域中的像素值(RGB值)差距相差不大。此时wr无限接近于1,因此此时的双边就是普通的高斯滤波,达到对图像平滑的效果,如左图。
当图像在变化程度剧烈的区域,比如在边缘区域时,邻域中的像素值(RGB值)差距相差很大。此时wr朝0值趋近,颜色差值越大,wr越逼近0,最终整个式子的值逼近于0。最终的结果是权值为0。因此在最终计算时,该处将不影响输出值,如右图。
对于双边滤波不只用在图像,很多时候也会在处理点云数据的时候使用,对点云数据进行光滑处理。双边滤波算法主要用于对点云数据的小尺度起伏噪声进行平滑光顺。双边滤波应用于三维点云数据去噪,既有效地对空间三维模型表面进行降噪,又可以保持点云数据中的几何特征信息,避免三维点云数据被过渡光滑。在点云模型中设点p的k邻域点集及单位法向量分别为与 ,双边滤波可以定义为:
WC,WS 分别表示双边滤波函数的空间域和频率域权重函数,它们分别控制着双边滤波的平滑程度和特征保持程度。为n与pj-pi的内积,, 为点 的法向量。
pcl::PointCloud<pcl::PointXYZ>::Ptr xyz (new pcl::PointCloud<pcl::PointXYZ>);
pcl::FastBilateralFilter<pcl::PointXYZ> fbf;
fbf.setInputCloud (xyz);
fbf.setSigmaS (sigma_s);//设置双边滤波器用于空间邻域/窗口的高斯的标准偏差
fbf.setSigmaR (sigma_r);//设置高斯的标准偏差用于控制相邻像素由于强度差异而下降多少(在我们的情况下为深度)
pcl::PointCloud<pcl::PointXYZ> xyz_filtered;
fbf.filter (xyz_filtered);
注意:能使用双边滤波的点云必须得包含强度字段。现有的points类型中,只有PointXYZI和PointXYZINormal有强度信息。FastBilateralFilter只适用于有序点云。
from:https://mp.weixin.qq.com/s/9pxff6LwcecDHsx4kI34sw
点云和图像一样,有可能也存在频率的概念。点云表达的是三维空间中的一种信息,这种信息本身并没有一一对应的函数值。故点云本身并没有在讲诉一种变化的信号。但点云存在某种空间关系。我们可以人为的指定点云空间中的一个点,基于此点来讨论点云在各个方向上所谓的频率。
在传统的信号处理中,高频信号一般指信号变化快,低频信号一般指信号变化缓慢。在图像处理中,高低频的概念被引申至不同方向上图像灰度的变化,傅里叶变换可以用于提取图像的周期成分滤除布纹噪声。在点云处理中,定义:点云法线向量差为点云所表达的信号。换言之,如果某处点云曲率大,则点云表达的是一个变化的信号。如果点云曲率小,则其表达的是一个不变的信号。这和我们的直观感受也是相近的,地面曲率小,它表达的信息量也小;人的五官部分曲率大,其表达了整个Scan中最大的信息量。
DoN算法
点云频率的思想已经被广泛的应用在了各个方面,最著名的莫过于DoN算法。DoN算法被作者归类于点云分割算法中,本质上DoN只是一种前处理,应该算是一种比较先进的点云滤波算法。分割本质上还是由欧式分割算法完成的。DoN 是 Difference of Normal 的简写。算法的目的是在去除点云低频滤波,低频信息(例如建筑物墙面,地面)往往会对分割产生干扰,高频信息(例如建筑物窗框,路面障碍锥)往往尺度上很小,直接采用 基于临近信息 的滤波器会将此类信息合并至墙面或路面中。所以DoN算法利用了多尺度空间的思想,算法如下:
在小尺度上计算点云法线1
在大尺度上计算点云法线2
法线1-法线2
滤去3中值较小的点
根据第三步得到的法线差,进行欧式分割
显然,在小尺度上是可以对高频信息进行检测的,此算法可以很好的小尺度高频信息。其在大规模点云(如LiDar点云)中优势尤其明显。
// Create a search tree, use KDTreee for non-organized data.
pcl::search::Search<PointXYZRGB>::Ptr tree;
if (cloud->isOrganized ())
{
tree.reset (new pcl::search::OrganizedNeighbor<PointXYZRGB> ());
}
else
{
tree.reset (new pcl::search::KdTree<PointXYZRGB> (false));
}
// Set the input pointcloud for the search tree
tree->setInputCloud (cloud);
//生成法线估计器(OMP是并行计算,忽略)
pcl::NormalEstimationOMP<PointXYZRGB, PointNormal> ne;
ne.setInputCloud (cloud);
ne.setSearchMethod (tree);
//设定法线方向(要做差,同向很重要)
ne.setViewPoint (std::numeric_limits<float>::max (), std::numeric_limits<float>::max (), std::numeric_limits<float>::max ());
//计算小尺度法线
pcl::PointCloud<PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<PointNormal>);
ne.setRadiusSearch (scale2);
ne.compute (*normals_large_scale);
//计算大尺度法线
pcl::PointCloud<PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<PointNormal>);
ne.setRadiusSearch (scale2);
ne.compute (*normals_large_scale);
//生成DoN分割器
pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> don;
don.setInputCloud (cloud);
don.setNormalScaleLarge (normals_large_scale);
don.setNormalScaleSmall (normals_small_scale);
//计算法线差
PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>);
copyPointCloud<PointXYZRGB, PointNormal>(*cloud, *doncloud);
don.computeFeature (*doncloud);
//生成滤波条件:把法线差和阈值比
pcl::ConditionOr<PointNormal>::Ptr range_cond (
new pcl::ConditionOr<PointNormal> ()
);
range_cond->addComparison (pcl::FieldComparison<PointNormal>::ConstPtr (
new pcl::FieldComparison<PointNormal> ("curvature", pcl::ComparisonOps::GT, threshold))
);
//生成条件滤波器,输入滤波条件和点云
pcl::ConditionalRemoval<PointNormal> condrem (range_cond);
condrem.setInputCloud (doncloud);
//导出滤波结果
pcl::PointCloud<PointNormal>::Ptr doncloud_filtered (new pcl::PointCloud<PointNormal>);
condrem.filter (*doncloud_filtered);
//欧式聚类~~~(略)
PCL实现参见博客:https://www.cnblogs.com/ironstark/p/5010771.html
————————————————
版权声明:本文为CSDN博主「菜鸟知识搬运工」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_30815237/article/details/86294496