回来没拿PCL书,幸亏安装时候就下好了源代码,只能看着代码看人是干啥的。
在获取点云时,由于各种因素数据中会不可避免的出现噪声点,所以需要进行滤波,一般也是进行预处理的第一步。我们要根据不同的情况选择合适的滤波方法。
pcl中提供了很多滤波器,嗯,真好。
一、Pass-through filter 直通滤波器
可以指定字段,指定坐标范围来滤除范围内外的点。看注释。
// 创建滤波器对象
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud (cloud);
pass.setFilterFieldName ("z");//选择z轴方向进行滤波
pass.setFilterLimits (0.0, 1.0);//过滤掉z轴坐标在[0,1]之外的点
//设置保留范围内的还是过滤掉范围内的
//默认false。true:滤波结果取反,过滤掉z轴坐标在[0.0, 1.0]范围之内的点
//pass.setFilterLimitsNegative (true);
pass.filter (*cloud_filtered);//执行滤波,cloud_filtered就是滤波后的点云
result:false / true
二、VoxelGrid 体素法滤波
主要作用是对点云进行降采样,可以在保证点云原有几何结构基本不变的前提下减少点的数量,多用于密集型点云的预处理中,以加快后续配准、重建等操作的执行速度。
体素栅格滤波器的主要思想是在点云所在三维空间创建一个体素栅格,对于栅格内的每一个体素,以体素内所有点的重心近似代替体素中的点,最终,所有体素中的重心点组成滤波后的点云。通过体素的大小可以控制降采样的程度,体素越大,则滤波后的点云越稀疏。体素栅格滤波器的执行速度较慢,但是它能最大限度地保留点云原始的几何信息。
优缺点:这种方法比用体素中心来逼近的方法更慢,但它对于采样点对应曲面的表示更为准确。
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
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); // 把路径改为自己存放文件的路径
std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
<< " data points (" << pcl::getFieldsList(*cloud) << ")." << std::endl;
// 创建滤波器对象,体素栅格下采样。下采样的大小为1cm。
pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
sor.setInputCloud (cloud);
sor.setLeafSize (0.01f, 0.01f, 0.01f);//设置滤波时创建的体素大小为1cm立方体
sor.filter (*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", *cloud_filtered,
Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false);
return (0);
}
result:可以把滤波前后点云放到CloudCampare中对比,观察变化。
三、statistical removal 统计滤波器
这个滤波器倒是闻所未闻。
主要作用是去除稀疏离群噪点。在采集点云的过程中,由于测量噪声的影响,会引入部分离群噪点,它们在点云空间中分布稀疏。在估算点云局部特征(例如计算采样点处的法向量和曲率变化率)时,这些噪点可能导致错误的计算结果,从而使点云配准等后期处理失败。
统计滤波器的主要思想是假设点云中所有的点与其最近的k个邻居点的平均距离满足高斯分布,那么,根据均值和方差可确定一个距离阈值,当某个点与其最近k个点的平均距离大于这个阈值时,判定该点为离群点并去除。统计滤波器的实现原理如下:首先,遍历点云,计算每个点与其最近的k个邻居点之间的平均距离;其次,计算所有平均距离的均值μ与标准差σ,则距离阈值dmax可表示为dmax=μ+α×σ,α是一个常数,可称为比例系数,它取决于邻居点的数目;最后,再次遍历点云,剔除与k个邻居点的平均距离大于dmax的点。
// 创建滤波器对象
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
sor.setInputCloud (cloud);
sor.setMeanK (50);//邻居点数目
sor.setStddevMulThresh (1.0);//比例系数α
sor.filter (*cloud_filtered);
四、Radius Outlier_Removal 半径滤波器
pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
outrem.setInputCloud(cloud);
outrem.setRadiusSearch(0.8);//在0.8为半径的范围内搜寻邻居点
outrem.setMinNeighborsInRadius (2);//邻居少于2个的点认为是离群点
outrem.filter (*cloud_filtered);
五、条件滤波
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
// 创建环境
pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond (new
pcl::ConditionAnd<pcl::PointXYZ> ());
range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::GT, 0.0)));
range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::LT, 0.8)));
//GT表示大于等于,LT表示小于等于
// 创建滤波器
pcl::ConditionalRemoval<pcl::PointXYZ> condrem (range_cond);
condrem.setInputCloud (cloud);
condrem.setKeepOrganized(true);
condrem.filter (*cloud_filtered);
六、ProjectInliers 投影滤波
将点投影到一个参数化模型上(例如平面或球等)。本例中我们使用一个ax+by+cz+d=0的平面模型。
// 创建一个系数为X=Y=0,Z=1的平面
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;
// 创建滤波器对象
pcl::ProjectInliers<pcl::PointXYZ> proj;
proj.setModelType (pcl::SACMODEL_PLANE);//设置对象对应的投影模型
proj.setInputCloud (cloud);
proj.setModelCoefficients (coefficients);//设置模型对应的系数
proj.filter (*cloud_projected);
result:可以看到,投影前的z轴都不为0,是随机产生的值,投影之后,xy没有改变,z都变为0,符合程序的逻辑,该投影滤波类输入为点云和投影模型,输出为投影到模型上之后的点云。
七、extract_indices 提取滤波器
分割出点云的一个平面,结合后面的分割共同理解,详见下一篇笔记。
八、BilateralFilter 双边滤波器
双边滤波主要作用是具有保边的功能,即在滤波的过程中不会连带边界一起都平滑掉,这样有利于计算准确的法线。一般情况下双边滤波的效果不是很明显,最好是分别计算了运行前后点云的法线,可以通过法线的分布清楚的分出效果来。
需要注意的是,处理的点云必须是organized。
pcl::FastBilateralFilter<pcl::PointXYZ> filter;
filter.setInputCloud(cloud);
filter.setSigmaS(0.5);
filter.setSigmaR(0.004);
filter.applyFilter(*cloud_filtered);
reference:
【1】《点云库PCL从入门到精通》
【2】https://blog.csdn.net/peach_blossom/article/details/80932853
【3】http://www.pclcn.org/study/ 中国pcl网