日期:2021/11/26
预备知识
1、什么是多线程?如何实现?
https://blog.csdn.net/beidaol/article/details/89135277
2、new&delete
3、体素格降采样VoxelGrid
使用体素化网格方法实现下采样,即减少点的数量 减少点云数据,并同时保存点云的形状特征,在提高配准、曲面重建、形状识别等算法速度中非常实用。
PCL是实现的VoxelGrid类通过输入的点云数据创建一个三维体素栅格,容纳后每个体素内用体素中所有点的重心来近似显示体素中其他点,这样该体素内所有点都用一个重心点最终表示,对于所有体素处理后得到的过滤后的点云,这种方法比用体素中心(注意中心和重心)逼近的方法更慢,但是对于采样点对应曲面的表示更为准确。
体素格滤波器可以达到向下采样同时不破坏点云本身几何结构的功能。点云几何结构 不仅是宏观的几何外形,也包括其微观的排列方式,比如横向相似的尺寸,纵向相同的距离。随机下采样虽然效率比体素滤波器高,但会破坏点云微观结构。
4、 均匀降采样:半径球体内保留一个点(重心点)
5、统计过滤器StatisticalOutlierRemoval
激光扫描通常会产生密度不均匀的点云数据集,另外测量中的误差也会产生稀疏的离群点,此时,估计局部点云特征(例如采样点处法向量或曲率变化率)时运算复杂,这会导致错误的数值,反过来就会导致点云配准等后期的处理失败。
解决办法:对每个点的邻域进行一个统计分析,并修剪掉一些不符合标准的点。具体方法为在输入数据中对点到临近点的距离分布的计算,对每一个点,计算它到所有临近点的平均距离(假设得到的结果是一个高斯分布,其形状是由均值和标准差决定),那么平均距离在标准范围之外的点,可以被定义为离群点并从数据中去除。
6、投影滤波
投影滤波器就是输入点云和投影模型,输出为投影到模型上之后的点云。
参考链接:https://blog.csdn.net/luolaihua2018/article/details/120238586
7、球半径过滤器RadiusOutlinerRemoval
球半径滤波器与统计滤波器相比更加简单粗暴。
以某点为中心 画一个球计算落在该球内的点的数量,当数量大于给定值时,则保留该点,数量小于给定值则剔除该点。
此算法运行速度快,依序迭代留下的点一定是最密集的,但是球的半径和球内点的数目都需要人工指定。
RadiusOutlinerRemoval比较适合去除单个的离群点 ConditionalRemoval 比较灵活,可以根据用户设置的条件灵活过滤。
8、条件过滤器 ConditionalRemoval
可以一次删除满足对输入的点云设定的一个或多个条件指标的所有的数据点。或者删除点云中不符合用户指定的一个或者多个条件的数据点。
不在条件范围内的点被替换为nan
pcl::removeNaNFromPointCloud()去除Nan点
9、模型过滤器
modeloutlierremoval是基于模型和点之间的距离过滤点云中的噪点。对整个输入迭代一次,自动过滤非有限点以及setsampleconsensusmodelpointer()指定的模型之外的点,和setthreholdfunctionpointer()指定的阈值。
过滤:统计过滤器
修改官网提供程序并设置参数如下:
/*
过滤:统计过滤器
*/
#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( "../pork/before1.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 (3.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("/home/sun/Filtering/pork/statisticaloutlierremoval/before1_inliers.pcd",*cloud_filtered_ptr, false);
// 保存外点 被滤出的点
sta.setNegative (true);
sta.filter (*cloud_filtered_ptr);
writer.write<pcl::PointXYZ> ("/home/sun/Filtering/pork/statisticaloutlierremoval/before1_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);
}
结果如下:
下采样:体素格降采样
修改官网提供程序并设置参数如下:
/*
下采样:体素格降采样
*/
#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( "/home/sun/Filtering/pork/statisticaloutlierremoval/before1_inliers.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;
// pcl::ApproximateVoxelGrid<pcl::PointXYZ> avg;
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("../pork/voxelgrid/before1_inliers_downsampled.pcd",*cloud2_filtered_ptr,
Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false);
// 调用系统可视化命令行显示
system("pcl_viewer /home/sun/Filtering/pork/statisticaloutlierremoval/before1_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);
}
结果如下:
报错
Could not find file ’ …/before1_inliers’.
段错误(核心已转储)
解决方法
反复检查文件路径,没有问题;反复修改文件位置,仍然报错;检查是否用其他应用打开,发现没有;最后将代码全部删除,重新复制官网代码,根据文件位置修改,编译运行,发现没有问题了,离大谱。