(1) 点云数据密度不规则需要平滑
(2) 因为遮挡等问题造成离群点需要去除
(3) 大量数据需要下采样
(4) 噪声数据需要去除
双边滤波、高斯滤波、分箱去噪、KD-Tree、直通滤波、随机采样一致性滤波等
1.双边滤波:将距离和空间结构结合去噪,效果较好。只适用于有序点云
2.高斯滤波(标准差去噪):适用于呈正态分布的数据。考虑到离群点的特征,则可以定义某处点云小于某个密度,既点云无效。计算每个点到其最近的k个点平均距离。则点云中所有点的距离应构成高斯分布。给定均值与方差,可剔除3∑之外的点。
3.分箱去噪:适用于呈偏态分布的数据。
4.dbscan:基于聚类原理去噪,复杂度较高。
5.KD-Tree(孤立森林):复杂度高。构建KD树,随机取点求平均距离d,删掉所有大于2d的点。适用于无序点云去噪。
6.条件滤波:条件滤波器通过设定滤波条件进行滤波,有点分段函数的味道,当点云在一定范围则留下,不在则舍弃。
7.直通滤波
8.随机采样一致性滤波
9.体素滤波:
体素的概念类似于像素,使用AABB包围盒将点云数据体素化,一般体素越密集的地方信息越多,噪音点及离群点可通过体素网格去除。另一方面如果使用高分辨率相机等设备对点云进行采集,往往点云会较为密集。过多的点云数量会对后续分割工作带来困难。体素滤波器可以达到向下采样同时不破坏点云本身几何结构的功能。
10.半径滤波:
半径滤波器与统计滤波器相比更加简单粗暴。以某点为中心画一个圆计算落在该圆中点的数量,当数量大于给定值时,则保留该点,数量小于给定值则剔除该点。此算法运行速度快,依序迭代留下的点一定是最密集的,但是圆的半径和圆内点的数目都需要人工指定。
原理以及核心代码:
直通滤波器:对于在空间分布有一定空间特征的点云数据,比如使用线结构光扫描的方式采集点云,沿z向分布较广,但x,y向的分布处于有限范围内。此时可使用直通滤波器,确定点云在x或y方向上的范围,可较快剪除离群点,达到第一步粗处理的目的。
// Create the filtering object
pcl::PassThrough pass;
pass.setInputCloud (cloud);
pass.setFilterFieldName ("z");
pass.setFilterLimits (0.0, 1.0);
//pass.setFilterLimitsNegative (true);
pass.filter (*cloud_filtered);
体素滤波器:
// Create the filtering object
pcl::VoxelGrid sor;
sor.setInputCloud (cloud);
sor.setLeafSize (0.01f, 0.01f, 0.01f);
sor.filter (*cloud_filtered);
统计滤波器:
// Create the filtering object
pcl::StatisticalOutlierRemoval sor;
sor.setInputCloud (cloud);
sor.setMeanK (50);
sor.setStddevMulThresh (1.0);
sor.filter (*cloud_filtered);
半径滤波器:
// build the filter
pcl::RadiusOutlierRemoval outrem;
outrem.setInputCloud(cloud);
outrem.setRadiusSearch(0.8);
outrem.setMinNeighborsInRadius (2);
// apply filter
outrem.filter (*cloud_filtered);
一般来说,滤波对应的方案有如下几种:
(1)按照给定的规则限制过滤去除点
(2)通过常用滤波算法修改点的部分属性
(3)对数据进行下采样
查阅的相关资料:
PCL点云滤波去噪:
https://blog.csdn.net/qq_30815237/article/details/86294496
https://mp.weixin.qq.com/s/9pxff6LwcecDHsx4kI34sw
PCL中关于点云滤波的所有函数:
http://docs.pointclouds.org/trunk/group__filters.html
具体实现:
#include
#include
#include //直通滤波器头文件
#include //体素滤波器头文件
#include //统计滤波器头文件
#include //条件滤波器头文件
#include //半径滤波器头文件
int main(int argc, char** argv)
{
/*创建点云数据集。*/
pcl::PointCloud::Ptr cloud(new pcl::PointCloud);
cloud->width = 500;
cloud->height = 1;
cloud->points.resize(cloud->width*cloud->height);
std::cout << "创建原始点云数据" << std::endl;
for (size_t i = 0; i < cloud->points.size(); ++i)
{
cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
}
for (size_t i = 0; i < cloud->points.size(); i++)
{
std::cerr << " " << cloud->points[i].x << " "
<< cloud->points[i].y << " "
<< cloud->points[i].z << std::endl;
}
std::cout << "原始点云数据点数:" << cloud->points.size() << std::endl << std::endl;
/*方法一:直通滤波器对点云进行处理。*/
pcl::PointCloud::Ptr cloud_after_PassThrough(new pcl::PointCloud);
pcl::PassThrough passthrough;
passthrough.setInputCloud(cloud);//输入点云
passthrough.setFilterFieldName("z");//对z轴进行操作
passthrough.setFilterLimits(0.0, 400.0);//设置直通滤波器操作范围
//passthrough.setFilterLimitsNegative(true);//true表示保留范围内,false表示保留范围外
passthrough.filter(*cloud_after_PassThrough);//执行滤波,过滤结果保存在 cloud_after_PassThrough
std::cout << "直通滤波后点云数据点数:" << cloud_after_PassThrough->points.size() << std::endl;
/*方法二:体素滤波器实现下采样*/
pcl::PointCloud::Ptr cloud_after_voxelgrid(new pcl::PointCloud);//
pcl::VoxelGrid voxelgrid;
voxelgrid.setInputCloud(cloud);//输入点云数据
voxelgrid.setLeafSize(10.0f, 10.0f, 10.0f);//AABB长宽高
voxelgrid.filter(*cloud_after_voxelgrid);
std::cout << "体素化网格方法后点云数据点数:" << cloud_after_voxelgrid->points.size() << std::endl;
/*方法三:统计滤波器滤波*/
pcl::PointCloud::Ptr cloud_after_StatisticalRemoval(new pcl::PointCloud);//
pcl::StatisticalOutlierRemoval Statistical;
Statistical.setInputCloud(cloud);
Statistical.setMeanK(20);//取平均值的临近点数
Statistical.setStddevMulThresh(5);//临近点数数目少于多少时会被舍弃
Statistical.filter(*cloud_after_StatisticalRemoval);
std::cout << "统计分析滤波后点云数据点数:" << cloud_after_StatisticalRemoval->points.size() << std::endl;
/*方法四:条件滤波器*/
pcl::PointCloud::Ptr cloud_after_Condition(new pcl::PointCloud);
pcl::ConditionAnd::Ptr range_condition(new pcl::ConditionAnd());
range_condition->addComparison(pcl::FieldComparison::ConstPtr(new
pcl::FieldComparison("z", pcl::ComparisonOps::GT, 0.0))); //GT表示大于等于
range_condition->addComparison(pcl::FieldComparison::ConstPtr(new
pcl::FieldComparison("z", pcl::ComparisonOps::LT, 0.8))); //LT表示小于等于
pcl::ConditionalRemoval condition;
condition.setCondition(range_condition);
condition.setInputCloud(cloud); //输入点云
condition.setKeepOrganized(true);
condition.filter(*cloud_after_Condition);
std::cout << "条件滤波后点云数据点数:" << cloud_after_Condition->points.size() << std::endl;
/*方法五:半径滤波器*/
pcl::PointCloud::Ptr cloud_after_Radius(new pcl::PointCloud);
pcl::RadiusOutlierRemoval radiusoutlier; //创建滤波器
radiusoutlier.setInputCloud(cloud); //设置输入点云
radiusoutlier.setRadiusSearch(100); //设置半径为100的范围内找临近点
radiusoutlier.setMinNeighborsInRadius(2); //设置查询点的邻域点集数小于2的删除
radiusoutlier.filter(*cloud_after_Radius);
std::cout << "半径滤波后点云数据点数:" << cloud_after_Radius->points.size() << std::endl;
int a;
std::cin >> a;
return (0);
}
原博文:
https://blog.csdn.net/yanghan742915081/article/details/85092643