为什么要对点云滤波?
一般下面这几种情况需要进行点云滤波处理:
(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
结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点 。双边滤波器的好处是可以做边缘保存。先简要介绍图像的双边滤波:
该算法是针对图像的空间域(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只适用于有序点云。
2.4、基于点云频率的滤波方法
点云的频率: 点云和图像一样,有可能也存在频率的概念。点云表达的是三维空间中的一种信息,这种信息本身并没有一一对应的函数值。故点云本身并没有在讲诉一种变化的信号。但点云存在某种空间关系。我们可以人为的指定点云空间中的一个点,基于此点来讨论点云在各个方向上所谓的频率。
在传统的信号处理中,高频信号一般指信号变化快,低频信号一般指信号变化缓慢。在图像处理中,高低频的概念被引申至不同方向上图像灰度的变化,傅里叶变换可以用于提取图像的周期成分滤除布纹噪声。在点云处理中,定义:点云法线向量差为点云所表达的信号。换言之,如果某处点云曲率大,则点云表达的是一个变化的信号。如果点云曲率小,则其表达的是一个不变的信号。这和我们的直观感受也是相近的,地面曲率小,它表达的信息量也小;人的五官部分曲率大,其表达了整个Scan中最大的信息量。
DoN算法
DoN算法被作者归类于点云分割算法中,本质上DoN只是一种前处理,应该算是一种比较先进的点云滤波算法。分割本质上还是由欧式分割算法完成的。DoN 是 Difference of Normal 的简写。算法的目的是在去除点云低频滤波,低频信息(例如建筑物墙面,地面)往往会对分割产生干扰,高频信息(例如建筑物窗框,路面障碍锥)往往尺度上很小,直接采用 基于临近信息 的滤波器会将此类信息合并至墙面或路面中。所以DoN算法利用了多尺度空间的思想,算法如下:
- 在小尺度上计算点云法线1
- 在大尺度上计算点云法线2
- 法线1-法线2
- 滤去3中值较小的点
- 根据第三步得到的法线差,进行欧式分割
显然,在小尺度上是可以对高频信息进行检测的,此算法可以很好的小尺度高频信息。其在大规模点云(如LiDar点云)中优势尤其明显。