本篇内容
- 通过PCD文件介绍点云数据
- 如何通过PCL库读取和保存PCD点云数据文件
1 点云数据
最简单的点云数据就是一堆三维坐标点(x,y,z),除了坐标还可以记录每个点的颜色信息(r,g,b),或者强度信息(intensity)等
2 PCD文件详解
把一个pcd文件放入vscode中,如下图所示:
PS:要保证pcd文件是通过ascii类型,如果是二进制类型,通过vscode打开则是乱码
- VERSION
指定pcd文件的版本 - FIELDS
指定数据区每个数据所代表的意义,从上述示图中可以看到,数据区每行有4个float类型的数字,通过空格隔开,分别代表x坐标、y坐标、z坐标、强度值 - SIZE
指定每个数据所占用的字节大小,float类型占用4个字节 - TYPE
指定每个数据的类型,F代表float - COUNT
抱歉,不知道代表什么意义,但是平时也没用到 - WIDTH
对于无序点云,WIDTH等于点云总数量;对于有序点云(通过深度相机采集),WIDTH等于图像宽度 - HEIGHT
对于无序点云,HEIGHT等于1;对于有序点云,HEIGHT等于图像高度 - POINTS
点云总数量 - VIEWPOINT
指定观测视角,例如通过pcl_viewer打开pcd文件时,通过VIEWPOINT可以决定默认是从左边观测或是从其他方向观测。它本质上是一个位姿,由平移tx,ty,tz和四元数qw,qx,qy,qz组成 - DATA
指定数据类型:ascii或binary
3 通过PCL读取点云文件
3.1 理解点云类型
大家对C++的vector很熟悉,声明一个vector变量方式如下:
std::vector<int> v; //一个存储一堆int类型数据的vector
在PCL库中声明一个用于保存点云数据的变量方式如下:
pcl::PointCloud<pcl::PointXYZ> cloud; //一个存储一堆pcl::PointXYZ类型数据的PointCloud
pcl::PointXYZ等价于int,用于描述每个点的类型,示例中就表示每个点只包含(x,y,z)坐标。Pcl库还提前定义了很多点云类型,这些点云类型对应了第2节中的FIELDS,FIELDS包含较多的信息,就可以更换对应的点云类型,通常至少会包含x,y,z,如下图所示:
3.2 读取点云文件流程
声明点云变量:
- 由于点云文件通常占用内存较大,因此一般申请为指针
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
读取点云文件:
pcl::io::loadPCDFile<pcl::PointXYZ>(pcd_file_path, *cloud);
保存点云文件:
pcl::io::savePCDFileASCII(pcd_save_path, *cloud);
调试过程:
通过cloudcompare软件打开需要读取的pcd文件,可以看到这份pcd文件包含了397个点
代码debug,成功读取:
4 完整代码
#include <string>
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
int main(int argc, char **argv)
{
if (argc < 3) {
std::cout<<"Usage: ./read_pcd <pcd_file_path> <pcd_save_path>\n";
return -1;
}
std::string pcd_file_path(argv[1]);
std::string pcd_save_path(argv[2]);
// 声明变量,用于保存点云数据
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 读取pcd点云文件
if (pcl::io::loadPCDFile<pcl::PointXYZ>(pcd_file_path, *cloud) == -1) {
std::cerr<<"check pcd path\n";
return -1;
}
// 打印点云info
std::cout<<"pcd size:"<<cloud->size()<<"\n";
std::cout<<"pcd width:"<<cloud->width<<"\n";
std::cout<<"pcd height:"<<cloud->height<<"\n";
// 保存点云数据
pcl::io::savePCDFileASCII(pcd_save_path, *cloud);
return 0;
}