PCL学习笔记——点云滤波(二)

版权声明:转载请注明出处,谢谢! https://blog.csdn.net/weixin_44420419/article/details/88863050

三. 基于统计分析的StatisticalOutlierRemoval滤波器

该滤波器主要用于移除离群点,那么什么样的点是离群点呢?计算点云中每个点与其所有临近点的平均距离,并假设其结果为一形状由均值和标准差决定的高斯分布,若有某点平均距离在标准范围(由全局距离平均值和方差定义)之外,则定义为离群点,并将其从数据集中去除掉,这也是本滤波器的内在处理逻辑,即对每个点的邻域进行一个统计分析。
激光扫描通常会产生密度不均匀的点云数据,另外,测量中的误差也会产生稀疏的离群点。

代码如下

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>

int
main(int argc, char** argv)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

	pcl::PCDReader reader;   // 定义读取对象
	reader.read<pcl::PointXYZ>("table_scene_lms400.pcd", *cloud);  // 读取点云文件

	std::cerr << "Cloud before filtering: " << std::endl;
	std::cerr << *cloud << std::endl;

	/*创建滤波器,对每个点分析的临近点的个数设置为50 ,并将标准差的倍数设置为1  这意味着如果一
	个点的距离超出了平均距离一个标准差以上,则该点被标记为离群点,并将它移除,存储起来*/
	pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; //创建滤波器对象
	sor.setInputCloud(cloud);                          //设置待滤波的点云
	sor.setMeanK(50);                                  //设置在进行统计时考虑查询点临近点数
	sor.setStddevMulThresh(1.0);                       //设置判断是否为离群点的阀值
	sor.filter(*cloud_filtered);                       //执行滤波处理保存内点到在cloud_filtered

	//打印滤波后的数据
	std::cerr << "Cloud after filtering: " << std::endl;
	std::cerr << *cloud_filtered << std::endl;
	//将过滤后得到的剩余内部点存入磁盘
	pcl::PCDWriter writer;
	writer.write<pcl::PointXYZ>("table_scene_lms400_inliers.pcd", *cloud_filtered, false);
	//使用同样的参数再次调用该滤波器,但是利用函数setNegative设置使输出取外点,以获取离群点,并存储
	sor.setNegative(true);
	sor.filter(*cloud_filtered);
	writer.write<pcl::PointXYZ>("table_scene_lms400_outliers.pcd", *cloud_filtered, false);

	return (0);
}

运行结果如下:
在这里插入图片描述
运行程序后会在同名文件目录下得到两个点云文件,分别存储内点和外点,之后可作可视化处理。

注:可能在运行程序时报错 难受啊
错误 C3861 “pop_t”: 找不到标识符
此时,修改打开的dist.h文件(不可以修改的话用管理员身份打开VS修改),将503行的
“typedef unsigned long long pop_t;”
移到上面几行的“#if GNUC”前面就可以了,具体原理没懂,参见https://github.com/mariusmuja/flann/issues/386

四. 使用ProjectInliers滤波器在参数化模型中投影点云

通过此滤波器将点投影到一个参数化模型上(平面或者球体等)。参数化模型通过一组参数来设定,对于平面来说使用其等式形式 ax + by + cz + d + 0,在PCL中有特意存储常见模型系数的数据结构。

代码如下:

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/ModelCoefficients.h>                //模型系数头文件
#include <pcl/filters/project_inliers.h>          //投影滤波类头文件

int
main(int argc, char** argv)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>);

	//创建点云并打印出来
	cloud->width = 5;
	cloud->height = 1;
	cloud->points.resize(cloud->width * cloud->height);

	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);
	}

	std::cerr << "Cloud before projection: " << std::endl;
	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;

	/* 填充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<pcl::PointXYZ> proj;       //创建投影滤波对象
	proj.setModelType(pcl::SACMODEL_PLANE);        //设置对象对应的投影模型
	proj.setInputCloud(cloud);                     //设置输入点云
	proj.setModelCoefficients(coefficients);       //设置模型对应的系数
	proj.filter(*cloud_projected);                 //投影结果存储

	//打印投影后的云
	std::cerr << "Cloud after projection: " << std::endl;
	for (size_t i = 0; i < cloud_projected->points.size(); ++i)
		std::cerr << "    " << cloud_projected->points[i].x << " "
		<< cloud_projected->points[i].y << " "
		<< cloud_projected->points[i].z << std::endl;

	return (0);
}

运行结果:
在这里插入图片描述
可见,实验结果可以看出投影前的Z轴都不为0 ,都是随机产生的值,投影之后,打印的结果表明,xy的值都没有改变,z都变为0。

注1:可能报错
error C4996: ‘pcl::SAC_SAMPLE_SIZE’: This map is deprecated and is kept only to prevent breaking existing user code. Starting from PCL 1.8.0 model sample size is a protected member of the SampleConsensusModel class
解决方法:https://blog.csdn.net/wokaowokaowokao12345/article/details/51287011

注2:PCL中存储的可投影的几何模型结构
https://blog.csdn.net/fandq1223/article/details/53176311

未完待续。

猜你喜欢

转载自blog.csdn.net/weixin_44420419/article/details/88863050