原理:对每个点找其到其K近邻的的点的距离的平均值d,所有的点的平均值应该呈现高斯分布(正态分布),其形状由均值和标准差决定,平均距离d在标准范围内 (由全局距离平均值<所有的d相加的和>和方差定义)之外的点,可以被定义为离群点并剔除。
代码:
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/visualization/pcl_visualizer.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::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_out(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;//重载了<<运算符.重载为全局的,但是为啥可以访问PointCloud类的成员变量呢?
// 创建滤波器对象
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
sor.setInputCloud (cloud);
sor.setMeanK (100);//寻找每个点的50个最近邻点
sor.setStddevMulThresh (1.0);//一个点的最近邻距离超过全局平均距离的一个标准差以上,就会舍弃
sor.filter (*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);
sor.setNegative (true);//获取刚才的离群点
sor.filter (*cloud_filtered_out);
std::cerr << "Cloud_outside after filtering: " << std::endl;
std::cerr << *cloud_filtered_out << std::endl;
writer.write<pcl::PointXYZ> ("table_scene_lms400_outliers.pcd", *cloud_filtered_out, false);
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer);
viewer->initCameraParameters();
int v1(0);
viewer->createViewPort(0,0,0.33,1,v1);
viewer->setBackgroundColor(0,0,0,v1);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color1(cloud,255,255,255);
viewer->addPointCloud<pcl::PointXYZ>(cloud,single_color1,"cloud",v1);
int v2(0);
viewer->createViewPort(0.33,0,0.66,1,v2);
viewer->setBackgroundColor(128,0,0,v2);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color2(cloud_filtered,0,255,0);
viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered,single_color2,"cloud_filtered",v2);
int v3(0);
viewer->createViewPort(0.66,0,1,1,v3);
viewer->setBackgroundColor(128,128,128,v3);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color3(cloud_filtered_out,0,0,255);
viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered_out,single_color3,"cloud_filtered_out",v3);
viewer->addCoordinateSystem();
viewer->spin();
return (0);
}
结果:依次为原数据、滤波之后的数据、滤掉的数据