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 Thisisa comment!

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

?

element

property

property

property

‘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

propertyfloatx

propertyfloaty

propertyfloatz

property uchar blue

property uchar green

property uchar red

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

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

?

element face 10

property list ucharintvertex_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

propertyfloatx

propertyfloaty

propertyfloatz

element face 4

property list ucharintvertex_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文件不支持中文格式的文件名字,所以在使用过程中避免使用中文来命名。

使用MATLAB对PLY文件进行读操作

function [ Elements, varargout ] = PLY_READ ( Path, Str )%*****************************************************************************80
%
%% PLY_READ reads a PLY 3D data file.
%
%   [DATA,COMMENTS] = PLY_READ(FILENAME) reads a version 1.0 PLY file
%   FILENAME and returns a structure DATA.  The fields in this structure
%   are defined by the PLY header; each element type is a field and each
%   element property is a subfield.  If the file contains any comments,
%   they are returned in a cell string array COMMENTS.
%
%   [TRI,PTS] = PLY_READ(FILENAME,'tri') or
%   [TRI,PTS,DATA,COMMENTS] = PLY_READ(FILENAME,'tri') converts vertex
%   and face data into triangular connectivity and vertex arrays.  The
%   mesh can then be displayed using the TRISURF command.
%
%   Note: This function is slow for large mesh files (+50K faces),
%   especially when reading data with list type properties.
%
%   Example:
%   [Tri,Pts] = PLY_READ('cow.ply','tri');
%   [Tri,Pts] = PLY_READ('bunny.ply','tri');
%   trisurf(Tri,Pts(:,1),Pts(:,2),Pts(:,3));
%   colormap(gray); axis equal;
%
%  Discussion:
%
%    The original version of this program had a mistake that meant it
%    did not properly triangulate files whose faces were not already triangular.
%    This has been corrected (JVB, 25 February 2007).
%
%    Glenn Ramsey pointed out and corrected a problem that occurred
%    with an uninitialized value of Type2, 27 August 2012.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 August 2012
%
%  Author:
%
%    Pascal Getreuer 2004
%
%  Parameters:
%
%  Local Parameters:
%
%    COMMENTS, any comments from the file.
%
%    ELEMENTCOUNT, the number of each type of element in file.
%
%    ELEMENTS, the element data.
%
%    PROPERTYTYPES, the element property types.
%
%    SIZEOF, size in bytes of each type.
%%
%  Open the input file in "read text" mode.
%[ fid, Msg ] = fopen ( Path, 'rt' );if ( fid == -1 )error ( Msg );endBuf = fscanf ( fid, '%s', 1 );if ( ~strcmp ( Buf, 'ply' ) )fclose ( fid );error('Not a PLY file.');end
%
%  Read the header.
%Position = ftell(fid);Format = '';NumComments = 0;Comments = {};NumElements = 0;NumProperties = 0;Elements = [];ElementCount = [];PropertyTypes = [];ElementNames = {};  % list of element names in the order they are stored in the filePropertyNames = [];  % structure of lists of property nameswhile ( 1 )
%
%  Read a line from the file.
%Buf = fgetl ( fid );BufRem = Buf;Token = {};Count = 0;
%
%  Split the line into tokens.
%while ( ~isempty(BufRem) )[ tmp, BufRem ] = strtok(BufRem);
%
%  Count the tokens.
%if ( ~isempty ( tmp ) )Count = Count + 1;Token{Count} = tmp;endend
%
%  Parse the line.
%if ( Count )switch lower ( Token{1} )
%
%  Read the data format.
%case 'format'if ( 2 <= Count )Format = lower ( Token{2} );if ( Count == 3 & ~strcmp ( Token{3}, '1.0' ) )fclose ( fid );error('Only PLY format version 1.0 supported.');endend
%
%  Read a comment.
%case 'comment'NumComments = NumComments + 1;Comments{NumComments} = '';for i = 2 : CountComments{NumComments} = [Comments{NumComments},Token{i},' '];end
%
%  Read an element name.
%case 'element'if ( 3 <= Count )if ( isfield(Elements,Token{2}) )fclose ( fid );error(['Duplicate element name, ''',Token{2},'''.']);endNumElements = NumElements + 1;NumProperties = 0;Elements = setfield(Elements,Token{2},[]);PropertyTypes = setfield(PropertyTypes,Token{2},[]);ElementNames{NumElements} = Token{2};PropertyNames = setfield(PropertyNames,Token{2},{});CurElement = Token{2};ElementCount(NumElements) = str2double(Token{3});if ( isnan(ElementCount(NumElements)) )fclose ( fid );error(['Bad element definition: ',Buf]);endelseerror(['Bad element definition: ',Buf]);end
%
%  Read an element property.
%case 'property'if ( ~isempty(CurElement) & Count >= 3 )NumProperties = NumProperties + 1;eval(['tmp=isfield(Elements.',CurElement,',Token{Count});'],...'fclose(fid);error([''Error reading property: '',Buf])');if ( tmp )error(['Duplicate property name, ''',CurElement,'.',Token{2},'''.']);end
%
%  Add property subfield to Elements.
%eval(['Elements.',CurElement,'.',Token{Count},'=[];'], ...'fclose(fid);error([''Error reading property: '',Buf])');
%
%  Add property subfield to PropertyTypes and save type.
%eval(['PropertyTypes.',CurElement,'.',Token{Count},'={Token{2:Count-1}};'], ...'fclose(fid);error([''Error reading property: '',Buf])');
%
%  Record property name order.
%eval(['PropertyNames.',CurElement,'{NumProperties}=Token{Count};'], ...'fclose(fid);error([''Error reading property: '',Buf])');elsefclose ( fid );if ( isempty(CurElement) )error(['Property definition without element definition: ',Buf]);elseerror(['Bad property definition: ',Buf]);endend
%
%  End of header.
%case 'end_header'break;endendend
%
%  Set reading for specified data format.
%if ( isempty ( Format ) )warning('Data format unspecified, assuming ASCII.');Format = 'ascii';endswitch Formatcase 'ascii'Format = 0;case 'binary_little_endian'Format = 1;case 'binary_big_endian'Format = 2;otherwisefclose ( fid );error(['Data format ''',Format,''' not supported.']);end
%
%  Read the rest of the file as ASCII data...
%if ( ~Format )Buf = fscanf ( fid, '%f' );BufOff = 1;else
%
%  ...or, close the file, and reopen in "read binary" mode.
%fclose ( fid );
%
%  Reopen the binary file as LITTLE_ENDIAN or BIG_ENDIAN.
%if ( Format == 1 )fid = fopen ( Path, 'r', 'ieee-le.l64' );elsefid = fopen ( Path, 'r', 'ieee-be.l64' );end
%
%  Find the end of the header again.
%  Using ftell on the old handle doesn't give the correct position.
%BufSize = 8192;Buf = [ blanks(10), char(fread(fid,BufSize,'uchar')') ];i = [];tmp = -11;while ( isempty(i) )i = findstr(Buf,['end_header',13,10]);   % look for end_header + CR/LFi = [i,findstr(Buf,['end_header',10])];  % look for end_header + LFif ( isempty(i) )tmp = tmp + BufSize;Buf = [Buf(BufSize+1:BufSize+10),char(fread(fid,BufSize,'uchar')')];endend
%
%  seek to just after the line feed
%fseek ( fid, i + tmp + 11 + (Buf(i + 10) == 13), -1 );end
%
%  Read element data.
%
%  PLY and MATLAB data types (for fread)
%PlyTypeNames = {'char','uchar','short','ushort','int','uint','float','double', ...'char8','uchar8','short16','ushort16','int32','uint32','float32','double64'};MatlabTypeNames = {'schar','uchar','int16','uint16','int32','uint32','single','double'};SizeOf = [1,1,2,2,4,4,4,8];for i = 1 : NumElements
%
%  get current element property information
%eval(['CurPropertyNames=PropertyNames.',ElementNames{i},';']);eval(['CurPropertyTypes=PropertyTypes.',ElementNames{i},';']);NumProperties = size(CurPropertyNames,2);%   fprintf('Reading %s...\n',ElementNames{i});
%
%  Read ASCII data.
%if ( ~Format )for j = 1 : NumPropertiesToken = getfield(CurPropertyTypes,CurPropertyNames{j});if ( strcmpi(Token{1},'list') )Type(j) = 1;elseType(j) = 0;end
%
%  Glenn Ramsey 20120827
%  Initialise Type2{} to prevent uninitialised value error.
%Type2{j} = '';end
%
%  Parse the buffer.
%if ( ~any(Type) )% no list typesData = reshape ( ...Buf(BufOff:BufOff+ElementCount(i)*NumProperties-1), ...NumProperties, ElementCount(i) )';BufOff = BufOff + ElementCount(i) * NumProperties;elseListData = cell(NumProperties,1);for k = 1 : NumPropertiesListData{k} = cell(ElementCount(i),1);end
%
% list type
%for j = 1 : ElementCount(i)for k = 1 : NumPropertiesif ( ~Type(k) )Data(j,k) = Buf(BufOff);BufOff = BufOff + 1;elsetmp = Buf(BufOff);ListData{k}{j} = Buf(BufOff+(1:tmp))';BufOff = BufOff + tmp + 1;endendendend
%
%  Read binary data.
%else
% translate PLY data type names to MATLAB data type namesListFlag = 0;  % = 1 if there is a list typeSameFlag = 1;     % = 1 if all types are the samefor j = 1 : NumPropertiesToken = getfield(CurPropertyTypes,CurPropertyNames{j});
%
%  Non-list type.
%if ( ~strcmp(Token{1},'list' ) )tmp = rem(strmatch(Token{1},PlyTypeNames,'exact')-1,8)+1;if ( ~isempty(tmp) )TypeSize(j) = SizeOf(tmp);Type{j} = MatlabTypeNames{tmp};TypeSize2(j) = 0;Type2{j} = '';SameFlag = SameFlag & strcmp(Type{1},Type{j});elsefclose(fid);error(['Unknown property data type, ''',Token{1},''', in ', ...ElementNames{i},'.',CurPropertyNames{j},'.']);endelse           % list typeif ( length(Token) == 3 )ListFlag = 1;SameFlag = 0;tmp = rem(strmatch(Token{2},PlyTypeNames,'exact')-1,8)+1;tmp2 = rem(strmatch(Token{3},PlyTypeNames,'exact')-1,8)+1;if ( ~isempty(tmp) & ~isempty(tmp2) )TypeSize(j) = SizeOf(tmp);Type{j} = MatlabTypeNames{tmp};TypeSize2(j) = SizeOf(tmp2);Type2{j} = MatlabTypeNames{tmp2};elsefclose(fid);error(['Unknown property data type, ''list ',Token{2},' ',Token{3},''', in ', ...ElementNames{i},'.',CurPropertyNames{j},'.']);endelsefclose(fid);error(['Invalid list syntax in ',ElementNames{i},'.',CurPropertyNames{j},'.']);endendend% read fileif ( ~ListFlag )
%
%  No list types, all the same type (fast)
%if ( SameFlag )Data = fread(fid,[NumProperties,ElementCount(i)],Type{1})';
%
%  No list types, mixed type.
%elseData = zeros(ElementCount(i),NumProperties);for j = 1 : ElementCount(i)for k = 1 : NumPropertiesData(j,k) = fread(fid,1,Type{k});endendendelseListData = cell(NumProperties,1);for k = 1 : NumPropertiesListData{k} = cell(ElementCount(i),1);endif ( NumProperties == 1 )BufSize = 512;SkipNum = 4;j = 0;
%
%  List type, one property (fast if lists are usually the same length)
%while ( j < ElementCount(i) )BufSize = min(ElementCount(i)-j,BufSize);Position = ftell(fid);
%
%  Read in BufSize count values, assuming all counts = SkipNum
%[Buf,BufSize] = fread(fid,BufSize,Type{1},SkipNum*TypeSize2(1));Miss = find(Buf ~= SkipNum);     % find first count that is not SkipNumfseek(fid,Position + TypeSize(1),-1);   % seek back to after first countif ( isempty(Miss) )
% all counts are SkipNumBuf = fread(fid,[SkipNum,BufSize],[int2str(SkipNum),'*',Type2{1}],TypeSize(1))';fseek(fid,-TypeSize(1),0);     % undo last skipfor k = 1:BufSizeListData{1}{j+k} = Buf(k,:);endj = j + BufSize;BufSize = floor(1.5*BufSize);else
%
%  Some counts are SkipNum.
%if ( 1 < Miss(1) )Buf2 = fread(fid,[SkipNum,Miss(1)-1],[int2str(SkipNum),'*',Type2{1}],TypeSize(1))';for k = 1:Miss(1)-1ListData{1}{j+k} = Buf2(k,:);endj = j + k;end
%
%  Read in the list with the missed count.
%SkipNum = Buf(Miss(1));j = j + 1;ListData{1}{j} = fread(fid,[1,SkipNum],Type2{1});BufSize = ceil(0.6*BufSize);endendelse
%
%  List type(s), multiple properties (slow)
%Data = zeros(ElementCount(i),NumProperties);for j = 1:ElementCount(i)for k = 1:NumPropertiesif ( isempty(Type2{k}) )Data(j,k) = fread(fid,1,Type{k});elsetmp = fread(fid,1,Type{k});ListData{k}{j} = fread(fid,[1,tmp],Type2{k});endendendendendend
%
%  Put data into Elements structure
%for k = 1 : NumPropertiesif ( ( ~Format & ~Type(k) ) || (Format & isempty(Type2{k})) )eval(['Elements.',ElementNames{i},'.',CurPropertyNames{k},'=Data(:,k);']);elseeval(['Elements.',ElementNames{i},'.',CurPropertyNames{k},'=ListData{k};']);endendendclear Dataclear ListData;fclose ( fid );
%
%  Output the data as a triangular mesh pair.
%if ( ( nargin > 1 & strcmpi(Str,'Tri') ) || nargout > 2 )
%
%  Find vertex element field
%Name = {'vertex','Vertex','point','Point','pts','Pts'};Names = [];for i = 1 : length(Name)if ( any ( strcmp ( ElementNames, Name{i} ) ) )Names = getfield(PropertyNames,Name{i});Name = Name{i};break;endendif ( any(strcmp(Names,'x')) & any(strcmp(Names,'y')) & any(strcmp(Names,'z')) )eval(['varargout{1}=[Elements.',Name,'.x,Elements.',Name,'.y,Elements.',Name,'.z];']);elsevarargout{1} = zeros(1,3);endvarargout{1} = varargout{1}';varargout{2} = Elements;varargout{3} = Comments;Elements = [];
%
% Find face element field
%Name = {'face','Face','poly','Poly','tri','Tri'};Names = [];for i = 1 : length(Name)if ( any(strcmp(ElementNames,Name{i})) )Names = getfield(PropertyNames,Name{i});Name = Name{i};break;endendif ( ~isempty(Names) )% find vertex indices property subfieldPropertyName = {'vertex_indices','vertex_indexes','vertex_index','indices','indexes'};for i = 1 : length(PropertyName)if ( any(strcmp(Names,PropertyName{i})) )PropertyName = PropertyName{i};break;endend
%
%  Convert face index list to triangular connectivity.
%if ( ~iscell(PropertyName) )eval(['FaceIndices=varargout{2}.',Name,'.',PropertyName,';']);N = length(FaceIndices);Elements = zeros(3,N*2);Extra = 0;for k = 1 : NElements(1:3,k) = FaceIndices{k}(1:3)';
%
%  The original code had an error in the following loop.
%for j = 4 : length(FaceIndices{k})Extra = Extra + 1;Elements(1,N + Extra) = FaceIndices{k}(1);Elements(2,N + Extra) = FaceIndices{k}(j-1);Elements(3,N + Extra) = FaceIndices{k}(j);endend
%
%  Add 1 to each vertex value; PLY vertices are zero based.
%Elements = Elements(:,1:N+Extra) + 1;endendelsevarargout{1} = Comments;endreturn
end**使用MATLAB对PLY文件进行写操作**
实现将矩阵的内容转换到封装的结构体中

function [Data1,Data2]=change(A,B)
Data1.vertex.x = A(:,1);
Data1.vertex.y = A(:,2);
Data1.vertex.z = A(:,3);
Data2.vertex.x = B(:,1);
Data2.vertex.y = B(:,2);
Data2.vertex.z = B(:,3);

function ply_write ( Elements, Path, Format, Str )%*****************************************************************************80
%
%% PLY_WRITE writes 3D data as a PLY file.
%
%  Discussion:
%
%    PLY_WRITE(DATA,FILENAME) writes the structure DATA as a binary
%    PLY file.  Every field of DATA is interpreted as an element
%    and every subfield as an element property.  Each subfield of
%    property data must either be an array or a cell array of
%    arrays.  All property data in an element must have the same
%    length.
%
%    A common PLY data structure has the following fields:
%      DATA.vertex.x = x coordinates, [Nx1] real array
%      DATA.vertex.y = y coordinates, [Nx1] real array
%      DATA.vertex.z = z coordinates, [Nx1] real array
%
%      DATA.face.vertex_indices = vertex index lists,
%         an {Mx1} cell array where each cell holds a one-
%         dimesional array (of any length) of vertex indices.
%
%    Some other common data fields:
%
%      DATA.vertex.nx = x coordinate of normal, [Nx1] real array
%      DATA.vertex.ny = y coordinate of normal, [Nx1] real array
%      DATA.vertex.nz = z coordinate of normal, [Nx1] real array
%
%      DATA.edge.vertex1 = index to a vertex, [Px1] integer array
%      DATA.edge.vertex2 = second vertex index, [Px1] integer array
%
%    Many other fields and properties can be added.  The PLY format
%    is not limited to the naming in the examples above -- they are
%    only the conventional naming.
%
%    PLY_WRITE(DATA,FILENAME,FORMAT) write the PLY with a specified
%    data format, where FORMAT is
%      'ascii'                  ASCII text data
%      'binary_little_endian'   binary data, little endian
%      'binary_big_endian'      binary data, big endian (default)
%
%    PLY_WRITE(DATA,FILENAME,FORMAT,'double') or
%
%    PLY_WRITE(DATA,FILENAME,'double') write floating-point data as
%    double precision rather than in the default single precision.
%
%  Example:
%
%    % make a cube
%    clear Data;
%    Data.vertex.x = [0;0;0;0;1;1;1;1];
%    Data.vertex.y = [0;0;1;1;0;0;1;1];
%    Data.vertex.z = [0;1;1;0;0;1;1;0];
%    Data.face.vertex_indices = {[0,1,2,3],[7,6,5,4], ...
%         [0,4,5,1],[1,5,6,2],[2,6,7,3],[3,7,4,0]};
%    ply_write(Data,'cube.ply','ascii');
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 July 2016    Seth Billings   bug fix: 'ushort' / 'uint16' data type was
%                                    not included in the min/max value arrays; now
%                                    excluding 'ushort' from the integer data types
%                                    (rather than fixing the min/max arrays), since
%                                    some programs such as MeshLab do not handle the
%                                    'ushort' data type properly anyway
%
%    01 July 2016    Seth Billings   bug fixes for max data value of 'short' / 'int16'
%                                    data type and for selection of output data type
%    01 March 2007
%
%  Author:
%
%    Pascal Getreuer 2004
%    Seth Billings 2016
%if ( nargin < 4 )Str = '';if ( nargin < 3 )Format = 'binary_big_endian';elseif ( strcmpi ( Format, 'double' ) )Str = 'double';Format = 'binary_big_endian';endend[ fid, Msg ] = fopen ( Path, 'wt' );if ( fid == -1 )error(Msg);end
%
%  Bug Fix: Seth Billings
%  - correcting max integer value for 'short' / 'int16' from 2^16-1 to 2^15-1
%  - excluding 'ushort' from integer types since MeshLab does not
%    read 'ushort' data type properly.
%PlyTypeNames = {'char','uchar','short','int','uint','float','double', ...'char8','uchar8','short16','int32','uint32','float32','double64'};FWriteTypeNames = {'schar','uchar','int16','int32','uint32','single','double'};MatlabTypeNames = {'int8','uint8','int16','int32','uint32','single','double'};PrintfTypeChar = {'%d','%u','%d','%d','%u','%-.6f','%-.14e'};IntegerDataMin =  [-128,   0, -2^15,  -2^31,   0];IntegerDataMax =  [ 127, 255,  2^15-1, 2^31-1, 2^32-1];numTypes = length(MatlabTypeNames);%PlyTypeNames = {'char','uchar','short','ushort','int','uint','float','double', ...%  'char8','uchar8','short16','ushort16','int32','uint32','float32','double64'};%FWriteTypeNames = {'schar','uchar','int16','uint16','int32','uint32','single','double'};%MatlabTypeNames = {'int8','uint8','int16','uint16','int32','uint32','single','double'};%PrintfTypeChar = {'%d','%u','%d','%u','%d','%u','%-.6f','%-.14e'};  %IntegerDataMin = [-128, 0, -2^15, -2^31, 0];%IntegerDataMax = [127, 255, 2^16-1, 2^31-1, 2^32-1];
%
%  Write the PLY header.
%fprintf(fid,'ply\nformat %s 1.0\ncomment created by MATLAB ply_write\n',Format);ElementNames = fieldnames(Elements);NumElements = length(ElementNames);Data = cell(NumElements,1);for i = 1 : NumElementseval(['tmp=isa(Elements.',ElementNames{i},',''struct'');']);if ( tmp )eval(['PropertyNames{i}=fieldnames(Elements.',ElementNames{i},');']);elsePropertyNames{i} = [];endif ( ~isempty(PropertyNames{i}) )eval(['Data{i}{1}=Elements.',ElementNames{i},'.',PropertyNames{i}{1},';']);ElementCount(i) = prod(size(Data{i}{1}));Type{i} = zeros(length(PropertyNames{i}),1);elseElementCount(i) = 0;endfprintf(fid,'element %s %u\n',ElementNames{i},ElementCount(i));for j = 1 : length(PropertyNames{i})eval(['Data{i}{j}=Elements.',ElementNames{i},'.',PropertyNames{i}{j},';']);if ( ElementCount(i) ~= prod(size(Data{i}{j})) )fclose(fid);error('All property data in an element must have the same length.');endif ( iscell(Data{i}{j}) )Type{i}(j) = numTypes + 1;  % Seth Billings%Type{i}(j) = 9;Data{i}{j} = Data{i}{j}{1};endfor k = 1 : length(MatlabTypeNames)if ( isa(Data{i}{j},MatlabTypeNames{k}) )Type{i}(j) = Type{i}(j) + k;break;endendif ( ~rem(Type{i}(j),numTypes+1) ) % Seth Billings%if ( ~rem(Type{i}(j),9) )fclose(fid);error('Unsupported data structure.');end
%
%  Try to convert float data to integer data
%
%  Array data.
%if ( Type{i}(j) <= numTypes)  % Seth Billings%if ( Type{i}(j) <= 8 )if any(strcmp({'single','double'},MatlabTypeNames{Type{i}(j)}))if ~any(floor(Data{i}{j}) ~= Data{i}{j})  % data is integerMinValue = min(min(Data{i}{j}));MaxValue = max(max(Data{i}{j}));% choose smallest possible integer data format            % Bug Fix: Seth Billingstmp = min(find(MinValue >= IntegerDataMin & MaxValue <= IntegerDataMax));%tmp = max(min(find(MinValue >= IntegerDataMin)),min(find(MaxValue <= IntegerDataMax)));if ~isempty(tmp)Type{i}(j) = tmp;endendendelse        % cell array dataeval(['Data{i}{j}=Elements.',ElementNames{i},'.',PropertyNames{i}{j},';']);tmp = 1;for k = 1:prod(size(Data{i}{j}))tmp = tmp & all(floor(Data{i}{j}{k}) == Data{i}{j}{k});endif tmp  % data is integerMinValue = inf;MaxValue = -inf;for k = 1:prod(size(Data{i}{j}))MinValue = min(MinValue,min(Data{i}{j}{k}));MaxValue = max(MaxValue,max(Data{i}{j}{k}));end
%
%  choose smallest possible integer data format
%  Bug Fix: Seth Billings
%tmp = min(find(MinValue >= IntegerDataMin & MaxValue <= IntegerDataMax));%tmp = max(min(find(MinValue >= IntegerDataMin)),min(find(MaxValue <= IntegerDataMax)));if ( ~ isempty ( tmp ) )Type{i}(j) = tmp + numTypes + 1;%Type{i}(j) = tmp + 9;endendend% convert double to single if specifiedif rem(Type{i}(j),numTypes+1) == numTypes & ~strcmpi(Str,'double') % Seth Billings%if rem(Type{i}(j),9) == 8 & ~strcmpi(Str,'double')Type{i}(j) = Type{i}(j) - 1;endif Type{i}(j) <= numTypes  % Seth Billings%if Type{i}(j) <= 8fprintf(fid,'property %s %s\n',PlyTypeNames{Type{i}(j)},PropertyNames{i}{j});elsefprintf(fid,'property list uchar %s %s\n',PlyTypeNames{Type{i}(j)-(numTypes+1)},PropertyNames{i}{j}); % Seth Billings%fprintf(fid,'property list uchar %s %s\n',PlyTypeNames{Type{i}(j)-9},PropertyNames{i}{j});endendendfprintf(fid,'end_header\n');switch Formatcase 'ascii'Format = 0;case 'binary_little_endian'fclose(fid);fid = fopen(Path,'a','ieee-le');Format = 1;case 'binary_big_endian'fclose(fid);fid = fopen(Path,'a','ieee-be');Format = 2;endfor i = 1 : NumElementsif ~isempty(PropertyNames{i})if ~Format          % write ASCII datafor k = 1:ElementCount(i)for j = 1:length(PropertyNames{i})if Type{i}(j) <= numTypes  % Seth Billings%if Type{i}(j) <= 8fprintf(fid,[PrintfTypeChar{Type{i}(j)},' '],Data{i}{j}(k));elsefprintf(fid,'%u%s ',length(Data{i}{j}{k}),sprintf([' ',PrintfTypeChar{Type{i}(j)-(numTypes+1)}],Data{i}{j}{k})); % Seth Billings%fprintf(fid,'%u%s ',length(Data{i}{j}{k}),sprintf([' ',PrintfTypeChar{Type{i}(j)-9}],Data{i}{j}{k}));endendfprintf(fid,'\n');endelse            % write binary dataif all(Type{i} <= numTypes) & all(Type{i} == Type{i}(1))  % Seth Billings%if all(Type{i} <= 8) & all(Type{i} == Type{i}(1))% property data without list types (fast)tmp = zeros(length(PropertyNames{i}),ElementCount(i));for j = 1:length(PropertyNames{i})tmp(j,:) = Data{i}{j}(:)';endfwrite(fid,tmp,FWriteTypeNames{Type{i}(j)});elseif all(Type{i} > numTypes) % Seth Billings%elseif all(Type{i} > 8)% only list typesType{i} = Type{i} - (numTypes+1); % Seth Billings%Type{i} = Type{i} - 9;if length(PropertyNames{i}) == 1% only one list propertytmp = FWriteTypeNames{Type{i}(1)};for k = 1:ElementCount(i)fwrite(fid,length(Data{i}{1}{k}),'uchar');fwrite(fid,Data{i}{1}{k},tmp);endelse% multiple list propertiesfor k = 1:ElementCount(i)for j = 1:length(PropertyNames{i})fwrite(fid,length(Data{i}{j}{k}),'uchar');fwrite(fid,Data{i}{j}{k},FWriteTypeNames{Type{i}(j)});endendendelse% mixed typefor k = 1:ElementCount(i)for j = 1:length(PropertyNames{i})if Type{i}(j) <= numTypes % Seth Billings%if Type{i}(j) <= 8fwrite(fid,Data{i}{j}(k),FWriteTypeNames{Type{i}(j)});elsefwrite(fid,length(Data{i}{j}{k}),'uchar');fwrite(fid,Data{i}{j}{k},FWriteTypeNames{Type{i}(j)-(numTypes+1)}); % Seth Billings%fwrite(fid,Data{i}{j}{k},FWriteTypeNames{Type{i}(j)-9});endendendendendendendfclose ( fid );return
end

PLY文件格式及其MATLAB读写操作相关推荐

  1. hdf5 matlab,hdf5格式的matlab读写操作

    最近要用caffe处理一个multi-label的回归问题,就是输出是一个向量,不是一个具体的数值,这个时候之前的leveldb格式就不凑效了,因为caffe源代码里面默认label是一个数值,网上搜 ...

  2. hdf5格式的matlab读写操作

    最近要用caffe处理一个multi-label的回归问题,就是输出是一个向量,不是一个具体的数值,这个时候之前的leveldb格式就不凑效了,因为caffe源代码里面默认label是一个数值,网上搜 ...

  3. matlab编写文件格式,MATLAB程序设计教程(4)——MATLAB文件操作

    MATLAB程序设计教程(4)--MATLAB文件操作 第4章MATLAB文件操作 4.1 文件的打开与关闭 4.2  文件的读写操作 4.3  数据文件定位 4.1 文件的打开与关闭 4.1.1 文 ...

  4. MATLAB对ply文件格式的读取和显示

    转自:https://blog.csdn.net/lafengxiaoyu/article/details/60574150 在网上搜索这个题目可以找到一些类似的文章,其来源大致都是http://pe ...

  5. matlab用excel的数据,使用MATLAB对excel文件数据的读写操作

    最近建模,刚好用matlab对excel中的数据进行处理,由于自己是个菜鸟,基本都是边问度娘边动手操作.感觉以后还会用得到,在此做个简单的总结,为下一次省点力... excel读写操作:xlsread ...

  6. matlab对nii文件处理,使用Nibabel库对nii格式图像的读写操作

    因为后期主要的研究方向是医学图像处理,而现有手头的大部分数据都是nii格式或者是hdr,img格式的数据,所以首先第一步我们需要解决图像的读写问题. 其实使用OpenCV也可以方便的进行图像读取,但是 ...

  7. matlab %4.3f,MATLAB程序设计教程(4)—MATLAB文件操作

    第4章 MATLAB文件操作 4.1 文件的打开与关闭 4.2 文件的读写操作 4.3 数据文件定位 4.1 文件的打开与关闭 4.1.1 文件的打开 fopen函数的调用格式为: fid= fope ...

  8. QT5 文件读写操作

    QFile Class 1.read读文件 加载文件对象  QFile file("文件地址"); 打开加载的文件file.open(打开方式); 操作文件 关闭打开的文件file ...

  9. OpenCV FileStorage类的数据读写操作

    OpenCV FileStorage类的数据读写操作 OpenCV的许多应用都需要使用数据的存储于读取,例如经过3D校准后的相机,需要存储校准结果矩阵,以方便下次调用该数据:基于机器学习的应用,同样需 ...

最新文章

  1. Leangoo产品白皮书
  2. Spring 注解 @Resource和@Autowired(转)
  3. 将Sql数据库中的表导出到指定文件
  4. 1088. [SCOI2005]扫雷Mine【网格DP】
  5. 数据结构与算法-算法入门-什么是算法-算法的挑战
  6. 【实践驱动开发3-003】TI WL1835MODCOM8 在android的移植 - 软件获取2
  7. python的基本概念_Python必学基础概念
  8. 事件 event
  9. P3690 【模板】Link Cut Tree (动态树)
  10. C9:Unity3D制作智能家居设计软件——导入户型图自动设计(算法剖析+源码实现篇)
  11. 新浪微博开放平台开发步骤简介(适合新手看)
  12. u盘中病毒解决方法 (文件夹变成exe文件)
  13. 自动化C语言第一次月考试卷,c语言程序设计第一次月考试题
  14. 命令提示符 查看已连接Wifi密码(忘记Wifi密码)
  15. noip模拟赛 whzzt-Warmth
  16. 一个华为人19年的工作体会:一颗电容会造成数亿损失[转]
  17. 为macbook双系统的windows装驱动
  18. php和mysql不在一台机器上_MySQL_在同一台机器上运行多个 MySQL 服务,**************************************** - phpStudy...
  19. CNN在自然语言处理上的详细解析与应用
  20. java连接ftp工具类

热门文章

  1. 【解决密码栏不显示】“可能是其他人在试图访问您的google账号....”
  2. Task01:数据载入及初步观察
  3. SwiftUI 中的水平条形图
  4. [GO项目]开源免费在线客服系统-真正免费开源-GOFLY0.3.2发布-极简强大Go语言开发网页客服...
  5. Navigating to current location (/) is not allowed
  6. 计算机在医学教学,计算机辅助教学在医学高校的运用
  7. pytorch模型保存与加载总结
  8. 无法安全地连接到此页面,这可能是因为该站点使用过期的或不安全的 TLS 安全设置.
  9. 嵌入式接口技术基础(粤嵌教学)
  10. 李笑来发出灵魂感叹背后:区块链投资机构正修炼“龟息大法”