目录
点云滤波简介
什么是点云滤波?
为什么要点云滤波?
常用滤波器
直通滤波器
体素滤波器(下采样)
均匀采样滤波器(下采样)
统计滤波器(去噪)
条件滤波
半径滤波(去噪)
投影滤波
模型滤波
高斯滤波(去噪、平滑)
双边滤波(平滑)
总结
点云滤波作为常见的点云处理算法,一般是点云处理的第一步,对后续处理有很重要作用。滤波
有很多方面也有很多种功能,比如去除噪声点、离群点、点云平滑以及空洞、数据压缩等
原始点云数据往往包含大量散列点、孤立点,在获取点云数据时 ,由于设备精度,操作者经验环
境因素带来的影响,以及电磁波的衍射性,被测物体表面性质变化和数据拼接配准操作过程的影
响,点云数据中讲不可避免的出现一些噪声,而且采样的分辨率也不同。
在点云处理流程中滤波处理作为预处理的第一步,对后续的影响比较大,只有在滤波预处理中将 噪声点,离群点,孔洞,数据压缩等按照后续处理定制,才能够更好的进行配准,特征提取,曲 面重建,可视化等后续应用处理。其类似于信号处理中的滤波。
PCL中总结了几种需要进行点云滤波处理的情况,这几种情况分别如下:
对应的方法如下:
直通滤波器就是根据点云的属性在点的属性上设置范围,对点进行滤波,保留范围内的或保留范围外的。
#include
// 原点云获取后进行滤波
pcl::PassThrough pass;// 创建滤波器对象
pass.setInputCloud (cloud);//设置输入点云
pass.setFilterFieldName ("z");//滤波字段名被设置为Z轴方向
pass.setFilterLimits (0.0, 1.0);//可接受的范围为(0.0,1.0)
//pass.setFilterLimitsNegative (true);//设置保留范围内 还是 过滤掉范围内
pass.filter (*cloud_filtered); //执行滤波,保存过滤结果在cloud_filter
体素滤波器可以达到向下采样同时不破坏点云本身几何结构的功能,但是会移动点的位置。 此外体素滤波器可以去除一定程度的噪音点及离群点。主要功能是用来进行降采样。
它的原理是根据输入的点云,首先计算一个能够刚好包裹住该点云的立方体,然后根据设定的分辨率,将该大立方体分割成不同的小立方体。对于每一个小立方体内的点,计算他们的质心,并用该质心的坐标来近似该立方体内的若干点。
ApproximateVoxelGrid的不同在于这种方法是利用每一个小立方体的中心来近似该立方体内的若干点。相比于 VoxelGrid,计算速度稍快,但也损失了原始点云局部形态的精细度
#include
// VoxelGrid
pcl::VoxelGrid sor;
sor.setInputCloud (cloud);
sor.setLeafSize (0.01f, 0.01f, 0.01f);
sor.filter (*cloud_filtered);
// Approximate 体素格滤波器
pcl::ApproximateVoxelGrid approximate_voxel_filter;
approximate_voxel_filter.setLeafSize (0.2, 0.2, 0.2);
approximate_voxel_filter.setInputCloud (input_cloud);
approximate_voxel_filter.filter (*filtered_cloud)
均匀采样滤波基本上等同于体素滤波器,但是其不改变点的位置。下采样后,其点云分布基本均匀,但是其点云的准确度要好于体素滤波,因为没有移动点的位置。
均匀采样算法:
均匀采样通过构建指定半径的球体对点云进行下采样滤波,将每一个球内距离球体中心最近的点作为下采样之后的点输出。
体素滤波是建立立方体,均匀采样是建立一个球。
#include
// Uniform sampling object.
pcl::UniformSampling filter;
filter.setInputCloud(cloud);
filter.setRadiusSearch(0.01f);
// We need an additional object to store the indices of surviving points.
pcl::PointCloud keypointIndices;
filter.compute(keypointIndices);
统计滤波器主要用于去除明显离群点。 离群点特征在空间中分布稀疏。定义某处点云小于某个密度,既点云无效。计算每个点到其最近的k个点平均距离。则点云中所有点的距离应构成高斯分布。根据给定均值与方差,可剔除方差之外的点。
#include
pcl::StatisticalOutlierRemoval sor;
sor.setInputCloud (cloud);
sor.setMeanK (50); //设置考虑查询点临近点数
sor.setStddevMulThresh (1.0);//设置判断是否为离群点的阀值
sor.filter (*cloud_filtered);
// 然后,使用同样的参数再次调用该滤波器,但是利用函数setNegative设置使输出取外点,以获取离群点数据(也就是原本滤除掉的点)。
sor.setNegative (true);
sor.filter (*cloud_filtered);
条件滤波器通过设定滤波条件进行滤波,删除不符合用户指定的一个或者多个条件。直通滤波器是一种较简单的条件滤波器。
#include
pcl::ConditionAnd::Ptr range_cond (new pcl::ConditionAnd()); //创建条件定义对象
//添加在Z字段上大于0的比较算子
range_cond->addComparison (pcl::FieldComparison::ConstPtr (new pcl::FieldComparison ("z", pcl::ComparisonOps::GT, 0.0)));
//添加在Z字段上小于0.8的比较算子
range_cond->addComparison (pcl::FieldComparison::ConstPtr (new pcl::FieldComparison ("z", pcl::ComparisonOps::LT, 0.8)));
// 创建滤波器并用条件定义对象初始化
pcl::ConditionalRemoval condrem;
condrem.setCondition (range_cond);
condrem.setInputCloud (cloud);
condrem.setKeepOrganized(true); //设置保持点云的结构
condrem.filter (*cloud_filtered); // 执行滤波
半径滤波器以某点为中心画一个圆计算落在该圆中点的数量,当数量大于给定值时,则保留该 点,数量小于给定值则剔除该点。
主要还是用于去除离群点,在一定程度上可以用来筛选边缘点。
#include
pcl::RadiusOutlierRemoval outrem;
outrem.setInputCloud(cloud);
outrem.setRadiusSearch(0.8);//设置半径为0.8的范围内找临近点
outrem.setMinNeighborsInRadius (2);//设置查询点的邻域点集数小于2的删除
outrem.filter (*cloud_filtered); //
将点投影到一个参数化模型上,这个参数化模型可以是平面、圆球、圆柱、锥形等进行投影滤波。 把三维点云投影到二维图像上,然后用图像处理的方法进行处理。
// 填充ModelCoefficients的值,使用ax+by+cz+d=0平面模型,其中 a=b=d=0,c=1 也就是X——Y平面
//定义模型系数对象,并填充对应的数据
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(4);
coefficients->values[0] = coefficients->values[1] = 0;
coefficients->values[2] = 1.0;
coefficients->values[3] = 0;
// 创建ProjectInliers对象,使用ModelCoefficients作为投影对象的模型参数
pcl::ProjectInliers proj; //创建投影滤波对象
proj.setModelType(pcl::SACMODEL_PLANE); //设置对象对应的投影模型
proj.setInputCloud(cloud);//设置输入点云
proj.setModelCoefficients(coefficients);//设置模型对应的系数
proj.filter(*cloud_projected);//投影结果存储
根据点到模型的距离,设置距离阈值过滤非模型点, 基于模型的点分割操作,将模型外的点从点云中剔除。
//x^2 + y^2 + z^2 = 1
pcl::ModelCoefficients sphere_coeff;
sphere_coeff.values.resize (4);
sphere_coeff.values[0] = 0;
sphere_coeff.values[1] = 0;
sphere_coeff.values[2] = 0;
sphere_coeff.values[3] = 1;
pcl::ModelOutlierRemoval sphere_filter;
sphere_filter.setModelCoefficients (sphere_coeff);
sphere_filter.setThreshold (0.05);
sphere_filter.setModelType (pcl::SACMODEL_SPHERE);
sphere_filter.setInputCloud (cloud);
sphere_filter.filter (*cloud_sphere_filtered);
GaussianKernel是基于高斯核的卷积滤波实现,高斯过滤器相当于一个具有平滑性能的低通滤波器, 通过该类处理后的点云,相对比较平滑。
pcl::filters::Convolution convolution;
Eigen::ArrayXf gaussian_kernel(5);
gaussian_kernel << 1.f/16, 1.f/4, 3.f/8, 1.f/4, 1.f/16;
convolution.setBordersPolicy(pcl::filters::Convolution::BORDERS_POLICY_IGNORE);
convolution.setDistanceThreshold (static_cast (0.1));
convolution.setInputCloud (inputCloud);
convolution.setKernel (gaussian_kernel);
convolution.convolve(*cloud);
双边滤波是一种非线性滤波器,它可以达到保持边缘、降噪平滑的效果。一定程度上拟补了高斯滤波的缺点。 双边滤波对高斯噪声效果比较好。
pcl::FastBilateralFilter fbf;