PCL C++版【学习备忘】

一、PCL基础及相关介绍

1、PCL官网及教程用例

请点击—> PCL官网链接 <-----&&&----->PCL教程用例

2、PCL中各个模块介绍

请点击—> PCL-简介(包含各个模块介绍)

PCL包含的模块:
libpcl filters:如采样、去除离群点、特征提取、拟合估计等数据实现过滤器;
libpcl features:实现多种三维特征,如曲面法线、曲率、边界点估计、矩不变量、主曲率,
        PFH和FPFH特征,旋转图像、积分图像,NARF描述子,RIFT,相对标准偏差,数据强度的筛选等等;
libpcl I/O:实现数据的输入和输出操作,例如点云数据文件(PCD)的读写;
libpcl segmentation:实现聚类提取,如通过采样一致性方法对一系列参数模型(如平面、
         柱面、球面、直线等)进行模型拟合点云分割提取,提取多边形棱镜内部点云等等;
libpcl surface:实现表面重建技术,如网格重建、凸包重建、移动最小二乘法平滑等;
libpcl register:实现点云配准方法,如ICP、NDT等;
libpcl keypoints:实现不同关键点的提取方法,可用来作为预处理步骤,决定在哪儿提取特征描述符;
libpcl range :实现支持不同点云数据集生成的范围图像。

3、PCL编程风格

请点击-> PCL编程风格

二、PCL中 I/O 模块

//所需头文件
#include <iostream>           //标准 C++ 库中的输入输出类相关头文件
#include <pcl/io/pcd_io.h>    //PCD 读写类相关的头文件
#include <pcl/point_types.h>  //PCL 中支持的点类型头文件

1、PCD文件相关介绍

&&&& PCD文件头 必须用ASCII码来编写。在连接两个不同点云为一个点云之前。要确保两个数据集中字段的类型相同和维度相同。

pcd文件头 示例值 含义
VERSION 0.7 指定 PCD 文件版本为 0.7
FIELDS x y z intensity 指定点的每一个维度的名称(x, y, z, intensity)
SIZE 4 4 4 4 以字节为单位指定每个维度的大小(
unsigned char/char 1字节
unsigned short/short 2字节
unsigned int/int/float 4字节
double 8字节
TYPE F F F F 用一个字符指定每一个维度的类型(目前支持的类型有:
I 表示有符号类型int8 ( char ), int16 ( short ) , int32 ( int )
U 表示无符号类型uint8 ( unsigned char ), uint16 ( unsigned short ) , uint32 ( unsigned int )
F 表示浮点型 .
COUNT 1 1 1 1 指定每个维度有多少个元素。例如,x 数据通常有 1 个元素,但像 VFH 这样的特征描述符有 308 个。基本上这是一种在每个点引入 n 维度直方图描述符,并将它们视为单个连续内存块的方法。默认情况下,如果 COUNT 不存在,则所有维度的计数都设置为 1。
WIDTH 69088 以点数指定点云数据集的宽度。有序点云数据集是对类似于有序的图像(或矩阵)结构的点云的名称,其中数据被分成行和列。此类点云的示例包括来自立体相机或飞行时间相机的数据。有组织的数据集的优点在于,通过了解相邻点(例如像素)之间的关系,最近邻操作的效率要高得多,从而加快了计算速度并降低了 PCL 中某些算法的成本。宽度有两个含义
1)它可以为无序数据集指定点云中的总点数(等于 POINTS,见下文);
2)它可以指定有组织的点云数据集的宽度(一行中的总点数)
HEIGHT 1 以点数指定点云数据集的高度。高度有两个含义
1)它可以指定一个有序的点云数据集的高度(总行数)
2)对于无序数据集,它被设置为 1(因此用于检查数据集是否有序)。
VIEWPOINT 0 0 0 1 0 0 0 指定数据集中点的采集视点。VIEWPOINT有可能在不同坐标系之间转换的时候应用,在辅助获取其他特征时,也比较有用,例如曲面法线,在判断方向一致时,需要知道视点的方位。视点信息被指定为平移(txtytz)+ 四元数(qwqxqyqz),默认值如左所示。
POINTS 69088 指定点云中点的总数。从 0.7 版本开始,它的目的有点多余,所以我们希望在未来的版本中删除它。
DATA binary 指定存储点云数据的数据类型。从 0.7 版本开始,支持两种数据类型:ASCII 和 binary(二进制)。

2、加载 PointCloud 数据,两种方式

(1)
pcl::PointCloud <pcl::PointXYZ>::Ptr cloud( new pcl::PointCloud<pcl::PointXYZ> );
sensor_msgs::PointCloud2 cloud_blob; // PointCloud2 适合版本低的点云文件
pcl::io::loadPCDFile("test_pcd.pcd", cloud_blob);
(2)
pcl::PCDReader reader;	//定义点云读取对象
if (reader.read("test.pcd", *cloud_in) < 0)
{
	PCL_ERROR("\a->点云文件不存在!\n");
	system("pause");
	return -1;
}
 
pcl::fromROSMsg(cloud_blob, *cloud); //  sensor_msgs/PointCloud2 转换为 pcl::PointCloud <T>
PCL中点云数据类型 描述
pcl::PointCloud <pcl::PointXYZ> cloud PointXYZ 成员:float x,y,z;
表示了xyz3D信息,可以通过points[i].data[0]或points[i].x访问点X的坐标值
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr( new pcl::PointCloud<pcl::PointXYZ> ); 相互转换链接(可点击)
cloud = *cloud_ptr;
cloud_ptr = cloud.makeShared();
pcl::PointCloud<pcl::PointXYZI> PointXYZI成员:float x, y, z, intensity;
表示XYZ信息加上强度信息的类型。
pcl::PointCloud<pcl::PointXYZRGB> PointXYZRGB 成员:float x,y,z,rgb;
表示XYZ信息加上RGB信息,RGB存储为一个float。
pcl::PointCloud<pcl::PointXYZRGBA> PointXYZRGBA 成员:float x , y, z; uint32_t rgba;
表示XYZ信息加上RGBA信息,RGBA用32bit的int型存储的。

3、解析rosbag文件得到pcd文件和查看pcd文件

3.1 解析rosbag文件(命令)
// [命令实现] 解析rosbag文件得到带时间戳的.pcd点云数据文件 在rosbag数据包所在文件夹下新建pcd文件夹,新建终端输入如下命令可实现pcd文件的解析。 rosrun pcl_ros bag_to_pcd <*.bag(path)> <topic> <output_directory> 示例如下: rosrun pcl_ros bag_to_pcd lidar.bag /lidar_top ./pcd

3.2 查看.pcd文件

// [命令实现] 
pcl_viewer [pcd文件名]
// sudo apt install pcl-tools

3.3 解析rosbag文件(代码)
以下代码参考:C++读取rosbag并转pcd和bin文件

// [代码实现] 
从rosbag 中提取pcd文件数据(部分代码)
int frame_cnt = 0;
rosbag::Bag bag;
bag.open(path, rosbag::bagmode::Read); //open *.bag
std::vector<std::string> topics; //set topics which you want to read
topics.push_back(std::string("/iv_points2")); //这个是我指定要读取的消息topic
rosbag::View view(bag, rosbag::TopicQuery(topics));; //read defined topics
for (rosbag::MessageInstance const m : view) 
{
    
    
    sensor_msgs::PointCloud2::ConstPtr input = m.instantiate<sensor_msgs::PointCloud2>();
    ++frame_cnt;
    if (input == NULL) {
    
     continue; }
    bool do_convert = true;
    pcl::PointCloud<pcl::PointXYZI> cloud;//定义转换的点云数据类型
    pcl::fromROSMsg(*input, cloud);
    //...//省略的代码...
}

三、 PCL中REGISTER(配准)模块

1、ICP

ICP算法英文全称为iterative closest point,即最近点迭代算法。该算法用于具有公共点的两幅点云间的匹配或者点云与模型的匹配问题。
ICP算法本质上是基于 最小二乘法 的最优配准方法。该算法重复进行选择对应关系点对, 计算最优刚体变换,直到满足正确配准的收敛精度要求。
请点击–> PCL中的点云配准(Registration)ICP算法

2、NDT

NDT全称为Normal Distributions Transform,正态分布转换,属于用 非线性优化方法 解决Slam中帧间匹配算法中的一种。阅读论文:The Normal Distributions Transform: A New Approach to Laser Scan Matching,熟悉NDT算法的整个流程。
请点击–> 正态分布变换(NDT)配准与无人车定位

X、PCL中类与函数汇总(列表)

PCL类的分类 PCL中类以及函数 描述
可视化类 pcl::visualization::PCLVisualizer

点云视窗类CloudViewer和PCLVisualizer区别
创建普通类对象: pcl::visualization::CloudViewer viewer(“Cloud Viewer”);
创建共享指针对象:boost::shared_ptr< pcl::visualization::PCLVisualizer > viewer(new pcl::visualization::PCLVisualizer(“3D Viewer”));
需包含头文件:#include <pcl/visualization/pcl_visualizer.h>
可视化类中的函数(可点击)
可视化类 viewer->registerKeyboardCallback (keyboardEventOccurred, (void*)&viewer);
viewer->registerMouseCallback (mouseEventOccurred, (void*)&viewer);
可视化类 pcl::visualization::CloudViewer 创建普通类对象:pcl::visualization::CloudViewer viewer(“Cloud Viewer”);
vieweraddPointClout(cloud_ptr, “sample_cloud”);
需包含头文件:#include <pcl/visualization/cloud_viewer.h>
随机颜色 pcl::visualization::PointCloudColorHandlerRandom<pcl::PointXYZ> pcl::visualization::PointCloudColorHandlerRandom<pcl::PointXYZ> RandomColor(Cloud(指针类型));
定制颜色 pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> custom_color(cloud(指针类型), 0, 0, 255);
模型系数 pcl::ModelCoefficients 指针类型(两种:Ptr,ConstPtr):pcl::ModelCoefficients::Ptr coefficients( new pcl::ModelCoefficients );
创建分割时所需要的模型系数对象,coefficients,
需包含头文件:#include <pcl/ModelCoefficients.h>
点数据索引 pcl::PointIndices 指针类型(两种:Ptr,ConstPtr):pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
创建分割时,用来保存分割后点云的数据索引
需包含头文件:#include <pcl/PointIndices.h>
聚类提取(分割) 类 pcl::SACSegmentation<pcl::PointXYZ > pcl::SACSegmentation<pcl::PointXYZ> seg;
需包含头文件:#include <pcl/segmentation/sac_segmentation.h> //基于采样一致性分割的类的头文件
from官网
pcl::SACSegmentationFromNormals<pcl::PointXYZRGBA, pcl::Normal> 初始化对象:pcl::SACSegmentationFromNormals<pcl::PointXYZRGBA, pcl::Normal> seg;
配准函数ICP pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp
需包含头文件:#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
配准函数NDT-案例讲解 pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ>

pcl::NormalDistributionsTransform< PointSource, PointTarget >
初始化正态分布变换(NDT)from官网:pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ> ndt;
//设置依赖尺度NDT参数
//为终止条件设置最小转换差异
ndt.setTransformationEpsilon(0.01);
//为More-Thuente线搜索设置最大步长
ndt.setStepSize(0.1);
//设置NDT网格结构的分辨率(VoxelGridCovariance)
ndt.setResolution(1.0);
//设置匹配迭代的最大次数
ndt.setMaximumIterations(35);
// 设置要配准的点云
ndt.setInputCloud(filtered_cloud);
//设置点云配准目标
ndt.setInputTarget(target_cloud);
ndt.align (PointCloudSource &output, const Matrix4 &guess);
需包含头文件:#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/ndt.h> //NDT配准类对应头文件
#include <pcl/filters/approximate_voxel_grid.h> //滤波类对应头文件
#include <pcl/visualization/pcl_visualizer.h>//可视化头文件
#include <boost/thread/thread.hpp>//多线程相关头文件
pcl::PCDReader pcl::PCDReader reader;
pcl::io::loadPCDFile(“pcd_path”, Cloud(非指针类型)); //读入点云数据
pcl::io::savePCDFile<pcl::PointXYZ> (“pcd_path”, cloud_filter(非指针类型)); pcl::io::savePCDFile<pcl::PointXYZ> (“demo_filter.pcd”, cloud_filter);
pcl::io::savePCDFileASCII pcl::io::savePCDFileASCII (“test_pcd.pcd”, cloud(非指针类型));
需包含头文件:#include <pcl/io/pcd_io.h> //PCD读写类相关的头文件
pcl::io::savePCDFileBinary()
pcl::PCDWriter pcl::PCDWriter writer;
pcl::ApproximateVoxelGrid<pcl::PointXYZI> pcl库中的VoxelGrid对点云进行体素化,主要就是创建一个三维体素栅格(就是每个比较小的立方体组成的体素栅格)。
初始化创建对象:pcl::ApproximateVoxelGrid<pcl::PointXYZI> avg;
直通滤波类 pcl::PassThrough<pcl::PointXYZ> 初始化滤波器对象:pcl::PassThrough<pcl::PointXYZ> pass;
成员函数:
pass.setInputCloud(cloud); //设置待滤波的点云
pass.setFilterFieldName(“z”); //设置在Z轴方向上进行滤波
pass.setFilterLimits(0, maxPt.z - 12); //设置滤波范围(从最高点向下12米去除)
pass.setFilterLimitsNegative(false); //保留
pass.filter(cloud_filter(非指针类型)); //滤波并存储
pcl几种滤波方法 点云滤波方法:直通滤波器、体素滤波器、统计滤波器、条件滤波器、半径滤波器。
pcl::NormalEstimation< PointInT, PointOutT > //创建法线估计对象:pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne1;
所需头文件:#include <pcl/features/normal_3d.h>
pcl::search::KdTree<pcl::PointXYZ>::Ptr
它的子类:pcl::KdTreeFLANN<pcl::PointXYZ>
// 定义初始化KDTree对象:pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
所需头文件:#include <pcl/search/kdtree.h>
保存点云索引 pcl::PointIndices pcl::PointIndices inliers;
pcl::ExtractIndices<pcl::PointXYZ> //实例化一个提取对象:pcl::ExtractIndices<pcl::PointXYZ> extract;
需包含头文件:#include <pcl/filters/extract_indices.h>
pcl::ProjectInliers<pcl::PointXYZ> //创建投影滤波对象: pcl::ProjectInliers<pcl::PointXYZ> proj;
作用:点云投射;
需包含头文件:#include <pcl/filters/project_inliers.h>
聚类提取 pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> boundEst;
同时,需要pcl::NormalEstimation先计算法线
需包含头文件:#include <pcl/features/boundary.h>
滤波器移除离群点 pcl::StatisticalOutlierRemoval<pcl::PointXYZ > 创建滤波器对象:pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
需包含头文件:#include <pcl/filters/statistical_outlier_removal.h> //滤波相关
void pcl::fromROSMsg ( const sensor_msgs::PointCloud2 & cloud, pcl::PointCloud< T > & pcl_cloud )
需包含头文件:#include <pcl_conversions/pcl_conversions.h>
#include <pcl/conversions.h>
#include <pcl_ros/transforms.h>
pcl::toROSMsg ( pcl::PointCloud<pcl::PointXYZ>, sensor_msgs::PointCloud2 );
pcl::Grabber 采集的类,此类还有很多派生类
void pcl::transformPointCloud ( const pcl::PointCloud< PointT > & cloud_in, pcl::PointCloud< PointT > & cloud_out, const Eigen::Matrix< Scalar, 4, 4 > & transform, bool copy_all_fields = true ) 应用由4x4矩阵定义的刚性变换。from官网
点云降采样 点云降采样分为:(1)体素降采样(2) 随机降采样(3)均匀降采样
VoxelGrid体素采样(内含三个类的区别) pcl::VoxelGrid<pcl::PointXYZ> from官网,pcl库中的VoxelGrid对点云进行体素化,主要就是创建一个三维体素栅格(就是每个比较小的立方体组成的体素栅格)。在每个体素(三维立方体)里面,求取该立方体内的所有点云重心点来代表这个立方体的表示,以此达到下采样的目的。
VoxelGrid体素采样 pcl::VoxelGrid<pcl::PCLPointCloud2> 其中,举例:
pcl::VoxelGrid<pcl::PCLPointCloud2> voxel_filter; // 创建滤波器对象
voxel_filter.setLeafSize (0.01f, 0.01f, 0.01f); //设置滤波时创建的体素大小为1cm立方体(单位:米)
VoxelGrid体素采样 pcl::ApproximateVoxelGrid<pcl::PointXYZ> from官网
pcl::copyPointCloud()
另种用法:pcl::copyPointCloud<Velodyne::Point>(*edges_cloud, inliers2, *pattern_cloud)
改变点云中点的类型用法,请点击 && 用法from官网
欧式聚类分割类 &&–概念原理 -&&-from官网讲解 pcl::EuclideanClusterExtraction< PointT > 需包含头文件:#include <pcl/segmentation/extract_clusters.h>
from官网
计算欧式距离 pcl::euclideanDistance( const PointType1 & p1, const PointType2 & p2 ) 计算已知两个点的欧式距离。
from官网
求两线的交点 bool pcl::lineWithLineIntersection ( const Eigen::VectorXf & line_a, const Eigen::VectorXf & line_b, Eigen::Vector4f & point, double sqr_eps = 1e-4 ) 获取空间中两条三维直线的交点。
需包含头文件:#include <pcl/common/impl/intersections.hpp>
pcl::SampleConsensusModelPlane< PointT > 用于定义三维平面分割的模型。
所需头文件:#include <pcl/sample_consensus/sac_model_plane.h>
pcl::console::setVerbosityLevel() setVerbosityLevel用于设置控制台输出的信息。(pcl::console::L_ALWAYS)不会输出任何信息; L_DEBUG会输出DEBUG信息; L_ERROR会输出ERROR信息。from官网
pcl::getMinMax3D() Get the minimum and maximum values on each of the 3 (x-y-z) dimensions in a given pointcloud.

XXX、多库合作知识(额外知识)

1、ROS消息数据与PCL数据相互转换

在ROS中表示点云的数据结构有:sensor_msgs::PointCloud, sensor_msgs::PointCloud2。
pcl::PointCloud 关于PCL在ros数据的结构,具体的介绍可查看 此链接(fromROS官网)
关于sensor_msgs::PointCloud2 和 pcl::PointCloud<PointT>之间的转换,使用
pcl::fromROSMsg()pcl::toROSMsg()
sensor_msgs::PointCloud 和 sensor_msgs::PointCloud2之间的转换,使用
sensor_msgs::convertPointCloud2ToPointCloudsensor_msgs::convertPointCloudToPointCloud2

2、拼接点云

请点击–> PCL系列——拼接两个点云

3、PCL的指针说明

请点击–> PCL之指针Ptr详解

猜你喜欢

转载自blog.csdn.net/expert_joe/article/details/123342098
pcl