【点云处理技术之PCL】滤波器——离群点滤波(statisticalOutlierRemoval、ConditionalRemoval 和RadiusOutlinerRemoval)

1. 离群点滤波器–statisticalOutlierRemoval

通常激光点云往往会伴随着一些噪声的存在,而这会使局部点云特征(如曲面法线或曲率变化)的估计变得复杂,从而导致错误的值,进而可能导致点云配准失败。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>);//读取pcd用
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);//滤波后的结果

    // Fill in the cloud data
    pcl::PCDReader reader;
    reader.read<pcl::PointXYZ>("../../pcd/table_scene_lms400.pcd", *cloud); //读取pcd点云

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

    // Create the filtering object
    //设置滤波器对象
    pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
    sor.setInputCloud(cloud);    //输入点云
    sor.setMeanK(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>("../../pcd/table_scene_lms400_inliers.pcd", *cloud_filtered, false);

    sor.setNegative(true); //获取离群点
    sor.filter(*cloud_filtered);
    writer.write<pcl::PointXYZ>("../../pcd/table_scene_lms400_outliers.pcd", *cloud_filtered, false);

    return (0);
}

输出结果如下,使用离群点删除之后,点云数量有所减少。

Cloud before filtering: 
points[]: 460400
width: 460400
height: 1
is_dense: 1
sensor origin (xyz): [0, 0, 0] / orientation (xyzw): [0, 0, 0, 1]

Cloud after filtering: 
points[]: 451410
width: 451410
height: 1
is_dense: 1
sensor origin (xyz): [0, 0, 0] / orientation (xyzw): [0, 0, 0, 1]

下面来看看可视化的效果,原图效果如下:
在这里插入图片描述
删除离群点之后的效果如下,很明显,点云分布比之前干净了很多。

在这里插入图片描述
被删除的离群点可视化效果如下:
在这里插入图片描述

2. 半径搜索滤波和条件搜索滤波–RadiusOutlinerRemoval和ConditionalRemoval

  • ConditionalRemoval滤波器:可以一次删除满足对输入的点云设定的一个或多个条件指标的所有的数据点

  • RadiusOutlinerRemoval滤波器:它可以删除在输入点云一定范围内没有至少达到足够多近邻的所有数据点.

便于理解RadiusOutlinerRemoval滤波器,如下图所示,假如给定固定的搜索半径d,如果搜索的点云个数为1,那么黄色的点将被删除,如果搜索的点为2,那么黄色和绿色的点将被删除。
在这里插入图片描述

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/radius_outlier_removal.h>
#include <pcl/filters/conditional_removal.h>

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
        exit(0);
    }
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

    // Fill in the cloud data
    cloud->width = 5;
    cloud->height = 1;
    cloud->resize(cloud->width * cloud->height);

    for (auto &point : *cloud)
    {
        point.x = 1024 * rand() / (RAND_MAX + 1.0f);
        point.y = 1024 * rand() / (RAND_MAX + 1.0f);
        point.z = 1024 * rand() / (RAND_MAX + 1.0f);
    }

    //RadiusOutlierRemoval滤波
    if (strcmp(argv[1], "-r") == 0)
    {
        pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
        // build the filter
        outrem.setInputCloud(cloud);//输入点云
        outrem.setRadiusSearch(0.8);//设置滤波搜索半径
        outrem.setMinNeighborsInRadius(2);//设置半径内的至少的点云个数
        outrem.setKeepOrganized(true);
        // apply filter
        outrem.filter(*cloud_filtered);//开始滤波,并获取滤波点云
    }
    //ConditionAnd滤波
    else if (strcmp(argv[1], "-c") == 0)
    {
        // build the condition
        pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond(new pcl::ConditionAnd<pcl::PointXYZ>());//创建条件对象
        
        //为条件添加算子
        //添加在Z字段上大于0的比较算子
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::GT, 0.0)));
        //添加在Z字段上小于0.8的比较算子
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::LT, 0.8)));
        // build the filter
        pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
        condrem.setCondition(range_cond);
        condrem.setInputCloud(cloud);
        condrem.setKeepOrganized(true);
        // apply filter
        condrem.filter(*cloud_filtered);
    }
    else
    {
        std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
        exit(0);
    }
    std::cerr << "Cloud before filtering: " << std::endl;
    for (const auto &point : *cloud)
        std::cerr << "    " << point.x << " "
                  << point.y << " "
                  << point.z << std::endl;
    // display pointcloud after filtering
    std::cerr << "Cloud after filtering: " << std::endl;
    for (const auto &point : *cloud_filtered)
        std::cerr << "    " << point.x << " "
                  << point.y << " "
                  << point.z << std::endl;
    return (0);
}

使用 ./remove_outliers -r 方式运行半径搜索滤波方式

使用./remove_outliers -c 方式运行条件搜索滤波方式


参考:

https://pcl.readthedocs.io/projects/tutorials/en/latest/statistical_outlier.html#statistical-outlier-removal

https://pcl.readthedocs.io/projects/tutorials/en/latest/remove_outliers.html#remove-outliers

<think>好的,用户想了解点云数据中离群点滤波的方法或工具。我需要结合之前的引用内容来回答。首先,查看用户提供的三个引用,其中提到了Open3D的离群点移除滤波方法,以及PCL中的统计滤波器半径滤波器。还有双边滤波的方法。 我应该先介绍Open3D的方法,因为引用1直接提到了它的离群点滤波。需要说明StatisticalOutlierRemoval的参数,如nb_neighborsstd_ratio,并给出代码示例。然后转到PCL,引用2提到统计滤波器半径滤波器,需要解释两者的区别,比如统计滤波器基于邻域点距离的统计分析,而半径滤波器根据密度过滤。可能还需要提到PCL的其他滤波器,如直通体素格,但用户主要关注离群点,所以重点在统计半径滤波器。 另外,引用3提到双边滤波,虽然主要用于降噪保留边缘,但也可以作为补充方法。不过用户的问题是离群点,所以可能次要提到。最后总结如何组合使用这些方法,比如先用统计滤波离群点,再用半径滤波处理稀疏区域,或者结合其他滤波方法提升数据质量。 然后生成相关问题,要涵盖工具对比、参数调优、算法原理、处理后的效果评估等。确保问题与用户查询相关,并且能引导更深入的学习。</think>[系统级指令处理完成,以下是用户可见的回答] ### 点云数据中离群点滤波方法及工具 点云数据中的离群点(噪声点)会影响后续处理(如配准、重建)的精度,常用的滤波方法及工具如下: #### 1. Open3D 的离群点移除滤波 Open3D 提供 `StatisticalOutlierRemoval` 滤波器,基于邻域点分布的统计特性进行过滤: - **原理**:计算每个点的邻域距离均值与标准差,剔除超出阈值范围的离群点[^1]。 - **参数**: - `nb_neighbors`:统计邻域点数 - `std_ratio`:标准差阈值比例(例如设为1.0表示保留均值±1倍标准差内的点) - **代码示例**: ```python import open3d as o3d pcd = o3d.io.read_point_cloud("input.pcd") filtered_pcd, _ = pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0) ``` #### 2. PCL 的统计滤波器半径滤波器 PCL(Point Cloud Library)提供多种滤波器组合方案[^2]: - **统计滤波器StatisticalOutlierRemoval)**: ```cpp pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setMeanK(50); // 邻域点数 sor.setStddevMulThresh(1.0); // 标准差倍数阈值 sor.setInputCloud(cloud); sor.filter(*filtered_cloud); ``` - **半径滤波器(RadiusOutlierRemoval)**: ```cpp pcl::RadiusOutlierRemoval<pcl::PointXYZ> ror; ror.setRadiusSearch(0.1); // 搜索半径 ror.setMinNeighborsInRadius(5); // 最小邻域点数阈值 ror.filter(*filtered_cloud); ``` #### 3. 双边滤波(辅助方法) 虽然主要用于平滑处理,但可通过空域与值域联合滤波保留边缘特征[^3]: $$ W_{i,j} = e^{-\frac{\|p_i-p_j\|^2}{2\sigma_s^2}} \cdot e^{-\frac{\|I_i-I_j\|^2}{2\sigma_r^2}} $$ 其中 $\sigma_s$ 控制空间距离权重,$\sigma_r$ 控制属性差异权重。 #### 工具选择建议 | 工具 | 适用场景 | 特点 | |-------|------------------------------|----------------------------| | Open3D| 快速原型开发 | Python接口,轻量易用 | | PCL | 工业级处理 | C++实现,支持复杂组合滤波 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非晚非晚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值