1 什么是去噪
1.1 噪声
噪声:也称为孤立点/离群点/异常点,是指点云数据中的不相关或不希望存在的干扰信号或误差。噪声来源:环境光线的明亮程度、测量设备精度及系统误差、物体材料及表面的纹理和人为抖动等因素影响。
1.2 噪声来源
环境光线的明亮程度、测量设备精度及系统误差、物体材料及表面的纹理和人为抖动等因素。
1.3 点云去噪
在点云数据中,通过适当的滤波和处理方法,去除无用或噪声点,以提高数据质量和准确性的过程。
2 常见的去噪算法
2.1 统计滤波
原理
去除明显分布稀疏的离群点。根据给定均值与方差,可剔除方差之外的点,即方差之外的点是正确点。
举例
一点云中有50(N)个点,每个点的邻近点个数设置为8,则50(N)个点(8领域)的平均值计算如下:
则算出50(N)个点的平均值,设置距离阈值σ(比如为1.5倍平均值),若平均值在阈值之外的视为离群点,在点云数据中去除。
核心代码
—--统计滤波
//创建滤波器。对每个点分析的临近点的个数设置为50,并将标准差的倍数设置为1,这意味着如果一个点的距
离超出了平均距离一个标准差以上,则该点被标记为离群点,并将它移除,存储起来
pcl::Statistical0utlierRemowal<pcl : : PointIYZ>Sor;
sor. setInputCloud (cloud);//设置待波波的点云
sor.setMeamK (50); //设置在进行统计时考虑查询点邻近点数
Sor. setStddevMu1Thresh(1); //设置判断是否为高群点的阈值,里边的数字表示标准差的倍数,1个标准差以上就是离群点。
//即。当判断点的k近邻平均距高(mean distance)大于全局的1倍标准差+平均距离(global distances meanm and standard),则为离群点。
2.2 直通滤波
原理
根据点云的属性(属性比如x,y,z,颜色值等),在点的属性上设置范围,对点进行滤波,保留范围内的或保留范围外的,则去除离群点。
举例
在一个点云数据中,取z轴0~1范围内的点云进行保存。
核心代码
//创建滤波器对象
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud (c1oud);
pass.setFi1terFie1dName ("z");//滤波字段名被设置为z轴方向
pass.setFi1terLimits (0.0,1.0);//设置在过滤方向上的过滤范围
// pass.setKeepOrganized(true);//保持有序点云结构,该功能用于有序点云才有意义。
pass.setNegative (true);//设置保留范围内的点还是过滤掉范围内的点,标志为false时保留范围内的点
2.3 半径滤波
原理
设定滤波半径,计算每个点在其半径范围内的其他点的个数。半径范围内其他点个数少于某一设定的阈值的点将被滤除。
举例
设置半径为d,分别考察黄蓝绿三点,若点个数的阈值为1,则黄色点将被滤除;若阈值为2,则黄色点和绿色点都将被滤除。
3 核心代码
ror.setInputC1oud(c1oud_in); //输入点云
ror.setRadiusSearch(0.1); //设置半径为0.1m范围内找临近点
ror.setMinNeighborsInRadius(10); // 设置查询点的邻域点集数小于10删除
ror.fi1ter(*cloud_radius); //执行滤波
2.4 条件滤波
原理
根据点云数据的某些属性或特征进行筛选,可以一次删除满足对输入的点云设定的一个或多个条件指标的所有的数据点,如点的法线方向、点的强度值、点的颜色等属性来筛选点云数据。
条件滤波和直通滤波的区别:
条件滤波基于点的任何属性或特征进行筛选,而直通滤波只能基于轴向范围进行筛选。
2.5 中值滤波
原理
是常用的非线性滤波方法,用于去除图像或信号中的噪声。它通过将像素值替换为其邻域窗口内的中值来实现去噪的效果。
步骤
-
定义一个固定大小的邻域窗口,通常是一个正方形或矩形窗口。
-
将窗口内的像素值按照从小到大的顺序进行排序。
-
取排序后的像素值的中间值作为中心像素的新值,用于替换原始像素值。
-
对图像中的每个像素都应用上述步骤,以完成中值滤波。
-
如下图3×3的内核(也可看做窗口,或者模版):
2.6 均值滤波
原理
是一种常用的线性滤波方法,通过计算邻域窗口内像素值的平均值来实现去噪的效果。但会破坏图像细节,使图像变得模糊。
举例
3×3的内核(也可看做窗口,或者模版)中,包含了9个点及对应像素值。在对该区域进行滤波过程为:对P1~P9九个像素的灰度值求平均,代替中间P5的灰度值。
中值滤波和均值滤波的区别
-
中值滤波能够更好地处理脉冲噪声或孤立的离群点,因为它选择中值作为替代值,而不受异常值的影响。
-
中值滤波去除脉冲噪声或孤立的离群点,均值滤波能够平滑信号或图像。
-
相比之下中值滤波运行速度更快
2.7 投影滤波
原理
将点投影到一个参数化模型上,这个参数化模型可以是平面、圆球、圆柱、锥形等进行投影滤波。
投影模型
核心代码
//本例使用axtby+ez+d=O的平面模型创建一个系数为a=b=d=0,c=1的平面,也就是X-Y平面。z轴相关的点全部投影在X-Y面上
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(4) ;
coefficients->values[0] = coefficients->values[1] = O;
coefficients->values[2] =1.0;
coefficients->values[3] =0;
2.8 高斯滤波
原理
用于平滑图像并减少图像中的噪声。基于高斯函数的数学原理,通过在图像上应用高斯核来实现平滑效果。
步骤
1)确定高斯核的大小和标准差:高斯核的大小是指核的尺寸,通常是一个奇数,例如3x3、5x5、7x7等。标准差决定了高斯函数的形状,控制了滤波的平滑程度。标准差越大,平滑效果越明显。
2)生成高斯核:根据确定的高斯核大小和标准差,生成一个二维的高斯权值矩阵。高斯权值矩阵中的每个元素表示了相应位置上的权重值,这些权重值是根据高斯函数计算得出的。
3)对图像进行卷积:将生成的高斯核应用于原始图像。对于图像中的每个像素,将高斯核与其周围的像素进行卷积操作。卷积操作即将高斯核的每个元素与对应位置的像素值相乘,并将结果进行求和。
4)更新像素值:将卷积操作得到的结果作为滤波后的像素值,用于更新原始图像中对应位置的像素值。这样就完成了一次高斯滤波操作。
5)对整个图像重复滤波操作:重复步骤3和步骤4,对整个图像进行滤波操作,直到所有像素都被更新为滤波后的值。
3 卷积原理
卷积操作中,高斯核与图像中的每个像素以及其周围的邻域像素进行加权求和。卷积的结果是通过将每个像素的值乘以对应位置的高斯核权重,并将所有结果相加得到的。假定中心点的坐标是(0,0),那么取距离它最近的8个点坐标,为了计算,需要设定σ的值。假定σ=1.5,则模糊半径为1的高斯模板如下:
这个时候我们我们还要确保这九个点加起来为1(高斯模板的特性),这9个点的权重总和等于0.4787147,因此上面9个值还要分别除以0.4787147,得到最终的高斯模板。假设现有9个像素点,灰度值(0-255)的高斯滤波计算如下:通常创建KD树,可以用于加速搜索滤波器的卷积操作。
KD-Tree
依次搜寻每个点云数据周围的k个邻域点,并计算出采样点到其k个邻域点的平均欧式距离。原始点云数据
经过KD-Tree 搜索后的数据集为:
定义di为已经得到的点pi到其k个邻域点的平均距离,σ为di的标准差。
-
σ值越大,权值分布越平缓。因此邻域各点值对输出值的影响越大,最终结果造成图像越模糊;
-
核大小固定,σ值越小,权值分布越突起。因此邻域各点值对输出值的影响越小,图像变化越小。假如中心点权值为1,其他点权值为0,最终结果是图像没有任何变化;
-
σ固定时,核越大图像越模糊;
-
σ固定时,核越小图像变化越小。
5 核心代码
//—————基于高斯核函数的卷积滤波实现-—---------
pcl::filters::CaussianKernel<pcl::PointXYZ, pcl::PointXYZ> kernel;//滤波器类 输入+输出
kernel.setSigma(4);//高斯函数的标准方差,决定函数的宽度
kernel.setThresho1dRelativeToSigma(4)://设置相对Sigma参数的距离阈值
kernel.setThreshold(0.05);//设置距离阈值,若点间距高大于阈值则不予考虑
court <<"Kernel made”<< end1;
//——————-创建k维树——————
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search:KdTree<pcl::PointXYZ>);
tree->setInputCloud (cloud);
court <<KdTree made<<end1:
//-———-—-设置三维卷积相关参数-——————————————
pc1:.filters::Convolution3D<pcl::PointXYZ, pcl::PointXYZ, pcl:filters::GaussianKernel<pcl::PointXYZ, pcl:PointXYZ>> convolution;
convolution.setKernel (kernel);//设置卷积核
convolution.setInputCloud (cloud);
convolution.setNumberOfThreads(8);//卷积操作的线程数量为8
convolution.setSearchMethod(tree);//搜索方法为tree
convolution.setRadiusSearch(0.01);//积操作的半径搜索参数为0.01
cout << "Convolution Start" << end1;
3 深度学习的去噪算法
略
参考来源:汇总!三维点云去噪算法,涉及深度学习等