PCL统计滤波(statistical_outlier_removal)

PCL专栏目录及须知-优快云博客

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

6.结果展示

<think>嗯,用户问的是PCL中的StatisticalOutlierRemoval滤波器的原理。首先,我需要确认自己对这个滤波器的理解是否正确。记得StatisticalOutlierRemoval主要用于去除离群点,也就是那些不符合周围点云统计特性的点。 用户可能是在处理点云数据时遇到了噪声问题,比如激光雷达数据中的漂浮物或者测量误差。他们可能已经尝试过其他滤波方法,比如体素网格下采样或者半径滤波,但发现有些离群点仍然存在,所以想用更高级的方法来处理。 接下来,我需要回忆这个算法的具体步骤。StatisticalOutlierRemoval是基于统计学的,通常计算每个点到其邻居的平均距离,假设这些距离符合高斯分布,然后根据均值和标准差设定阈值,去除超出阈值的点。这个过程需要设置两个主要参数:K近邻的数目和标准差倍数。比如,设置均值的标准差倍数,超过这个倍数的点被视为离群点。 可能用户在使用时遇到了参数设置的问题,比如如何选择合适的K值或者标准差倍数。这时候需要解释参数的影响,比如K值过小可能导致噪声误判,过大则可能忽略真实离群点。标准差倍数通常设为1或2,根据具体场景调整。 另外,用户可能想知道这个滤波器与其他滤波方法的区别,比如和RadiusOutlierRemoval相比,StatisticalOutlierRemoval更依赖统计特性,适合处理密度变化较大的点云,而RadiusOutlierRemoval则是基于固定半径内的点数,适合均匀分布的数据。 在实现细节方面,用户可能需要了解是否需要安装额外的模块,或者头文件。不过之前的问题已经问过头文件,所以这里可能更关注原理和参数调整。另外,可能需要注意这个滤波器处理后的点云索引变化,或者是否需要预处理步骤,比如先进行下采样提高计算效率。 用户还可能关心算法的计算复杂度,因为对于大规模点云,StatisticalOutlierRemoval可能会比较耗时,特别是当K值较大时。这时候可以建议先使用体素滤波减少点数,再应用StatisticalOutlierRemoval。 最后,需要确认是否有常见的错误或陷阱,比如未正确设置输入点云,或者参数不合理导致过滤过度或不足。这时候提供示例代码和参数设置建议会很有帮助,帮助用户快速上手。</think>在PCL中,`StatisticalOutlierRemoval`(统计离群点滤波)的原理是通过统计分析点云密度分布,剔除不符合统计规律的离群点。以下是其核心原理分步说明: --- ### 🌟 **核心原理** 1. **邻域密度统计** 对每个点计算其到 **$k$ 最近邻点** 的平均距离 公式: $$\bar{d}_i = \frac{1}{k} \sum_{j=1}^k ||p_i - p_j||$$ ($p_i$为当前点,$p_j$为邻居点) 2. **全局分布建模** 假设所有点的平均距离服从 **高斯分布** 计算全局均值$\mu$和标准差$\sigma$: $$\mu = \frac{1}{N} \sum_{i=1}^N \bar{d}_i, \quad \sigma = \sqrt{\frac{1}{N} \sum_{i=1}^N (\bar{d}_i - \mu)^2}$$ 3. **阈值过滤** 设定标准差倍数阈值$\alpha$(通常$\alpha=1$或$2$) 保留满足条件的点: $$\bar{d}_i \in [\mu - \alpha\sigma, \mu + \alpha\sigma]$$ --- ### 🛠️ **参数配置** ```cpp pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setMeanK(50); // 设置邻域点数k(建议值:20-100) sor.setStddevMulThresh(1.0); // 设置标准差倍数α(典型值:1.0-2.0) sor.setInputCloud(cloud); sor.filter(*filtered_cloud); ``` --- ### 🎯 **适用场景** | 场景类型 | 效果说明 | |-----------------------|-------------------------| | 激光雷达噪声点 | 去除漂浮物/鬼影 | | 深度相机异常值 | 消除传感器噪点 | | 复杂环境点云 | 保留主体结构,去除离散点 | --- ### ⚖️ **优缺点对比** | 优点 | 缺点 | |-----------------------|-------------------------| | 自适应密度变化 | 计算量较大(需KNN搜索) | | 参数物理意义明确 | 对k值选择敏感 | | 保留锐利边缘 | 不适用于均匀分布噪声 | --- ### 🔍 **算法扩展** - **加速优化**:结合 **KD-Tree** 加速邻域搜索(PCL内部自动使用) - **改进变种**:`RadiusOutlierRemoval`(固定半径统计,适合均匀噪声) - **多阶段滤波**:建议先使用`VoxelGrid`下采样,再执行统计滤波 --- ### 📊 **实验效果可视化** ``` 原始点云 滤波后点云 ●●●●●● ●●●●● ●● ●● ●● ●● ●●●● ●●●● (含离散噪点) (结构更清晰) ``` --- ### ⚠️ **常见错误** ```cpp // 错误1:未设置足够大的k值导致过度滤波 sor.setMeanK(5); // k过小会导致正常点被误删 // 错误2:未正确处理NaN值(需先调用removeNaNFromPointCloud) sor.setInputCloud(cloud_with_nan); // 将引发计算异常 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值