点云处理技术之PCL滤波器——离群点滤波(statisticalOutlierRemovalConditionalRemoval 和RadiusOutlinerRemoval)

Posted 非晚非晚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了点云处理技术之PCL滤波器——离群点滤波(statisticalOutlierRemovalConditionalRemoval 和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

以上是关于点云处理技术之PCL滤波器——离群点滤波(statisticalOutlierRemovalConditionalRemoval 和RadiusOutlinerRemoval)的主要内容,如果未能解决你的问题,请参考以下文章

点云处理技术之PCL滤波器——体素滤波器(pcl::VoxelGrid)

点云处理技术之PCL滤波器——参数化模型(投影点云,pcl::ProjectInliers)

点云处理技术之PCL滤波器——提取索引的点云(pcl::ExtractIndices)

pcl库中滤波器总结

点云处理技术之PCL滤波器——直通滤波器(pcl::PassThrough)

PCL 滤波采样——统计学滤波