PCL入门系列 —— StatisticalOutlierRemoval 点云统计滤波

PCL入门系列 —— StatisticalOutlierRemoval 点云统计滤波


前言

随着工业自动化、智能化的不断推进,机器视觉(2D/3D)在工业领域的应用和重要程度也同步激增(识别、定位、抓取、测量,缺陷检测等),而针对不同作业场景进行解决方案设计时,通常会借助PCL、OpenCV、Eigen等简单方便的开源算法库进行方案的快速验证和迭代以满足作业场景下的目标需求。

为了让对工业机器视觉方向感兴趣的同学能够少走一些弯路,故推出了此一系列简易入门教程示例,让初次使用者能够最简单直观地感受到当前所用算法模块的执行效果。

后续会逐步扩增与工业机器视觉相关的一些其它内容,如:

项目案例剖析场景数据分析基础算法模块相机评测 等;

如有兴趣可加入群聊(若入群二维码被屏蔽,则可以通过Q群(1032861997)或评论、私信博主“群聊”,邀请入群),与同道同学及圈内同行一起交流讨论。

在这里插入图片描述


程序说明

展示 StatisticalOutlierRemoval 统计滤波效果;

输出结果

在这里插入图片描述

代码示例

/*
 * @File: statistical_outlier_removal.cpp
 * @Brief: pcl course
 * @Description: 展示StatisticalOutlierRemoval统计滤波效果
 * @Version: 0.0.1
 * @Author: MuYv
 */
#include <iostream>
#include <string>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/visualization/pcl_visualizer.h>



int main(int argc, char** argv){
    if(argc != 2){
        std::cout<<"Usage: exec cloud_file_path"<<std::endl;
        return -1;
    }
    const std::string kCloudFilePath = argv[1]; // ../clouds/table_scene.pcd

    // 定义变量
    pcl::PointCloud<pcl::PointXYZ>::Ptr \
                    cloud_src(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::PointCloud<pcl::PointXYZ>::Ptr \
                    cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>());

    // 成功返回0,失败返回-1
    if(-1 == pcl::io::loadPCDFile(kCloudFilePath,*cloud_src)){
        std::cout<<"load pcd file failed. please check it."<<std::endl;
        return -2;
    }

    // 创建统计滤波模板类对象
    pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
    // 设置输入点云
    sor.setInputCloud(cloud_src);
    // 设置统计分析时的邻域点数
	sor.setMeanK(50); //K近邻搜索点个数
    // 设置标准差系数
	sor.setStddevMulThresh(1.0); //标准差倍数
    // 默认是剔除不满足统计分析的点(噪声点),如需反向操作,则设为true
	sor.setNegative(false); //此处保留未滤波点(内点)
    // 执行滤波,并带出结果数据
	sor.filter(*cloud_filtered);  //保存滤波结果到cloud_filtered

    // 创建可视化对象
    pcl::visualization::PCLVisualizer viewer("viewer");

    // 将当前窗口,拆分成横向的2个可视化窗口,以viewport区分(v1/v2)
    int v1; 
    int v2;
    //窗口参数分别对应 x_min, y_min, x_max, y_max, viewport
    viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);  
    viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);

    // 添加2d文字标签
    viewer.addText("v1", 10,10, 20, 1,0,0, "viewport_v1", v1);
    viewer.addText("v2", 10,10, 20, 0,1,0, "viewport_v2", v2);

    // 添加坐标系
    viewer.addCoordinateSystem(0.5);    // 单位:m

    // 设置可视化窗口背景色
    viewer.setBackgroundColor(0.2,0.2,0.2);     // r,g,b  0~1之间

    // 向v1窗口中添加点云
    viewer.addPointCloud(cloud_src,"cloud_src",v1);
    // // 根据点云id,设置点云可视化属性,此处将可视化窗口中的点大小调整为2级
    // viewer.setPointCloudRenderingProperties \
    //         (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud_src");

    // 向v2窗口中添加点云
    viewer.addPointCloud(cloud_filtered,"cloud_filtered",v2);
    // // 根据点云id,设置点云可视化属性,此处将可视化窗口中的点大小调整为2级
    // viewer.setPointCloudRenderingProperties \ 
    //         (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud_filtered");

    // 关闭窗口则退出
    while(!viewer.wasStopped()){
        viewer.spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }

    return 0;
}

总结

基于当前点与邻域点数据的距离统计信息进行离群点判定并进行剔除,当噪声数据的空间点密度与有效区域的点密度差距较为明显时会有不错的滤波效果;


注:部分测试所用点云数据来源于网络,如有侵权,请联系博主删除,谢谢。

<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、付费专栏及课程。

余额充值