PCL点云库入门——PCL库中点云数据格式PCD和PLY及其输入输出(IO)
1、前言
根据PCL点云库的IO模块信息,目前PCL库中支持PCD、PLY、OBJ、IFS和PNG等多种文件格式的读取与写入。然而,支持的文件类型相对有限。在本节中,我们将重点讲解和阐释PCL库中最为常用的PCD和PLY文件格式。
2、PCD数据格式
PCD文件,是由PCL库所提供的一种文件格式,它支持两种主要的存储方式:ASCII(文本)格式和二进制格式。ASCII格式便于查看和编辑点云中的点信息,但文件大小相对较大;相比之下,二进制格式虽然占用空间较小,但不便于直接查看点云中各个点的具体信息。
一个PCD文件由两部分组成:头部(header)和数据体(data body)。头部部分包含了点云文件的基本信息,而数据体部分则存储了点云中所有点的详细信息。
2.1、PCD文件头信息
PCD文件的头部信息比较简单,具体信息如下:
字段名称 | 字段描述 |
VERSION | 文件格式的版本信息 |
FIELDS | 点云数据的字段名称,例如 x, y, z, intensity |
SIZE | 每个字段的大小(以字节为单位) |
TYPE | 每个字段的数据类型,例如 F(浮点型)、U(无符号整型,常用于颜色信息) |
COUNT | 每个字段的元素个数,通常是 1 |
WIDTH | 点云数据的宽度 |
HEIGHT | 点云数据的高度,如果是 1 则表示无序点云。 |
VIEWPOINT | 相机视点信息(通常用于三维重建) |
POINTS | 点云中的点的总数 |
DATA | 数据存储的格式,如 ascii、binary、binary_compressed |
PCD 文件头部示例: |
# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 100
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 100
DATA ascii
2.2、PCD数据体
PCD文件数据体包含了点云中点的所有信息, 根据头部的描述的 ASCII 或二进制格式存储,
ASCII格式以为文本形式存储,每个点以行顺序排列,示例为(X Y Z )如下:
4.3903928 4.0623188 7.8344064
9.2648087 8.4102907 0.63966799
0.024109622 3.431196 4.1898861
6.9972839 4.2567215 7.6363416
0.41810358 3.1290629 7.3696098
5.9019747 6.4213996 1.8802453
3.3515427 3.6896877 8.5329752
. . .
从上面可知,PCD文件格式比较简单,掌握起来比较容易。
2.3 、PCL库PCD文件的输入和输出(IO)示例
PCL 的 IO 模块提供了读取和写入 PCD 文件的功能,在文件中#include <pcl/io/pcd_io.h>,下面示例演示用PCL库完成PCD点云文件的输出和输入操作。
1)、PCD文件输出(save)代码示例,新建testPCL_io.cpp,内容如下:
/*****************************************************************//**
* \file testPCL_io.cpp
* \brief
*
* \author YZS
* \date December 2024
*********************************************************************/
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
// 创建点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 随机生成点云数据
srand(static_cast<unsigned int>(time(NULL)));
for (int i = 0; i < 100; ++i)
{
pcl::PointXYZ point;
point.x = 10.0f * rand() / RAND_MAX; // 在 x 方向上点坐标
point.y = 10.0f * rand() / RAND_MAX; // 在 y 方向上点坐标
point.z = 10.0f * rand() / RAND_MAX; // 在 z 方向上点坐标
cloud->push_back(point);
}
//输出点云数目
std::cout << "Point Sizes:" << cloud->points.size() << std::endl;
//保存ASCII文件
pcl::io::savePCDFileASCII("output_ascii.pcd", *cloud);
//保存二进制文件
pcl::io::savePCDFileBinary("output_Binary.pcd", *cloud);
//或者
//二进制文件
//pcl::io::savePCDFile("testPCL_io.pcd", *cloud, true);
//ASCII文件
//pcl::io::savePCDFile("testPCL_io.pcd", *cloud, false);
std::cout << "Save Done!" << std::endl;
std::system("pause");
return 0;
}
2)、PCD文件输入(load):
/*****************************************************************//**
* \file testPCL_io.cpp
* \brief
*
* \author YZS
* \date December 2024
*********************************************************************/
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
// 创建点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
//PCD文件名
std::string filePCD = "test_pcd.pcd";
//打开点云文件
if (pcl::io::loadPCDFile<pcl::PointXYZ>(filePCD, *cloud) == -1)
{
PCL_ERROR("Couldn't read file test_pcd.pcd \n");
return (-1);
}
//打印输出点云数目
std::cout << " Point Sizes:" << cloud->points.size() << std::endl;
//打印输出所有点信息
for (size_t i = 0; i < cloud->points.size(); ++i)
{
std::cout << " Point:" << cloud->points[i] << std::endl;
}
std::cout << "Load Done!" << std::endl;
std::system("pause");
return 0;
}
3、PLY数据格式
在PCL库中另外比较常用的文件格式是PLY格式,他的全称为Polygon File Format,是一种用于存储三维点云数据和多边形网格的文件格式。它由斯坦福大学的Greg Turk和Perry Schein提出,因此PLY格式也被称为斯坦福三角格式,旨在提供一种简单、灵活且易于扩展的方式来存储三维图形数据。PLY文件格式支持多种属性,如顶点坐标、颜色、法线、纹理坐标等,并允许用户自定义属性。
PLY文件也两有种类型:ASCII和二进制。它们的优缺点与PCD文件类似,因此这里不再赘述。PLY文件的结构与PCD文件相似,由头部(Header)和数据体(Body)组成,头部通过过定义带有一组“属性”的“元素”来指定文件中的数据,因此头部信息比PCD文件更为复杂。PLY更侧重于三维模型数据,而PCD专注于点云数据。
3.1 、PLY文件头信息
一个PLY文件头部信息如下表,相对PCD文件头的复杂 。
ply | 文件符号 ,表明它是一个ply文件。 |
format binary_big_endian 1.0 | 指定数据格式和版本 |
element vertex 9200 | “顶点”元素 |
property float x | 属性 x |
property float y | 属性 y |
property float z | 属性 z |
element face 18000 | “面”元素 |
property list uchar int vertex_indices | |
end_header | data starts after this line |
该文件以“ply”开头,表明它是一个ply文件。头文件还必须包含带有语法的格式。
format <data format> <PLY version>
支持的数据格式为:以文本形式存储的数据为“ascii”,二进制数据为“binary_little_endian”和“binary_big_endian”
如表中,“element vertex 9200”定义了一个元素“vertex”,并指定在文件中存储9200个顶点。每个元素定义后紧跟该元素的属性列表。有两种属性,标量和列表。标量属性定义具有以下语法:
property <data type><property name>
其中<data type>支持以下类型:
类型 | 描述 |
char | (8-bit) character |
uchar | (8-bit) unsigned character |
short | (16-bit) short integer |
ushort | (16-bit) unsigned short integer |
int | (32-bit) integer |
uint | (32-bit) unsigned integer |
float | (32-bit) single-precision float |
double | (64-bit) double-precision float |
为了系统间的兼容性,请注意每种数据类型的位数必须一致。列表类型的存储方式是一个计数后跟一个标量列表。列表属性的语法如下:
property list <count data type><data type><property name>
如表中的: property list uchar int vertex_index,定义vertex_index属性以字节计数开头,后跟整数值。这对于存储多边形数据很有用,因为它可以灵活地在每个面指定可变数量的顶点索引。
头文件还可以包含注释。注释的语法是简单的一行,以“comment”开头,后跟一行注释,语法如下:
comment<comment text>
注释可以提供关于数据的信息,比如文件的作者、数据描述、数据源和其他文本数据。如:
comment Created by CloudCompare v2.12 alpha
完整的PLY文件头示例如下:
ply
format ascii 1.0
comment PCL generated
obj_info Generated by CloudCompare!
element vertex 355
property float x
property float y
property float z
property float nx
property float ny
property float nz
end_header
3.2、PLY数据体
在PLY文件头之后,元素数据存储为ASCII或二进制数据(由标头中的格式行指定)。在标头之后,数据按照定义元素和属性的顺序存储。首先,存储第一个元素类型的所有数据。在示例头文件中,第一个元素类型是“vertex”,文件中有9200个顶点,顶点属性为float类型的 “x”,“y”和“z”。通常,每个元素的属性数据按照以下方式存储:
<property 1><property 2> ... <property N> element[1] |
<property 1><property 2> ... <property N> element[2] |
列表类型属性以一个计数开头,后跟一个标量列表。例如,“face”元素类型具有uchar计数和int标量类型的列表属性“vertex_indices”。
uchar count |
int face[1].vertex_indices[1] |
int face[1].vertex_indices[2] |
int face[1].vertex_indices[3] |
... |
int face[1].vertex_indices[count] |
uchar count |
int face[2].vertex_indices[1] |
int face[2].vertex_indices[2] |
int face[2].vertex_indices[3] |
... |
int face[2].vertex_indices[count] |
PLY数据体:
0.187609 0.093643 0.039663 -0.649805 0.449351 -0.613055
0.188815 0.099349 0.045957 -0.580640 0.736778 -0.346432
0.158298 0.138410 0.046260 -0.355774 -0.929340 0.098751
0.188396 0.100414 0.051341 0.041796 -0.978035 0.204205
0.156597 0.029029 0.052961 -0.679234 -0.217043 -0.701095
0.163612 0.030268 0.053767 -0.049291 -0.977399 0.205578
0.161468 0.132395 0.053141 -0.971239 -0.235855 -0.032657
0.154333 0.141806 0.053134 -0.556541 -0.730562 0.395653
0.152264 0.030030 0.054185 -0.320229 -0.942084 -0.099656
0.151468 0.147238 0.054078 0.365883 -0.875995 0.314265
0.190363 0.096857 0.055901 -0.636895 -0.744843 0.198933
0.163386 0.129854 0.055857 -0.670100 -0.086135 0.737256
0.166323 0.030137 0.057209 0.028762 -0.985955 0.164518
0.157578 0.141252 0.057459 -0.780060 -0.592353 0.201554
3.3、PLY文件的常用元素和属性
尽管PLY格式能够灵活定义多种元素和属性类型,但在不同程序间实现对一组公共元素的理解以进行公共3D数据类型的通信仍是一个挑战。Turk建议,程序应当努力使元素和属性的名称标准化。
核心属性 | 元素 | 属性 | 数据类型 | 属性描述 |
✓ | vertex | x | float | x,y,z coordinates |
✓ | y | float | ||
✓ | z | float | ||
nx | float | x,y,z of normal | ||
ny | float | |||
nz | float | |||
red | uchar | vertex color | ||
green | uchar | |||
blue | uchar | |||
alpha | uchar | amount of transparency | ||
material_index | int | index to list of materials | ||
face | vertex_indices | list of int | indices to vertices | |
back_red | uchar | backside color | ||
back_green | uchar | |||
back_blue | uchar | |||
edge | vertex1 | int | index to vertex | |
vertex2 | int | index to other vertex | ||
crease_tag | uchar | crease in subdivision surface | ||
material | red | uchar | material color | |
green | uchar | |||
blue | uchar | |||
alpha | uchar | amount of transparency | ||
reflect_coeff | float | amount of light reflected | ||
refract_coeff | float | amount of light refracted | ||
refract_index | float | index of refraction | ||
extinct_coeff | float | extinction coefficient |
3.4、PCL库PLY文件的输出和输入(IO)示例
PCL 的 IO 模块也提供了读取和写入 PLY文件的功能,在文件中#include <pcl/io/ply_io.h>,下面示例演示用PCL库完成PLY点云文件的输出和输入操作。
PLY文件输出示例:
/*****************************************************************//**
* \file testPCL_io.cpp
* \brief
*
* \author YZS
* \date December 2024
*********************************************************************/
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/ply_io.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
// 创建点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 随机生成点云数据
srand(static_cast<unsigned int>(time(NULL)));
for (int i = 0; i < 100; ++i)
{
pcl::PointXYZ point;
point.x = 10.0f * rand() / RAND_MAX; // 在 x 方向上点坐标
point.y = 10.0f * rand() / RAND_MAX; // 在 y 方向上点坐标
point.z = 10.0f * rand() / RAND_MAX; // 在 z 方向上点坐标
cloud->push_back(point);
}
//输出点云数目
std::cout << "Point Sizes:" << cloud->points.size() << std::endl;
//保存ASCII文件
pcl::io::savePLYFileASCII("output_ascii.ply", *cloud);
//保存二进制文件
pcl::io::savePLYFileBinary("output_Binary.ply", *cloud);
//或者
//二进制文件
//pcl::io::savePLYFile("testPCL_io.ply", *cloud, true);
//ASCII文件
//pcl::io::savePLYFile("testPCL_io.ply", *cloud, false);
std::cout << "Save Done!" << std::endl;
std::system("pause");
return 0;
}
PLY文件输入示例:
/*****************************************************************//**
* \file testPCL_io.cpp
* \brief
*
* \author YZS
* \date December 2024
*********************************************************************/
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/ply_io.h>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
// 创建点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
//PLY文件名
std::string filePLY = "test_ply.ply";
//打开点云文件
if (pcl::io::loadPLYFile<pcl::PointXYZ>(filePLY, *cloud) == -1)
{
PCL_ERROR("Couldn't read file test_ply.ply \n");
return (-1);
}
//打印输出点云数目
std::cout << " Point Sizes:" << cloud->points.size() << std::endl;
//打印输出所有点信息
for (size_t i = 0; i < cloud->points.size(); ++i)
{
std::cout << " Point:" << cloud->points[i] << std::endl;
}
std::cout << "Load Done!" << std::endl;
std::system("pause");
return 0;
}
4、PCL点云库中IO综合Demo
综合示例如下:
/*****************************************************************//**
* \file PointCloudIOmain.cpp
* \brief
*
* \author YZS
* \date December 2024
*********************************************************************/
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
//不需要指定文件的格式,目前只支持ply,pcd和ifs三种文件格式的输入和输出
#include <pcl/io/auto_io.h>
using namespace std;
int main(int argc, char* argv)
{
// 创建点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
srand(static_cast<unsigned int>(time(NULL)));
//产生点云数据
for (int i = 0; i < 100; ++i)
{
pcl::PointXYZ point;
point.x = 10.0f * rand() / RAND_MAX; // 在 x 方向上点坐标
point.y = 10.0f * rand() / RAND_MAX; // 在 y 方向上点坐标
point.z = 10.0f * rand() / RAND_MAX; // 在 z 方向上点坐标
cloud->push_back(point);
}
//PLY文件名
std::string filePLY = "test_ply.ply";
//保存数据,根据文件后缀自动存储
pcl::io::save(filePLY, *cloud);
pcl::PointCloud<pcl::PointXYZ> cloud2;
//打开点云文件,根据文件后缀自动读取
if (pcl::io::load<pcl::PointXYZ>(filePLY, cloud2) == -1)
{
PCL_ERROR("Couldn't read file test_ply.ply \n");
return (-1);
}
//打印输出点云数目
std::cout << " Point Sizes:" << cloud2.points.size() << std::endl;
//打印输出所有点信息
for (size_t i = 0; i < cloud2.points.size(); ++i)
{
std::cout << " Point:" << cloud2.points[i] << std::endl;
}
//保存为PCD文件
std::string filePCD = "test_pcd.pcd";
pcl::io::save(filePCD, cloud2);
std::cout << "Hello PCL!" << std::endl;
system("pause");
return 0;
}
至此完成第三节PCL中点云数据格式PCD和PLY以及其输入输出(IO)的学习,下一节我们将进入《PCL库中点云数据可视化(CloudViewer/PCLVisualizer)》的学习。
原文地址:https://blog.csdn.net/qq_36812406/article/details/144410446
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!