linux下pcl安装
1】命令行安装 编译好的二进制文件
sudo add-apt-repository ppa:v-launchpad-jochen-sprickerhof-de/pcl
sudo apt-get update
sudo apt-get install libpcl-all
2】源码安装
安装依赖
Boost,Eigen,FlANN,VTK,OpenNI,QHull
sudo apt-get install build-essential libboost-all-dev
sudo apt-get install libvtk5-dev
Vtk,(visualization toolkit 可视化工具包)是一个开源的免费软件系统,
教程 http://blog.csdn.net/www_doling_net/article/details/8763686
主要用于三维计算机图形学、图像处理和可视化。
它在三维函数库OpenGL的基础上采用面向对象的设计方法发展而来,且具有跨平台的特性。
Vtk是在面向对象原理的基础上设计和实现的,它的内核是用C++构建的
VTK面向对象,含有大量的对象模型。
源对象是可视化流水线的起点,
映射器(Mapper)对象是可视化流水线的终点,是图形模型和可视化模型之间的接口.
回调(或用户方法): 观察者监控一个对象所有被调用的事件,
如果正在监控的一个事件被触发,一个与之相应的回调函数就会被调用。
图形模型:
Renderer 渲染器,vtkRenderWindow 渲染窗口
可视化模型:
vtkDataObject 可以被看作是一个二进制大块(blob)
vtkProcessObject 过程对象一般也称为过滤器,按照某种运算法则对数据对象进行处理
FLANN介绍
FLANN库全称是Fast Library for Approximate Nearest Neighbors,
它是目前最完整的(近似)最近邻开源库。
http://www.cs.ubc.ca/research/flann/uploads/FLANN/flann_manual-1.8.4.pdf
去下载 http://www.cs.ubc.ca/research/flann/#download
linux下安装 eigen
sudo apt-get install libeigen3-dev
定位安装位置
locate eigen3
sudo updatedb
下载源码
git clone https://github.com/PointCloudLibrary/pcl pcl-trunk
cd pcl-trunk && mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
make -j2
sudo make -j2 install
点云滤波 /filters
点云滤波,顾名思义,就是滤掉噪声。原始采集的点云数据往往包含大量散列点、孤立点,
其类似于信号处理中的滤波,单实现手段却和信号处理不一样,主要有以下几方面原因:
点云不是函数,无法建立横纵坐标之间的关系
点云在空间中是离散的,不像图像信号有明显的定义域
点云在空间中分布广泛,建立点与点之间的关系较为困难
点云滤波依赖于集合信息而非数值信息
点云滤波方法主要有:
直通滤波器 pcl::PassThrough<pcl::PointXYZ> pass、
体素格滤波器 pcl::VoxelGrid<pcl::PCLPointCloud2> sor;、
统计滤波器 pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;、
半径滤波器 pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
双边滤波 pcl::BilateralFilter<pcl::PointXYZ> bf;
空间剪裁:
pcl::Clipper3D<pcl::PointXYZ>
pcl::BoxClipper3D<pcl::PointXYZ>
pcl::CropBox<pcl::PointXYZ>
pcl::CropHull<pcl::PointXYZ> 剪裁并形成封闭曲面
卷积滤波:实现将两个函数通过数学运算产生第三个函数,可以设定不同的卷积核
pcl::filters::Convolution<PointIn, PointOut>
pcl::filters::ConvolvingKernel<PointInT, PointOutT>
随机采样一致滤波
等,
通常组合使用完成任务。
1】直通滤波器 PassThrough
/*
直通滤波器 PassThrough 直接指定保留哪个轴上的范围内的点
#include <pcl/filters/passthrough.h>
如果使用线结构光扫描的方式采集点云,必然物体沿z向分布较广,
但x,y向的分布处于有限范围内。
此时可使用直通滤波器,确定点云在x或y方向上的范围,
可较快剪除离群点,达到第一步粗处理的目的。
// 创建点云对象 指针
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
// 原点云获取后进行滤波
pcl::PassThrough<pcl::PointXYZ> pass;// 创建滤波器对象
pass.setInputCloud (cloud);//设置输入点云
pass.setFilterFieldName ("z");//滤波字段名被设置为Z轴方向
pass.setFilterLimits (0.0, 1.0);//可接受的范围为(0.0,1.0)
//pass.setFilterLimitsNegative (true);//设置保留范围内 还是 过滤掉范围内
pass.filter (*cloud_filtered); //执行滤波,保存过滤结果在cloud_filtered
*/
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>//直通滤波器 PassThrough
#include <pcl/visualization/cloud_viewer.h>//点云可视化
// 别名
typedef pcl::PointCloud<pcl::PointXYZ> Cloud;
int
main (int argc, char** argv)
{
// 定义 点云对象 指针
Cloud::Ptr cloud_ptr(new Cloud());
Cloud::Ptr cloud_filtered_ptr(new Cloud());
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr (new pcl::PointCloud<pcl::PointXYZ>);
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_ptr (new pcl::PointCloud<pcl::PointXYZ>);
// 产生点云数据
cloud_ptr->width = 5;
cloud_ptr->height = 1;
cloud_ptr->points.resize (cloud_ptr->width * cloud_ptr->height);
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
{
cloud_ptr->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cerr << "Cloud before filtering滤波前: " << std::endl;
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
std::cerr << " " << cloud_ptr->points[i].x << " "
<< cloud_ptr->points[i].y << " "
<< cloud_ptr->points[i].z << std::endl;
// 创建滤波器对象 Create the filtering object
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud (cloud_ptr);//设置输入点云
pass.setFilterFieldName ("z");// 定义轴
pass.setFilterLimits (0.0, 1.0);// 范围
pass.setFilterLimitsNegative (true);//标志为false时保留范围内的点
pass.filter (*cloud_filtered_ptr);
// 输出滤波后的点云
std::cerr << "Cloud after filtering滤波后: " << std::endl;
for (size_t i = 0; i < cloud_filtered_ptr->points.size (); ++i)
std::cerr << " " << cloud_filtered_ptr->points[i].x << " "
<< cloud_filtered_ptr->points[i].y << " "
<< cloud_filtered_ptr->points[i].z << std::endl;
// 程序可视化
pcl::visualization::CloudViewer viewer("pcd viewer");// 显示窗口的名字
viewer.showCloud(cloud_filtered_ptr);
while (!viewer.wasStopped())
{
// Do nothing but wait.
}
return (0);
}
2】体素格滤波器VoxelGrid
/*
下载桌子点云数据
https://raw.github.com/PointCloudLibrary/data/master/tutorials/table_scene_lms400.pcd
体素格滤波器VoxelGrid 在网格内减少点数量保证重心位置不变 PCLPointCloud2()
下采样
#include <pcl/filters/voxel_grid.h>
注意此点云类型为 pcl::PCLPointCloud2 类型 blob 格子类型
#include <pcl/filters/voxel_grid.h>
// 转换为模板点云 pcl::PointCloud<pcl::PointXYZ>
pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered);
如果使用高分辨率相机等设备对点云进行采集,往往点云会较为密集。
过多的点云数量会对后续分割工作带来困难。
体素格滤波器可以达到向下采样同时不破坏点云本身几何结构的功能。
点云几何结构 不仅是宏观的几何外形,也包括其微观的排列方式,
比如横向相似的尺寸,纵向相同的距离。
随机下采样虽然效率比体素滤波器高,但会破坏点云微观结构.
使用体素化网格方法实现下采样,即减少点的数量 减少点云数据,
并同时保存点云的形状特征,在提高配准,曲面重建,形状识别等算法速度中非常实用,
PCL是实现的VoxelGrid类通过输入的点云数据创建一个三维体素栅格,
容纳后每个体素内用体素中所有点的重心来近似显示体素中其他点,
这样该体素内所有点都用一个重心点最终表示,对于所有体素处理后得到的过滤后的点云,
这种方法比用体素中心(注意中心和重心)逼近的方法更慢,但是对于采样点对应曲面的表示更为准确。
*/
#include <iostream>
#include <pcl/point_types.h>
//#include <pcl/filters/passthrough.h>
#include <pcl/filters/voxel_grid.h>//体素格滤波器VoxelGrid
#include <pcl/io/pcd_io.h>//点云文件pcd 读写
#include <pcl/visualization/cloud_viewer.h>//点云可视化
#include <pcl_conversions/pcl_conversions.h>//点云类型转换
/*
CloudViewer是简单显示点云的可视化工具,可以使用比较少的代码查看点云,
但是这个是不能用于多线程应用程序当中的。
下面的代码的工作是关于如何在可视化线程中运行代码的例子,
PCLVisualizer是CloudViewer的后端,但它在自己的线程中运行,
如果要使用PCLVisualizer类必须使用调用函数,这样可以避免可视化的并发问题。
但是在实际调用的时候要注意,以防出现核心已转储这一类很麻烦的问题。
*/
using namespace std;
// 别名
typedef pcl::PointCloud<pcl::PointXYZ> Cloud;
int
main (int argc, char** argv)
{
// 定义 点云对象 指针
pcl::PCLPointCloud2::Ptr cloud2_ptr(new pcl::PCLPointCloud2());
pcl::PCLPointCloud2::Ptr cloud2_filtered_ptr(new pcl::PCLPointCloud2());
Cloud::Ptr cloud_filtered_ptr(new Cloud);
// 读取点云文件 填充点云对象
pcl::PCDReader reader;
reader.read( "../table_scene_lms400.pcd", *cloud2_ptr);
if(cloud2_ptr==NULL) { cout << "pcd file read err" << endl; return -1;}
cout << "PointCLoud before filtering 滤波前数量: " << cloud2_ptr->width * cloud2_ptr->height
<< " data points ( " << pcl::getFieldsList (*cloud2_ptr) << "." << endl;
// 创建滤波器对象 Create the filtering object
pcl::VoxelGrid<pcl::PCLPointCloud2> vg;
vg.setInputCloud (cloud2_ptr);//设置输入点云
vg.setLeafSize(0.01f, 0.01f, 0.01f);// 体素块大小 1cm
vg.filter (*cloud2_filtered_ptr);
// 输出滤波后的点云信息
cout << "PointCLoud before filtering 滤波后数量: " << cloud2_filtered_ptr->width * cloud2_filtered_ptr->height
<< " data points ( " << pcl::getFieldsList (*cloud2_filtered_ptr) << "." << endl;
// 写入内存
pcl::PCDWriter writer;
writer.write("table_scene_lms400_downsampled.pcd",*cloud2_filtered_ptr,
Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false);
// 调用系统可视化命令行显示
//system("pcl_viewer table_scene_lms400_inliers.pcd");
// 转换为模板点云 pcl::PointCloud<pcl::PointXYZ>
pcl::fromPCLPointCloud2 (*cloud2_filtered_ptr, *cloud_filtered_ptr);
// 程序可视化
pcl::visualization::CloudViewer viewer("pcd viewer");// 显示窗口的名字
viewer.showCloud(cloud_filtered_ptr);
while (!viewer.wasStopped())
{
// Do nothing but wait.
}
return (0);
}
3】条件滤波器 conditional_removal
/*
条件滤波器
可以一次删除满足对输入的点云设定的一个或多个条件指标的所有的数据点
删除点云中不符合用户指定的一个或者多个条件的数据点
不在条件范围内的点 被替换为 nan
#include <pcl/filters/conditional_removal.h>
*/
#include <iostream>
#include <pcl/point_types.h>
//#include <pcl/filters/passthrough.h>
//#include <pcl/ModelCoefficients.h> //模型系数头文件
//#include <pcl/filters/project_inliers.h> //投影滤波类头文件
#include <pcl/io/pcd_io.h> //点云文件pcd 读写
//#include <pcl/filters/radius_outlier_removal.h>// 球半径滤波器
#include <pcl/filters/conditional_removal.h> //条件滤波器
//#include <pcl/filters/filter.h>
#include <pcl/visualization/cloud_viewer.h>//点云可视化
// 别名
typedef pcl::PointCloud<pcl::PointXYZ> Cloud;
using namespace std;
int main (int argc, char** argv)
{
// 定义 点云对象 指针
Cloud::Ptr cloud_ptr(new Cloud());
Cloud::Ptr cloud_filtered_ptr(new Cloud());
// 产生点云数据
cloud_ptr->width = 5;
cloud_ptr->height = 1;
cloud_ptr->points.resize (cloud_ptr->width * cloud_ptr->height);
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
{
cloud_ptr->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cerr << "Cloud before filtering半径滤波前: " << std::endl;
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
std::cerr << " " << cloud_ptr->points[i].x << " "
<< cloud_ptr->points[i].y << " "
<< cloud_ptr->points[i].z << std::endl;
// 可使用 strcmp获取指定命令行参数 if (strcmp(argv[1], "-r") == 0)
//创建条件定义对象
pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond_cptr(new pcl::ConditionAnd<pcl::PointXYZ>());
//为条件定义对象添加比较算子
range_cond_cptr->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::GT, 0.0)));
//添加在Z字段上大于(pcl::ComparisonOps::GT great Then)0的比较算子
range_cond_cptr->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::LT, 0.8)));
//添加在Z字段上小于(pcl::ComparisonOps::LT Lower Then)0.8的比较算子
// 创建滤波器并用条件定义对象初始化
pcl::ConditionalRemoval<pcl::PointXYZ> conditrem;//创建条件滤波器
conditrem.setCondition (range_cond_cptr); //并用条件定义对象初始化
conditrem.setInputCloud (cloud_ptr); //输入点云
conditrem.setKeepOrganized(true); //设置保持点云的结构
// 执行滤波
conditrem.filter(*cloud_filtered_ptr); //大于0.0小于0.8这两个条件用于建立滤波器
// 不在条件范围内的点 被替换为 nan
// 输出滤波后的点云
std::cerr << "Cloud after filtering半径滤波后: " << std::endl;
for (size_t i = 0; i < cloud_filtered_ptr->points.size (); ++i)
std::cerr << " " << cloud_filtered_ptr->points[i].x << " "
<< cloud_filtered_ptr->points[i].y << " "
<< cloud_filtered_ptr->points[i].z << std::endl;
// 去除 nan点
std::vector<int> mapping;
pcl::removeNaNFromPointCloud(*cloud_filtered_ptr, *cloud_filtered_ptr, mapping);
// 输出去除nan后的点云
std::cerr << "Cloud after delet nan point去除nan点 : " << std::endl;
for (size_t i = 0; i < cloud_filtered_ptr->points.size (); ++i)
std::cerr << " " << cloud_filtered_ptr->points[i].x << " "
<< cloud_filtered_ptr->points[i].y << " "
<< cloud_filtered_ptr->points[i].z << std::endl;
// 程序可视化
pcl::visualization::CloudViewer viewer("pcd viewer");// 显示窗口的名字
viewer.showCloud(cloud_filtered_ptr);
while (!viewer.wasStopped())
{
// Do nothing but wait.
}
return (0);
}
4】投影滤波 输出投影后的点的坐标 project_inliers
/*
投影滤波 输出投影后的点的坐标
使用参数化模型投影点云
如何将点投影到一个参数化模型上(平面或者球体等),
参数化模型通过一组参数来设定,对于平面来说使用其等式形式。
在PCL中有特定存储常见模型系数的数据结构。
#include <pcl/ModelCoefficients.h> //模型系数头文件
#include <pcl/filters/project_inliers.h> //投影滤波类头文件
*/
#include <iostream>
#include <pcl/point_types.h>
//#include <pcl/filters/passthrough.h>
#include <pcl/ModelCoefficients.h> //模型系数头文件
#include <pcl/filters/project_inliers.h> //投影滤波类头文件
#include <pcl/io/pcd_io.h> //点云文件pcd 读写
#include <pcl/visualization/cloud_viewer.h>//点云可视化
// 别名
typedef pcl::PointCloud<pcl::PointXYZ> Cloud;
using namespace std;
int main (int argc, char** argv)
{
// 定义 点云对象 指针
Cloud::Ptr cloud_ptr(new Cloud());
Cloud::Ptr cloud_filtered_ptr(new Cloud());
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr (new pcl::PointCloud<pcl::PointXYZ>);
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_ptr (new pcl::PointCloud<pcl::PointXYZ>);
// 产生点云数据
cloud_ptr->width = 5;
cloud_ptr->height = 1;
cloud_ptr->points.resize (cloud_ptr->width * cloud_ptr->height);
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
{
cloud_ptr->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cerr << "Cloud before filtering投影滤波前: " << std::endl;
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
std::cerr << " " << cloud_ptr->points[i].x << " "
<< cloud_ptr->points[i].y << " "
<< cloud_ptr->points[i].z << std::endl;
// 填充ModelCoefficients的值,使用ax+by+cz+d=0平面模型,其中 a=b=d=0,c=1 也就是X——Y平面
//定义模型系数对象,并填充对应的数据 创建投影滤波模型重会设置模型类型 pcl::SACMODEL_PLANE
pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients());
coefficients->values.resize (4);
coefficients->values[0] = coefficients->values[1] = 0;
coefficients->values[2] = 1.0;
coefficients->values[3] = 0;
// 创建投影滤波模型ProjectInliers对象,使用ModelCoefficients作为投影对象的模型参数
pcl::ProjectInliers<pcl::PointXYZ> proj; //创建投影滤波对象
proj.setModelType (pcl::SACMODEL_PLANE); //设置对象对应的投影模型 平面模型
proj.setInputCloud (cloud_ptr); //设置输入点云
proj.setModelCoefficients (coefficients); //设置模型对应的系数
proj.filter (*cloud_filtered_ptr); //投影结果存储
// 输出滤波后的点云
std::cerr << "Cloud after filtering投影滤波后: " << std::endl;
for (size_t i = 0; i < cloud_filtered_ptr->points.size (); ++i)
std::cerr << " " << cloud_filtered_ptr->points[i].x << " "
<< cloud_filtered_ptr->points[i].y << " "
<< cloud_filtered_ptr->points[i].z << std::endl;
// 程序可视化
pcl::visualization::CloudViewer viewer("pcd viewer");// 显示窗口的名字
viewer.showCloud(cloud_filtered_ptr);
while (!viewer.wasStopped())
{
// Do nothing but wait.
}
return (0);
}
5】球半径滤波器 radius_outlier_removal
/*
球半径滤波器
#include <pcl/filters/radius_outlier_removal.h>
球半径滤波器与统计滤波器相比更加简单粗暴。
以某点为中心 画一个球计算落在该球内的点的数量,当数量大于给定值时,
则保留该点,数量小于给定值则剔除该点。
此算法运行速度快,依序迭代留下的点一定是最密集的,
但是球的半径和球内点的数目都需要人工指定。
*/
#include <iostream>
#include <pcl/point_types.h>
//#include <pcl/filters/passthrough.h>
//#include <pcl/ModelCoefficients.h> //模型系数头文件
//#include <pcl/filters/project_inliers.h> //投影滤波类头文件
#include <pcl/io/pcd_io.h> //点云文件pcd 读写
#include <pcl/filters/radius_outlier_removal.h>// 球半径滤波器
#include <pcl/visualization/cloud_viewer.h>//点云可视化
// 别名
typedef pcl::PointCloud<pcl::PointXYZ> Cloud;
using namespace std;
int main (int argc, char** argv)
{
// 定义 点云对象 指针
Cloud::Ptr cloud_ptr(new Cloud());
Cloud::Ptr cloud_filtered_ptr(new Cloud());
// 产生点云数据
cloud_ptr->width = 5;
cloud_ptr->height = 1;
cloud_ptr->points.resize (cloud_ptr->width * cloud_ptr->height);
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
{
cloud_ptr->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_ptr->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cerr << "Cloud before filtering半径滤波前: " << std::endl;
for (size_t i = 0; i < cloud_ptr->points.size (); ++i)
std::cerr << " " << cloud_ptr->points[i].x << " "
<< cloud_ptr->points[i].y << " "
<< cloud_ptr->points[i].z << std::endl;
// 可使用 strcmp获取指定命令行参数 if (strcmp(argv[1], "-r") == 0)
// 创建滤波器
pcl::RadiusOutlierRemoval<pcl::PointXYZ> Radius;
// 建立滤波器
Radius.setInputCloud(cloud_ptr);
Radius.setRadiusSearch(1.2);//半径为 0.8m
Radius.setMinNeighborsInRadius (2);//半径内最少需要 2个点
// 执行滤波
Radius.filter (*cloud_filtered_ptr);
// 输出滤波后的点云
std::cerr << "Cloud after filtering半径滤波后: " << std::endl;
for (size_t i = 0; i < cloud_filtered_ptr->points.size (); ++i)
std::cerr << " " << cloud_filtered_ptr->points[i].x << " "
<< cloud_filtered_ptr->points[i].y << " "
<< cloud_filtered_ptr->points[i].z << std::endl;
// 程序可视化
pcl::visualization::CloudViewer viewer("pcd viewer");// 显示窗口的名字
viewer.showCloud(cloud_filtered_ptr);
while (!viewer.wasStopped())
{
// Do nothing but wait.
}
return (0);
}
6】统计滤波器 StatisticalOutlierRemoval
/*
下载桌子点云数据
https://raw.github.com/PointCloudLibrary/data/master/tutorials/table_scene_lms400.pcd
统计滤波器 StatisticalOutlierRemoval
#include <pcl/filters/statistical_outlier_removal.h>
统计滤波器用于去除明显离群点(离群点往往由测量噪声引入)。
其特征是在空间中分布稀疏,可以理解为:每个点都表达一定信息量,
某个区域点越密集则可能信息量越大。噪声信息属于无用信息,信息量较小。
所以离群点表达的信息可以忽略不计。考虑到离群点的特征,
则可以定义某处点云小于某个密度,既点云无效。计算每个点到其最近的k(设定)个点平均距离
。则点云中所有点的距离应构成高斯分布。给定均值与方差,可剔除n个西格玛之外的点
激光扫描通常会产生密度不均匀的点云数据集,另外测量中的误差也会产生稀疏的离群点,
此时,估计局部点云特征(例如采样点处法向量或曲率变化率)时运算复杂,
这会导致错误的数值,反过来就会导致点云配准等后期的处理失败。
解决办法:对每个点的邻域进行一个统计分析,并修剪掉一些不符合标准的点。
具体方法为在输入数据中对点到临近点的距离分布的计算,对每一个点,
计算它到所有临近点的平均距离(假设得到的结果是一个高斯分布,
其形状是由均值和标准差决定),那么平均距离在标准范围之外的点,
可以被定义为离群点并从数据中去除。
*/
#include <iostream>
#include <pcl/point_types.h>
//#include <pcl/filters/passthrough.h>
//#include <pcl/filters/voxel_grid.h>//体素格滤波器VoxelGrid
#include <pcl/filters/statistical_outlier_removal.h>//统计滤波器
#include <pcl/io/pcd_io.h>//点云文件pcd 读写
#include <pcl/visualization/cloud_viewer.h>//点云可视化
using namespace std;
// 别名
typedef pcl::PointCloud<pcl::PointXYZ> Cloud;
int
main (int argc, char** argv)
{
// 定义 点云对象 指针
Cloud::Ptr cloud_ptr (new Cloud);
Cloud::Ptr cloud_filtered_ptr (new Cloud);
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr (new pcl::PointCloud<pcl::PointXYZ>);
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_ptr (new pcl::PointCloud<pcl::PointXYZ>);
// 读取点云文件 填充点云对象
pcl::PCDReader reader;
reader.read( "../table_scene_lms400.pcd", *cloud_ptr);
if(cloud_ptr==NULL) { cout << "pcd file read err" << endl; return -1;}
cout << "PointCLoud before filtering 滤波前数量: " << cloud_ptr->width * cloud_ptr->height
<< " data points ( " << pcl::getFieldsList (*cloud_ptr) << "." << endl;
// 创建滤波器,对每个点分析的临近点的个数设置为50 ,并将标准差的倍数设置为1 这意味着如果一
// 个点的距离超出了平均距离一个标准差以上,则该点被标记为离群点,并将它移除,存储起来
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sta;//创建滤波器对象
sta.setInputCloud (cloud_ptr); //设置待滤波的点云
sta.setMeanK (50); //设置在进行统计时考虑查询点临近点数
sta.setStddevMulThresh (1.0); //设置判断是否为离群点的阀值
sta.filter (*cloud_filtered_ptr); //存储内点
// 输出滤波后的点云信息
std::cerr << "Cloud after filtering: " << std::endl;
std::cerr << *cloud_filtered_ptr << std::endl;
// 写入内存 保存内点
pcl::PCDWriter writer;
writer.write("table_scene_lms400_inliers.pcd",*cloud_filtered_ptr, false);
// 保存外点 被滤出的点
sta.setNegative (true);
sta.filter (*cloud_filtered_ptr);
writer.write<pcl::PointXYZ> ("table_scene_lms400_outliers.pcd", *cloud_filtered_ptr, false);
// 调用系统可视化命令行显示
//system("pcl_viewer table_scene_lms400_inliers.pcd");
// 程序可视化
pcl::visualization::CloudViewer viewer("pcd viewer");// 显示窗口的名字
viewer.showCloud(cloud_filtered_ptr);
while (!viewer.wasStopped())
{
// Do nothing but wait.
}
return (0);
}
版权声明:本文为xiaoxiaowenqiang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。