PCL的点云滤波


    点云数据中会存在噪声点,离群点这些我们在后续操作中不需要的点,所以需要滤波删除这些点。这个过程也可以称为点云预处理。同时预处理还包括孔洞修复,数据压缩等,这里我们暂时只讨论噪声点和离群点,其他后续如有需要再学习。通过预处理后,才能更好的进行配准、特征提取、曲面重建、可视化等后续应用处理。pcl/filters模块提供了一些滤波处理算法,接下来对其中的一部分进行介绍。

使用直通滤波器对点云进行滤波处理

    直通滤波器通常是对指定的某一维度进行滤波,也就是去掉用户指定范围内部或者外部的点 ,例如高程筛选。下面是一个高程筛选的例子,将点云Z方向的范围设置为(0.0,1.0),并保留内部点,删除外部点。
官方tutorials: http://pointclouds.org/documentation/tutorials/passthrough.php#passthrough

#include <iostream>
#include <ctime>
#include <pcl/point_types.h>            //点云格式
#include <pcl/filters/passthrough.h>    //PCL滤波算法中的passthrough

int            //PCL函数定义编码规范,返回值类型单独放一行,函数名及参数列表放一行。
main (int argc, char** argv)
{ 
    srand(time(0));
    //pcl是命名空间,PointCloud是类模板,<pcl::PointXYZ>是模板实例化的类型,Ptr是智能指针
    //cloud是指针变量 指向PointCloud<pcl::PointXYZ>类对象的指针
    //简单来说,就是创建了一份名cloud的存储XYZ类型点云数据的指针。
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
  
    //填入点云数据
    cloud->width  = 5;                   //设置点云宽度/数量
    cloud->height = 1;                   //设置点云高度/无序点云
    cloud->points.resize (cloud->width * cloud->height);      //点云总数

    //size_t 其实就是unsinged int
    for (size_t i = 0; i < cloud->points.size (); ++i)      //为点云填充数据,这里为随机数
    {
        cloud->points[i].x = rand () / (RAND_MAX + 1.0f)-0.5;
        cloud->points[i].y = rand () / (RAND_MAX + 1.0f)-0.5;
        cloud->points[i].z = rand () / (RAND_MAX + 1.0f)-0.5;
    }

    //std::err 标准出错输出对象,默认信息输出到屏幕。
    //打印所有点到标准错误输出
    std::cerr << "Cloud before filtering: " << std::endl;
    for (size_t i = 0; i < cloud->points.size (); ++i)
    {
        std::cerr << "    " << cloud->points[i].x << " " 
                        << cloud->points[i].y << " " 
                        << cloud->points[i].z << std::endl;
     }


/*************************************************************************
 创建直通滤波器的对象,设立参数,滤波字段名被设置为Z轴方向,可接受的范围为(0.0,1.0)
 即将点云中所有点的Z轴坐标不在该范围内的点过滤掉或保留,这里是过滤掉,由函数
 setFilterLimitsNegative设定。即是按高程信息筛选。
*************************************************************************/
      // 创建滤波器对象
      pcl::PassThrough<pcl::PointXYZ> pass;    //设置滤波器对象
      pass.setInputCloud (cloud);              //设置输入点云
      pass.setFilterFieldName ("z");           //设置过滤时所需要点云类型的z字段
      pass.setFilterLimits (0.0, 1.0);         //设置在过滤的z字段上的范围
      //pass.setFilterLimitsNegative (true);   //设置保留范围内的还是范围外
      pass.filter (*cloud_filtered);           //执行滤波,把滤波结果保存在cloud_filtered

      std::cerr << "Cloud after filtering: " << std::endl;
      for (size_t i = 0; i < cloud_filtered->points.size (); ++i)
     {  
         std::cerr << "    " << cloud_filtered->points[i].x << " " 
                        << cloud_filtered->points[i].y << " " 
                        << cloud_filtered->points[i].z << std::endl;
      }
  return (0);
}

结果为:
在这里插入图片描述
    可以看到在滤波之前共有5个点云,其中z方向为负的有3个,经过滤波之后所有z方向为负的均被删除,只留下两个点云。

PS:由于本人在接触PCL以及点云知识之前对计算机知识完全属于零基础,连C++都是从头开始学,对于C++代码在ubuntu下的编译和运行并没有充分理解,导致在编译以上代码时走了很多弯路。下面给出我自己用的方法,不知是否正确,还希望读到这的朋友能够不吝指教,感谢!

首先在代码文件和CMakeLists.txt的文件夹中打开终端

mkdir src
mkdir build
cd build
cmake ..
make

在build文件中会生成个xxxx.out文件

./xxxx.out

便可运行该文件,得到上述图中结果。

使用VoxelGrid滤波器对点云进行下采样

    VoxelGrid滤波也叫体素化网格法,是PCL中VoxelGrid类通过输入的点云数据创建一个三维体素栅格(简单点来说就是特别小的空间三维立方体的集合),然后在每个体素(三维立方体)内,用体素中所有点云点的重心(不是中心)近似的表示该体素内的所有点,对于所有体素处理后得到过滤后的点云。这种方法比用体素中心来逼近的方法更慢,但是对于采样点对应曲面的表示更为准确。
官方tutorials: http://pointclouds.org/documentation/tutorials/voxel_grid.php#voxelgrid

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
int
main (int argc, char** argv)
{
      pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2 ());
      pcl::PCLPointCloud2::Ptr cloud_filtered (new pcl::PCLPointCloud2 ());
      // 读取点云数据
      pcl::PCDReader reader;
      // 把路径改为自己存放文件的路径
      reader.read ("table_scene_lms400.pcd", *cloud);    //读取点云到cloud中
      std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height 
                << " data points (" << pcl::getFieldsList (*cloud) << ").";
    
      // pcl::getFieldsList (*cloud)得到cloud的field信息(x y z intensity distance sid)
  
      // 创建滤波器对象
      pcl::VoxelGrid<pcl::PCLPointCloud2> sor;      // 创建滤波对象
      sor.setInputCloud (cloud);                    //给滤波对象设置需要过滤的点云
      sor.setLeafSize (0.01f, 0.01f, 0.01f);        //设置滤波时创建的体素大小1cm立方体
      sor.filter (*cloud_filtered);                 //执行滤波处理,存储输出cloud_filtered
      std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height 
                << " data points (" << pcl::getFieldsList (*cloud_filtered) << ").";
      
      //最后将数据写入磁盘以做他用,例如可视化等
      pcl::PCDWriter writer;
      writer.write ("table_scene_lms400_downsampled.pcd", 
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
PCL(点云库)是一种用于处理三维点云数据的开源库。在PCL中,点云滤波是一种通过对点云数据进行处理来去除噪音和无效点的方法。下面是一个示例代码,用于使用PCL进行离群点滤波和统计滤波。 首先,需要包含PCL库的头文件: ```cpp #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/filters/statistical_outlier_removal.h> #include <pcl/filters/voxel_grid.h> ``` 然后,定义一个主函数,在其中读取点云数据文件并应用滤波器: ```cpp int main() { // 创建点云数据对象 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // 从磁盘读取点云数据文件 if (pcl::io::loadPCDFile<pcl::PointXYZ>("/path/to/pointcloud.pcd", *cloud) == -1) { PCL_ERROR("Couldn't read file!"); return -1; } // 创建离群点滤波器对象 pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud(cloud); sor.setMeanK(50); // 用于计算每个点邻域的均值的点数 sor.setStddevMulThresh(1.0); // 标准差倍数阈值 sor.filter(*cloud); // 应用滤波器 // 创建体素(体素网格)滤波器对象 pcl::VoxelGrid<pcl::PointXYZ> vg; vg.setInputCloud(cloud); vg.setLeafSize(0.01, 0.01, 0.01); // 设置体素的大小 vg.filter(*cloud); // 应用滤波器 // 输出滤波后的点云数据 std::cout << "Filtered point cloud contains " << cloud->size() << " data points." << std::endl; return 0; } ``` 上述代码首先创建了一个点云数据对象,并从磁盘读取点云数据文件。然后,创建了一个离群点滤波器对象,并设置相关参数。接着,将点云数据传递给离群点滤波器,并应用滤波器进行滤波。之后,创建了一个体素滤波器对象,并设置相关参数。将点云数据传递给体素滤波器,并应用滤波器进行滤波。最后,输出滤波后的点云数据的数量。 这段代码演示了如何使用PCL进行点云滤波。在实际应用中,可以根据特定需求选择不同的滤波方法和参数进行更精确的处理。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值