关于点云滤波去噪的方法

  • 为什么进行点云滤波处理:
(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

你可能感兴趣的:(图像处理)