PCL专栏目录及须知-CSDN博客
1.原理
统计滤波即:对点云中每个点进行邻域搜索,判断邻域搜索出的这块点云是否符合高斯分布。根据给定的参数,如均值和方差等,剔除在高斯期望之外的点。
(1)对点云建KD树。
(2)点云中每个点进行邻域搜索,获取邻域搜索出的点云块。
(3)根据给定的阈值(PCL统计滤波器阈值讲解在下文4.关键函数中),判断每个点是否符合高斯期望,剔除期望值之外的点;得到结果点云。
2.使用场景
去噪:当使用半径滤波器等效果不大好的时候使用统计滤波器。
实际工作中,去噪优先级:
半径滤波 > 统计滤波 > 法线空间下采样滤波 > 中值滤波 ≈ 高斯滤波
3.注意事项
高斯滤波用于平滑点云并去噪。
统计滤波只用于去噪。
注意二者区别和使用场景。
4.关键函数
(1)设置K邻域搜索点的个数;即每次选取点云点附近n个点作为邻域点。
setMeanK()
(2)设置高斯期望的计算阈值;
该值为标准差的倍数,如传入参数值为x,那么阈值即为 x*标准差。
函数内部比较逻辑:平均值 + 倍数*标准差 > 平均邻域距离,离群点;
平均值 + 倍数*标准差 < 平均邻域距离,离群点;
setStddevMulThresh()
5.代码
#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>
#include <boost/thread/thread.hpp>
int main()
{
/****************统计滤波********************/
// 原始点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::io::loadPCDFile("D:/code/csdn/data/bunny.pcd", *cloud); // 加载原始点云数据
// 结果点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGB>);
// 统计滤波器
pcl::StatisticalOutlierRemoval<pcl::PointXYZRGB> filters; // 统计滤波器
filters.setInputCloud(cloud);
filters.setMeanK(6); // K邻域搜索的个数
filters.setStddevMulThresh(1.0); // 判断是否是离群点的阈值,大于该阈值,即为离群点(具体见4.关键函数)
filters.filter(*cloud_filtered);
/****************展示********************/
boost::shared_ptr<pcl::visualization::PCLVisualizer> view_raw(new pcl::visualization::PCLVisualizer("raw"));
view_raw->addPointCloud<pcl::PointXYZRGB>(cloud, "raw cloud");
view_raw->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "raw cloud");
boost::shared_ptr<pcl::visualization::PCLVisualizer> view_filtered(new pcl::visualization::PCLVisualizer("filter"));
view_filtered->addPointCloud<pcl::PointXYZRGB>(cloud_filtered, "filtered cloud");
view_filtered->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "filtered cloud");
while (!view_raw->wasStopped())
{
view_raw->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
while (!view_filtered->wasStopped())
{
view_filtered->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}