由于采集的点云数据存在噪声,这些噪声不利于对点云后续特征的提取,因此需要通过相应的滤波算法去除噪声数据。常用的点云滤波算法有:体素网格滤波、直通滤波、半径滤波、统计滤波器,双边滤波器,卷积滤波,高斯滤波,条件滤波等。
(1) 体素网格滤波
体素网格滤波用于对稠密点云进行降采样,其首先把 3D 空间划分成多个很小的体素, 然后将每个体素网格的中心点作为该网格内的唯一点,体素网格滤波可以在减少数据量的同时很好的保留原始点云的几何结构。 PCL 点云库中通过 VoxelGrid 函数进行体素网格滤波,使用 setLeafSize 函数来设置网格的大小, leafSize 越大表示每个网格的体积越大,保留的点云数量越少。
#include
#include
void DownSample_Filter(pcl::PointCloud::Ptr cloud_in,
pcl::PointCloud::Ptr &cloud_downsize,
double downsize){
pcl::VoxelGrid downsample_filter;
downsample_filter.setLeafSize(downsize, downsize, downsize);
downsample_filter.setDownsampleAllData(true); //对全字段进行下采样;
downsample_filter.setInputCloud(cloud_in);
downsample_filter.filter(*cloud_downsize);
}
(2)直通滤波
直通滤波通过限定点云三轴坐标的范围快速剔除掉不在需求范围内的离群点。 PCL 点云库中直通滤波函数为 PassThrough, 使用函数 setFilterFieldName设置需要剔除点云的字段(x、 y、 z、intensity), setFilterLimits 设置保留点云数据相应坐标轴的范围。
#include
//直通滤波器,在Z轴方向上剪除多余的点
void PassThrough_filter(pcl::PointCloud::Ptr cloud,
pcl::PointCloud::Ptr &cloud_medium,
double min, double max)
{
pcl::PassThrough pass; //创建滤波器对象
pass.setInputCloud (cloud); //设置待滤波的点云
pass.setFilterFieldName ("x"); //设置在x轴方向上进行滤波
pass.setNegative (false); //false:保留当前范围内数据;true:取反;
pass.setFilterLimits (min, max); //设置滤波范围为min~max,在范围之外的点会被剪除
pass.filter (*cloud_medium); //存储
}
(3)半径滤波
半滤波通过计算每个点在设置半径范围内是否有足够的点云数量来进行滤波处理,可以快速移除稀疏离群点。 PCL 点云库中的半径滤波函数为RadiusOutlierRemoval,通过函数 setRadius 设置进行统计计算的半径,setMinNeighborsInRadius 来判断该点是否为稀疏离群点的阈值。
#include
#include
void Radius_outlier_filter(pcl::PointCloud::Ptr cloud_input,
pcl::PointCloud::Ptr &cloud_filter,
float radius, int num)
{
pcl::RadiusOutlierRemoval outrem; // 创建滤波器
outrem.setInputCloud(cloud_input); //设置输入点云
/****搜索半径设为radius,在此半径内点必须要有至少num个邻居时,此点才会被保留***/
outrem.setRadiusSearch(radius); //设置在radius半径的范围内找邻近点
outrem.setMinNeighborsInRadius(num); //设置查询点的邻近点集数小于num的删除
outrem.filter(*cloud_filter); //执行条件滤波,存储结果到cloud_filter
}
(4)统计滤波器
用于去除明显离群点,即噪声数据。噪声信息属于无用信息,信息量较小。所以离群点表达的信息可以忽略不计。考虑到离群点的特征,则可以定义某处点云小于某个密度,既点云无效。计算每个点到其最近的k个点平均距离。则点云中所有点的距离应构成高斯分布。
//统计滤波器,删除离群点
void staticOutlierRemoval(pcl::PointCloud::Ptr cloud_input,
pcl::PointCloud::Ptr &cloud_filtered,
int num, float threshold)
{
pcl::StatisticalOutlierRemoval Static; //创建滤波器对象
Static.setInputCloud(cloud_input); //设置待滤波的点云
Static.setMeanK(num); //设置在进行统计时考虑查询点临近点数
Static.setStddevMulThresh(threshold); //设置判断是否为离群点的阈值
Static.filter(*cloud_filtered); //存储
}
(5)双边滤波
双边滤波是一种非线性滤波器,它可以达到保持边缘、降噪平滑的效果。一定程度上拟补了高斯滤波的缺点。双边滤波对高斯噪声效果比较好。双边滤波从单纯的考虑空间域点的位置的高斯滤波上,又加上一个维度上的权重。在点云处理上,可以叫做为特征域,即当前点的法向量与临近点的法向量。
#include
void Bilateral_Filter(pcl::PointCloud::Ptr cloud_input,
pcl::PointCloud::Ptr &result,
float sigma_s, float sigma_R )
{
pcl::FastBilateralFilter filter;
filter.setInputCloud(cloud_input);
filter.setSigmaS(sigma_s); //0.5 空间邻域/窗口设置双边滤波器使用的高斯标准差
filter.setSigmaR(sigma_R); //0.0004 设置高斯的标准偏差,用于控制由于强度差,而使相邻像素的权重降低的程度
filter.applyFilter(*result);
}
(6)均匀采样滤波
均匀采样滤波基本上等同于体素滤波器,但是其不改变点的位置。下采样后,其点云分布基本均匀,但是其点云的准确度要好于体素滤波,因为没有移动点的位置。
#include
void Uniform_Filter(pcl::PointCloud::Ptr cloud_input,
pcl::PointCloud::Ptr &result,
float radius)
{
pcl::UniformSampling sor2; // 创建均匀采样对象
sor2.setInputCloud(cloud_input); //设置需要过滤的点云
sor2.setRadiusSearch(radius); //设置滤波时创建的体素体积为1cm的立方体,radius=0.01f
sor2.filter(*result); //执行滤波处理,储存输出点云
}
(7)高斯滤波
高斯滤波是一种非线性滤波器,采用加权平均的方式,高斯滤波相当于一个具有平滑性能的低通滤波器。在指定域内的权重是根据欧式距离的高斯分布,通过权重加权平均的方式得到当前点的滤波后的点。
(8)条件滤波
条件滤波器通过设定滤波条件进行滤波,有点分段函数的味道,当点云在一定范围则留下,不在则舍弃。直通滤波器是一种较简单的条件滤波器。条件滤波器更像是一个不带有滤波核的工具。
#include
//创建条件限定的下的滤波器
void conditional_Filter(pcl::PointCloud::Ptr cloud_input,
pcl::PointCloud::Ptr &result,
)
{
pcl::ConditionAnd::Ptr range_cond (new pcl::ConditionAnd ()); //创建条件定义对象
/***为条件定义对象添加比较算子****/
range_cond->addComparison (pcl::FieldComparison::ConstPtr (new pcl::FieldComparison ("z", pcl::ComparisonOps::GT, 0.0))); //添加在Z字段上大于0的比较算子
range_cond->addComparison (pcl::FieldComparison::ConstPtr (new pcl::FieldComparison ("z", pcl::ComparisonOps::LT, 0.8))); //添加在Z字段上小于0.8的比较算子
/*****创建滤波器并用条件定义对象初始化*****/
pcl::ConditionalRemoval condrem;
condrem.setCondition (range_cond);
condrem.setInputCloud (cloud_input); //输入点云
condrem.setKeepOrganized(true); //设置保持点云的结构
condrem.filter (*result); //大于0.0小于0.8这两个条件用于建立滤波器
}
点云显示方法;
#include
pcl::PointCloud::Ptr show_points(new pcl::PointCloud());
static pcl::visualization::CloudViewer viewer("key points");
viewer.showCloud(show_points);
#include
int *rand_rgb(){//随机产生颜色
int *rgb = new int[3];
rgb[0] = rand() % 255;
rgb[1] = rand() % 255;
rgb[2] = rand() % 255;
return rgb;
}
void show_result()
{
static boost::shared_ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
//显示部分;
int *rgb1 = rand_rgb();
pcl::visualization::PointCloudColorHandlerCustomrgb2(filterd,rgb1[0], rgb1[1], rgb1[2]);
delete[]rgb1;
viewer->setBackgroundColor(0, 0, 0); //设置背景颜色;
viewer->addCoordinateSystem(1.0); //设置点云大小;
viewer->addPointCloud(filterd, rgb2, "v1");
}