PCL点云滤波去噪
为什么要对点云滤波?一般下面这几种情况需要进行点云滤波处理:(1) 点云数据密度不规则需要平滑(2) 因为遮挡等问题造成离群点需要去除(3) 大量数据需要下采样(4) 噪声数据需要去除点云中的噪声点对后续操作的影响比较大。就像盖房子一样,地基有很多瑕疵,如果不加以处理最终可能会导致整个房子坍塌的。不过别担心,PCL中有一个专门的点云滤波模块,可以将噪声点去除,还可以进行...
为什么要对点云滤波?
一般下面这几种情况需要进行点云滤波处理:
(1) 点云数据密度不规则需要平滑
(2) 因为遮挡等问题造成离群点需要去除
(3) 大量数据需要下采样
(4) 噪声数据需要去除
点云中的噪声点对后续操作的影响比较大。就像盖房子一样,地基有很多瑕疵,如果不加以处理最终可能会导致整个房子坍塌的。不过别担心,PCL中有一个专门的点云滤波模块,可以将噪声点去除,还可以进行点云压缩等操作,非常灵活实用,例如:双边滤波,统计滤波,条件滤波,随机采样一致性滤波等。这样才能够更好的进行配准,特征提取,曲面重建,可视化等后续应用处理。PCL中关于点云滤波的所有函数都在这里:
http://docs.pointclouds.org/trunk/group__filters.html
一般来说,滤波对应的方案有如下几种:
(1)按照给定的规则限制过滤去除点
(2) 通过常用滤波算法修改点的部分属性
(3)对数据进行下采样
1.点云下采样:
点云的数目越大,储存、操作都是个大问题!通过按一定的规则从里面抽取有代表性的样本,可以代替原来的样本,节省计算开销,这个下采样PCL中有专门的类,叫做
class pcl::ApproximateVoxelGrid< PointT >
比较适合对海量的点云在处理前进行数据压缩,而且可以在特征提取等处理中选择合适的体素(voxel)大小等参数,提高算法效率。该函数对输入的点云数据创建一个三维体素栅格,每个体素内用体素中所有点的重心来近似显示体素中其他点,这样该体素内所有点都用一个重心点最终表示。它的优点是可以在下采样的时候保存点云的形状特征。
关键代码:
pcl::VoxelGrid<PointT> downSampled; //创建滤波对象
downSampled.setInputCloud (cloud); //设置需要过滤的点云给滤波对象
downSampled.setLeafSize (0.01f, 0.01f, 0.01f); //设置滤波时创建的体素体积为1cm的立方体,三个参数表示体素栅格叶大小,分别表示体素在XYZ方向的尺寸
downSampled.setDownsampleAllData(bool downsample)//设置是否对所有的字段进行下采样
downSampled.filter (*cloud_downSampled); //执行滤波处理,存储输出
setDownsampleAllData的意思是:点云有不同的类型,比如 PointXYZ,有的是PointXYZRGB,还有其他类型,也就是一个点包含多种不同信息,比如空间位置XYZ,颜色信息RGB,或者强度信息等,如果想要对所有信息(字段)下采样则设置为true,只对XYZ下采样的话设置为false。下采样结果如下图所示。
2.去除点云的离群点
离群点对应的英文是outliers,也叫外点,就是明显偏离“群众”的点,比如我们用激光扫描一面平坦的墙壁,正常情况下得到的应该是差不多也位于同一个平面的点云,但是由于设备测量误差等原因,会产生少量脱离群众的空间点,离本来的墙壁过远,我们就叫这部分点为离群点。离群点会使局部点云特征(如表面法线或曲率变化)的估计复杂化,从而导致错误的值,从而可能导致点云配准失败。列举两个常用的去除离群点的类:StatisticalOutlierRemoval 、RadiusOutlierRemoval
2.1 StatisticalOutlierRemoval
顾名思义,使用统计分析技术,从一个点云数据中集中移除测量噪声点。对每个点的邻域进行统计分析,剔除不符合一定标准的邻域点。具体来说:
1.对于每个点,计算它到所有相邻点的平均距离。假设得到的分布是高斯分布,我们可以计算出一个均值 μ 和一个标准差 σ;
2.这个邻域点集中所有点与其邻域距离大于 μ + std_mul * σ 区间之外的点都可以被视为离群点,并可从点云数据中去除。std_mul 是标准差倍数的一个阈值,可以自己指定。
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; //创建滤波器对象
sor.setInputCloud (cloud); //设置待滤波的点云
sor.setMeanK (50); //设置在进行统计时考虑的临近点个数
sor.setStddevMulThresh (1.0); //设置判断是否为离群点的阀值,用来倍乘标准差,也就是上面的std_mul
sor.filter (*cloud_filtered); //滤波结果存储到cloud_filtered
如上代码所示,先创建统计分析滤波器,然后设置滤波器输入是 cloud,也就是我们待处理的点云,然后设置对每个点分析的临近点的个数设置为50 ,并将标准差的倍数设置为1, 这意味着如果一个点的距离超出了平均距离加上一个标准差以上,则该点被标记为离群点,并将它移除。最后统计分析滤波后,输出的结果就是cloud_filtered。
2.2 RadiusOutlierRemoval
一个比较简单常用的方法就是根据空间点半径范围临近点数量来滤波,对应的类名是 RadiusOutlinerRemoval,这个很容易理解,它的滤波思想非常直接,就是在点云数据中,设定每个点一定半径范围内周围至少有足够多的近邻,不满足就会被删除。比如你指定了一个半径d,然后指定该半径内至少有1个邻居,那么下图中只有黄色的点将从点云中删除。如果指定了半径内至少有2个邻居,那么黄色和绿色的点都将从点云中删除。
pcl::RadiusOutlierRemoval<pcl::PointXYZ> pcFilter; //创建滤波器对象
pcFilter.setInputCloud(cloud); //设置待滤波的点云
pcFilter.setRadiusSearch(0.8); // 设置搜索半径
pcFilter.setMinNeighborsInRadius(2); // 设置一个内点最少的邻居数目
pcFilter.filter(*cloud_filtered); //滤波结果存储到cloud_filtered
2.3 FastBilateralFilter、BilateralFilter
双边滤波(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>为n与pj-pi的内积,, 为点 的法向量。
举一个极端的例子,如果对一条直线上的点进行双边滤波,因为每个点的法向量都相同,则接近于0,即y因子接近于零,此时取最大值。因为垂直,所以等于0,即最终双边滤波因子。这种结果是满足实际的。
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
2.4、基于点云频率的滤波方法
点云的频率: 点云和图像一样,有可能也存在频率的概念。点云表达的是三维空间中的一种信息,这种信息本身并没有一一对应的函数值。故点云本身并没有在讲诉一种变化的信号。但点云存在某种空间关系。我们可以人为的指定点云空间中的一个点,基于此点来讨论点云在各个方向上所谓的频率。
在传统的信号处理中,高频信号一般指信号变化快,低频信号一般指信号变化缓慢。在图像处理中,高低频的概念被引申至不同方向上图像灰度的变化,傅里叶变换可以用于提取图像的周期成分滤除布纹噪声。在点云处理中,定义:点云法线向量差为点云所表达的信号。换言之,如果某处点云曲率大,则点云表达的是一个变化的信号。如果点云曲率小,则其表达的是一个不变的信号。这和我们的直观感受也是相近的,地面曲率小,它表达的信息量也小;人的五官部分曲率大,其表达了整个Scan中最大的信息量。
DoN算法
点云频率的思想已经被广泛的应用在了各个方面,最著名的莫过于DoN算法。DoN算法被作者归类于点云分割算法中,本质上DoN只是一种前处理,应该算是一种比较先进的点云滤波算法。分割本质上还是由欧式分割算法完成的。DoN 是 Difference of Normal 的简写。算法的目的是在去除点云低频滤波,低频信息(例如建筑物墙面,地面)往往会对分割产生干扰,高频信息(例如建筑物窗框,路面障碍锥)往往尺度上很小,直接采用 基于临近信息 的滤波器会将此类信息合并至墙面或路面中。所以DoN算法利用了多尺度空间的思想,算法如下:
- 在小尺度上计算点云法线1
- 在大尺度上计算点云法线2
- 法线1-法线2
- 滤去3中值较小的点
- 根据第三步得到的法线差,进行欧式分割
显然,在小尺度上是可以对高频信息进行检测的,此算法可以很好的小尺度高频信息。其在大规模点云(如LiDar点云)中优势尤其明显。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)