PCD文件介绍
PCL以PCD文件形式保存点云。 (主要是为了保存n维点类型)
其文件格式如下:
每一个PCD文件都包含一个文件头,它确定和声明文件中存储的点云数据的某种特性。
PCD文件头必须使用ASCII码来编码。PCD文件中指定的每一个文件头字段以及ASCII点数据都用一个新行(\n)分开了。
从0.7版本开始,PCD文件头包含下面的这些字段
- VERSIO:指定PCD文件版本
- FEIELDS:指定一个点可以有的每一个维度和字段的名字。例如
FEIELDS x y z # XYZ data
FEIELDS x y zrgb # XYZ+colors
- SIZE: 用字节数指定每一个维度的大小
unsigned char/char/ 1个字节
unsigned short/short 2个字节
unsigned int/int/float 4个字节
double 8个字节
- TYPE:用要给字符指定每一个维度的类型。可以使用的类型有:
I 表示有符号类型 int8(char)、int16(short)、int32(int)
U 表示无符号类型 uint8(unsigned char)、uint16(unsigned short)、uint32(unsigned int)
F 表示 浮点型
- COUNT:指定每一个维度包含的元素数目。x这元素就是1.默认没有COUNT ,所有维度数目设置为1
- WIDTH:用点的数量表示点云数据集的宽度。根据是有序点云还是无序点云。有序就是一行的宽度,无序就是点云总个数
- HEIGHT: 用点的数量表示点云数据集的高度。被用于检查有序还是无序。无序为1 ,有序为高度
//有序点云
WIDTH 640 #像图像一样的有序结构 640*480
HEIGHT 480
//无序点云
WIDTH 307200
HEIGHT 1 # 无序点 共 307200个
- VIEWPOINT:指定数据集中点云的获取视点。在不同坐标系转换的时候用到。 平移+四元数 默认为 VIEWPOINT 0 0 0 1 0 0 0
- DATA :指定存储点云数据的数据类型。
从PCD文件中读点云数据
需要包含的头文件
创建一个点云变量 的共享指针 并实例化
从 pcd文件 读取 点云
如果没有读到 报错相关信息 结束进程
这里要重点说明下 loadPCDFile 这个函数了 。 这个就是 pcl 里面 从PCD文件读取点云的核心函数
结合上面的例子 用法就是:
pcl::io::loadPCDFile< 点云类型 >(PCD文件路径,读取后存入的 地址指向)
计算点云数量 打印相关信息
Code
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
int main(int argc,char** argv)
{
/*创建一个点云变量 的共享指针 并实例化*/
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
/*从 pcd文件 读取 点云*/
if(pcl::io::loadPCDFile<pcl::PointXYZ>("../test_pcd.pcd",*cloud)==-1)
{
// 返回值是 -1 代表 没有读到
PCL_ERROR("Couldn't read file test_pcd.pcd \n");
return (-1);
}
//计算点云数量 打印相关信息
std::cout<<"Loaded "<<cloud->width*cloud->height<<" data points from test_pcd.pcd with the following fields: "<<std::endl;
/*遍历输出 各点云的内容*/
for(size_t i=0;i<cloud->points.size();++i)
{
std::cout<<" "<<cloud->points[i].x
<<" "<<cloud->points[i].y
<<" "<<cloud->points[i].z<<std::endl;
}
return(0);
}
Result
原pcd
读取终端 显示 内容
从PCD读取自定义的点云类型
上面的例子是 读取 pcl原定义好的点云类型
如果像之前我们 定义了 新的点云类型,此时 如何读取?
此时需要在 main函数前 加上 自己的点云定义
struct MyPointType //定义点类型结构
{
PCL_ADD_POINT4D; //该点类型有4个元素
/*尝试新增一个自定义*/
float JoneAdd; //定义自己新增的类型名称
//测试了添加这么多个也没问题
float JoneAdd1;
float JoneAdd2;
float JoneAdd3;
float JoneAdd4;
float JoneAdd5;
float JoneAdd6;
float JoneAdd7;
float JoneAdd8;
float JoneAdd9;
EIGEN_MAKE_ALIGNED_OPERATOR_NEW //确保new操作符对齐操作
}EIGEN_ALIGN16; //强制SSE 对齐
POINT_CLOUD_REGISTER_POINT_STRUCT(MyPointType, //注册点类型宏
(float ,x,x)
(float ,y,y)
(float ,z,z)
(float ,JoneAdd,JoneAdd)
(float ,JoneAdd,JoneAdd1)
(float ,JoneAdd,JoneAdd2)
(float ,JoneAdd,JoneAdd3)
(float ,JoneAdd,JoneAdd4)
(float ,JoneAdd,JoneAdd5)
(float ,JoneAdd,JoneAdd6)
(float ,JoneAdd,JoneAdd7)
(float ,JoneAdd,JoneAdd8)
(float ,JoneAdd,JoneAdd9)
)
或者 定义在 一个.hpp文件里面 。 引用这个文件
然后 函数里面的 内容 改成 如下 形式
那么如果 加载的pcd 文件不是 我们 定义 的点云类型 会怎么办 ?
出现下面的结果
设置 打印 信息 如下
原PCD文件
终端打印读取信息