一、格式介绍

PLY是一种电脑档案格式,全名为多边形档案(Polygon File Format)或 斯坦福三角形档案(Stanford Triangle Format)。 

史丹佛大学的 The Digital Michelangelo Project计划采用PLY格式储存极高分辨率之米开朗基罗的作品"大卫"雕塑。

该格式主要用以储存立体扫描结果的三维数值,透过多边形片面的集合描述三维物体,与其他格式相较之下这是较为简单的方法。它可以储存的资讯包含颜色、透明度、表面法向量、材质座标与资料可信度,并能对多边形的正反两面设定不同的属性。

在档案内容的储存上PLY有两种版本,分别是纯文字(ASCII)版本与二元码(binary)版本,其差异在储存时是否以ASCII编码表示元素资讯。

档案格式

(本文并未提供完整的格式描述,以下仅介绍PLY的基本概念与格式)

每个PLY档都包含档头(header),用以设定网格模型的“元素”与“属性”,以及在档头下方接着一连串的元素“数值资料”。一般而言,网格模型的“元素”就是顶点(vertices)、面(faces),另外还可能包含有边(edges)、深度图样本(samples of range maps)与三角带(triangle strips)等元素。无论是纯文字与二元码的PLY档,档头资讯都是以ASCII编码编写,接续其后的数值资料才有编码之分。PLY档案以此行:

ply

开头作为PLY格式的识别。接着第二行是版本资讯,目前有三种写法:

format ascii 1.0
format binary_little_endian 1.0
format binary_big_endian 1.0

其中ascii, binary_little_endian, binary_big_endian是档案储存的编码方式,而1.0是遵循的标准版本(现阶段仅有PLY 1.0版)。在档头中可使用'comment'作为一行的开头以编写注解,例如:

comment This is a comment!

描述元素及属性,必须使用'element'及'property'的关键字,一般的格式为element下方接着属性列表,例如:

element <element name> <number in file>
 property <data_type> <property name 1>
 property <data_type> <property name 2>
 property <data_type> <property name 3>

'property'不仅定义了资料的型态,其出现顺序亦定义了资料的顺序。内定的资料形态有两种写法:一种是char uchar short ushort int uint float double,另外一种是具有位元长度的int8 uint8 int16 uint16 int32 uint32 float32 float64。 例如,描述一个包含12个顶点的物体,每个顶点使用3个单精度浮点数 (x,y,z)代表点的座标,使用3个unsigned char代表顶点颜色,颜色顺序为 (B, G, R),则档头的写法为:

element vertex 12
propertyfloat x
propertyfloat y
propertyfloat z
property uchar blue
property uchar green
property uchar red

其中vertex是内定的元素类型,接续的6行property描述构成vertex元素的数值字段顺序代表的意义,及其资料形态。

另一个常使用的元素是面。由于一个面是由3个以上的顶点所组成,因此使用一个“顶点列表”即可描述一个面, PLY格式使用一个特殊关键字'property list'定义之。 例如,一个具有10个面的物体,其PLY档头可能包含:

element face 10
 property list uchar int vertex_indices

'property list'表示该元素face的特性是由一行的顶点列表来描述。列表开头以uchar型态的数值表示列表的项目数,后面接着资料型态为int的顶点索引值(vertex_indices),顶点索引值从0开始。

最后,标头必须以此行结尾:

end_header

档头后接着的是元素资料(端点座标、拓朴连结等)。在ASCII格式中各个端点与面的资讯都是以独立的一行描述,而二元编码格式则连续储存这些资料,加载时须以'element'定义的元素数目以及'property'中设定的资料形态计算各笔字段的长度。

范例

一个典型的PLY档案结构分成三部分:

档头 (从ply开始到end_header)
顶点元素列表
面元素列表

其中的顶点元素列表一般以x y z方式排列,形态如档头所定义;而面元素列表是以下列格式表示。

<組成面的端點數N> <端點#1的索引> <端點#2的索引> ... <端點#N的索引>

例如画出一个有4个顶点,4个面的四面体,档案内容为:

ply
format ascii 1.0
comment這是一個正四面體
element vertex 4
propertyfloat x
propertyfloat y
propertyfloat z
element face 4
property list uchar int vertex_index
end_header
0 3 0
2.449 -1.0 -1.414
0 -1 2.828
-2.449 -1.0 -1.414
3 0 1 3
3 0 2 1
3 0 3 2
3 1 2 3

其中1~10行是档头, 11~14行是顶点元素列表, 15~18行则是面元素列表。

其中: 0 3 0是顶点

历史

PLY格式发展于90年代中期,在史丹佛大学图学实验室的Marc Levoy教授指导下,由Greg Turk及其他成员开发出来。PLY格式受Wavefront .obj格式的启发,但改进了Obj格式所缺少的对任意属性及群组的扩充性。因此PLY格式发明了"property"及"element"这两个关键词,来概括“顶点、面、相关资讯、群组”的概念。

注意

ply文件不支持中文格式的文件名字,所以在使用过程中避免使用中文来命名。

二、C语言读取PLY文件

// Try to read a plyfile, returning vertices and faces
bool read_ply(const char *plyfile,int &numleaves, QTree_Node * &leaves,int &numfaces, face * &faces,bool &have_colors,std::string &comments)
{bool have_faces=false, have_tstrips=false;int tstripdatalen=0, *tstripdata = NULL;int other_prop_len, color_offset;char buf[255];int i, result;have_colors = false;  numleaves = numfaces = 0;leaves = NULL;  faces = NULL;FILE *f = fopen(plyfile, "r");if (!f) {fprintf(stderr, "Can't open plyfile %s\n", plyfile);return false;}printf("Reading %s...\n", plyfile);// Read headerif (!fgets(buf, 255, f) || strncmp(buf, "ply", 3)) {fprintf(stderr, "Not a ply file.\n");return false;}#define GET_LINE() if (!fgets(buf, 255, f)) goto plyreaderror
#define LINE_IS(text) !strncasecmp(buf, text, strlen(text))GET_LINE();if (!LINE_IS("format binary_big_endian 1.0")&&!LINE_IS("format binary_little_endian 1.0")) {fprintf(stderr, "Can only read binary  ply files.\n");}while (1) {GET_LINE();if (LINE_IS("obj_info")) {continue;} else if (LINE_IS("comment")) {comments += buf+8;continue;} else {break;}}result = sscanf(buf, "element vertex %d\n", &numleaves);if (result != 1) {fprintf(stderr, "Expected \"element vertex\"\n");goto plyreaderror;}GET_LINE();if (!LINE_IS("property float x")) {fprintf(stderr, "Expected \"property float x\"\n");goto plyreaderror;}GET_LINE();if (!LINE_IS("property float y")) {fprintf(stderr, "Expected \"property float y\"\n");goto plyreaderror;}GET_LINE();if (!LINE_IS("property float z")) {fprintf(stderr, "Expected \"property float z\"\n");goto plyreaderror;}other_prop_len = 0;GET_LINE();while (LINE_IS("property")) {if (LINE_IS("property char") ||LINE_IS("property uchar")) {other_prop_len += 1;} else if (LINE_IS("property int") ||LINE_IS("property uint") ||LINE_IS("property float")) {other_prop_len += 4;} else {fprintf(stderr, "Unsupported vertex property: %s\n", buf);goto plyreaderror;}if (LINE_IS("property uchar diffuse_red")) {have_colors = true;color_offset = other_prop_len - 1;}GET_LINE();}result = sscanf(buf, "element face %d", &numfaces);if (result == 1) {have_faces = true;GET_LINE();if (!LINE_IS("property list uchar int vertex_indices"))goto plyreaderror;GET_LINE();} else if (LINE_IS("element tristrips 1")) {have_tstrips = true;GET_LINE();if (!LINE_IS("property list int int vertex_indices"))goto plyreaderror;GET_LINE();}if (!LINE_IS("end_header")) {fprintf(stderr, "Expected \"end_header\"\n");goto plyreaderror;}// OK, we think we've parsed the header. Slurp in the actual data...leaves = new QTree_Node[numleaves];printf(" Reading %d vertices... ", numleaves); fflush(stdout);for (i=0; i < numleaves; i++) {if (!fread((void *)&(leaves[i].pos[0]), 12, 1, f))goto plyreaderror;if (other_prop_len && !fread((void *)buf, other_prop_len, 1, f))goto plyreaderror;if (have_colors) {memcpy((void *)&(leaves[i].col[0]),buf + color_offset,sizeof(color));}}printf("Done.\n");if (have_tstrips) {printf(" Reading triangle strips... "); fflush(stdout);if (!fread((void *)&tstripdatalen, 4, 1, f))goto plyreaderror;FIX_LONG(tstripdatalen);tstripdata = new int[tstripdatalen];if (!fread((void *)tstripdata, 4*tstripdatalen, 1, f))goto plyreaderror;for (int t=0; t < tstripdatalen; t++)FIX_LONG(tstripdata[t]);} else if (have_faces) {printf(" Reading %d faces... ", numfaces); fflush(stdout);faces = new face[numfaces];for (i=0; i < numfaces; i++) {if (!fread((void *)buf, 1, 1, f))goto plyreaderror;if (buf[0] != 3) {fprintf(stderr, "Non-triangle found in mesh.\n");}if (!fread((void *)faces[i], 12, 1, f))goto plyreaderror;}}printf("Done.\n");if (tstripdatalen) {unpack_tstrips(tstripdatalen, tstripdata, numfaces, faces);delete [] tstripdata;}fgets(buf, 2, f);if (!feof(f)) {fprintf(stderr, "Warning: ignored excess garbage at end of ply file.\n");}fclose(f);return true;plyreaderror:fclose(f);fprintf(stderr, "Error reading plyfile.\n");if (leaves) delete [] leaves;if (faces) delete [] faces;if (tstripdata) delete [] tstripdata;return false;
}

三、利用QSplatmake将PLY文件转化为QS文件时需要注意little_endian与Big_endian的区别主要在FIXFLOAT和FIX_LONG等会受到影响,可以直接忽略这句语句。其具体有什么用我还不太明了,猜想应该是控制数值的形式。对于little_endian与Big_endian分别所代表的含义可自行百度,这里就不太累述。

PLY格式介绍与读取相关推荐

  1. Python将网格off格式转换为ply格式

    文章目录 背景 一.off文件格式 二.ply文件格式 三.读取单个off文件并写ply文件 1.引入库igl和plyfile 2.读入数据(三角网格面) 2.写入数据 法一:直接写文件 法二:用pl ...

  2. python读取ply格式的3D模型文件

    在研究生的一些项目中,会用python语言读取3D模型,3D模型通常有很多种类,但我的研究领域,通常用到ply格式的文件,因此,我今天晚上写一个博客来实现用python读取3D模型. 我的项目是位姿估 ...

  3. 点云格式介绍(更新中,待补充)

    常见点云存储方式有pcd.ply.txt.bin文件. 一.点云的基本组成 点云组成可以是以下几种形式数据的排列组合. (1)x.y.z:点云的空间坐标. (2)i:强度值,强度反应了点的密集成度. ...

  4. livechart 只显示 y 值_基于Python语言的SEGY格式地震数据读取与显示编程

    敬请关注<地学新视野> 摘要:本文简单介绍了SEG-Y地震数据文件格式,以及如何用Python语言编写读写SEG-Y格式的地震数据并绘制地震剖面,其中用到了Segyio和matplotli ...

  5. 关于医疗影像的mhd和dcm格式图像的读取和坐标转换

    本篇博客主要对近年来大赛(Luna16,kaggle,天池)中使用的肺部图像的读取和坐标转换进行整理,如果有错误,欢迎批评指正,谢谢. 1 介绍mhd格式的数据: 数据可以在Luna16(https: ...

  6. FME的ESRI Geodatabase (MDB)格式介绍(一)

    原文发布时间:2010-10-13 作者:毛毛虫 来源: ESRI Geodatabase (MDB) 是一种FME 格式,它的FME格式关键字是GEODATABASE_MDB. 1.创建类: FME ...

  7. OpenGL--------读取PLY格式的bunny兔子文件以便画出兔子

    写在前面的话:PLY文件格式是Stanford大学开发的一套三维mesh模型数据格式,开发目标是建立一套针对多边形模型的,结构简单但是能够满足大多数图形应用需要的模型格式,而且它允许以ASCII码格式 ...

  8. PFM格式图像和读取middlebury 数据集

    PFM格式图像和读取middlebury 数据集 PFM格式图像 图像格式 Middlebury 2014数据集 数据集介绍 读取Middlebury数据集中视差图生成depth map PFM格式图 ...

  9. Unity 之 纹理类型导入设置和压缩格式介绍

    Unity 之 纹理类型导入设置和压缩格式介绍 一,纹理相关 1.1 导入设置 1.2 支持格式 二,纹理类型 2.1 纹理类型说明 2.2 纹理尺寸大小 三,所有支持的纹理压缩格式 一,纹理相关 1 ...

最新文章

  1. matlab数据可视化总结,机器学习----Matlab数据可视化总结(plot篇)
  2. [VBScript] 自动删除2小时以前生成的文件
  3. 目标检测--RON: Reverse Connection with Objectness Prior Networks for Object Detection
  4. python3精要(50)-二分法解一元方程
  5. inherits java_JAVA内部类和组合的区别
  6. 【超级鼠标键盘锁】之远线程注入winlogon.exe进程屏蔽Ctrl+Alt+Del、Win+L
  7. FreeBSD5.0内核 - 锁机制
  8. 程序员的恶性循环:加班-没空学习-老是写同等水平代码-无法提升代码质量-老是出BUG-老是需要修改-加班-......
  9. 软件质量保证SQA、软件测试ST
  10. android备份手机号码,Android QQ同步助手3.2 保证号码备份“不丢人”
  11. 文件导入工具类--利用反射自动转换为list对象
  12. win服务器系统设置休眠时间,win7系统电脑设置休眠时间的操作方法
  13. 2022.4.7学习笔记
  14. markdown 文本内跳转,生成目录
  15. 【SAMF】A Scale Adaptive Kernel Correlation Filter Tracker with Feature Integration 论文阅读笔记
  16. 川土微电子 | 如何隔离 RS-485 系统
  17. realme真我V15国潮锦鲤手机:携《国家宝藏》IP筑开年之作
  18. 郑渊洁:一个著作等身的文盲
  19. 嵌入式中的BSP---BSP到底是什么?
  20. STM32F4xx 读保护 写保护 芯片被锁 解锁

热门文章

  1. DataFrame中实现int、float存储形式列之间的除法运算
  2. win10计算机拨号连接,Win10设置电脑开机自动连接宽带的方法
  3. javaSE基础重点知识点总结 持续更新
  4. C#情怀与未来,怨天尤人还是抓住机会,能否跟上dnc新时代浪潮?
  5. windows虚机环境下,如何快速有效的删除大文件夹?
  6. java黑马面试_JavaWeb-黑马面面(面试刷题系统)项目实战
  7. java中的odb_obd适配器的初始化
  8. Windows下Qt程序初步打包
  9. 使用Angular 2, ASP。NET Core 1.1和实体框架核心(第1部分)
  10. 中国卸油系统行业市场供需与战略研究报告