文章目录
点云数据中会存在噪声点,离群点这些我们在后续操作中不需要的点,所以需要滤波删除这些点。这个过程也可以称为点云预处理。同时预处理还包括孔洞修复,数据压缩等,这里我们暂时只讨论噪声点和离群点,其他后续如有需要再学习。通过预处理后,才能更好的进行配准、特征提取、曲面重建、可视化等后续应用处理。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",