自学内容网 自学内容网

PCL点云库入门——PCL库中点云数据格式PCD和PLY及其输入输出(IO)

1、前言

        根据PCL点云库的IO模块信息,目前PCL库中支持PCD、PLY、OBJ、IFS和PNG等多种文件格式的读取与写入。然而,支持的文件类型相对有限。在本节中,我们将重点讲解和阐释PCL库中最为常用的PCDPLY文件格式。

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)!