PLY文件格式及其MATLAB读写操作
2016-07-13 19:52
507 查看
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 ); end Buf = 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 file PropertyNames = []; % structure of lists of property names while ( 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; end end % % 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.'); end end % % Read a comment. % case 'comment' NumComments = NumComments + 1; Comments{NumComments} = ''; for i = 2 : Count Comments{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},'''.']); end NumElements = 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]); end else error(['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])'); else fclose ( fid ); if ( isempty(CurElement) ) error(['Property definition without element definition: ',Buf]); else error(['Bad property definition: ',Buf]); end end % % End of header. % case 'end_header' break; end end end % % Set reading for specified data format. % if ( isempty ( Format ) ) warning('Data format unspecified, assuming ASCII.'); Format = 'ascii'; end switch Format case 'ascii' Format = 0; case 'binary_little_endian' Format = 1; case 'binary_big_endian' Format = 2; otherwise fclose ( 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' ); else fid = 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/LF i = [i,findstr(Buf,['end_header',10])]; % look for end_header + LF if ( isempty(i) ) tmp = tmp + BufSize; Buf = [Buf(BufSize+1:BufSize+10),char(fread(fid,BufSize,'uchar')')]; end end % % 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 : NumProperties Token = getfield(CurPropertyTypes,CurPropertyNames{j}); if ( strcmpi(Token{1},'list') ) Type(j) = 1; else Type(j) = 0; end % % Glenn Ramsey 20120827 % Initialise Type2{} to prevent uninitialised value error. % Type2{j} = ''; end % % Parse the buffer. % if ( ~any(Type) ) % no list types Data = reshape ( ... Buf(BufOff:BufOff+ElementCount(i)*NumProperties-1), ... NumProperties, ElementCount(i) )'; BufOff = BufOff + ElementCount(i) * NumProperties; else ListData = cell(NumProperties,1); for k = 1 : NumProperties ListData{k} = cell(ElementCount(i),1); end % % list type % for j = 1 : ElementCount(i) for k = 1 : NumProperties if ( ~Type(k) ) Data(j,k) = Buf(BufOff); BufOff = BufOff + 1; else tmp = Buf(BufOff); ListData{k}{j} = Buf(BufOff+(1:tmp))'; BufOff = BufOff + tmp + 1; end end end end % % Read binary data. % else % translate PLY data type names to MATLAB data type names ListFlag = 0; % = 1 if there is a list type SameFlag = 1; % = 1 if all types are the same for j = 1 : NumProperties Token = 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}); else fclose(fid); error(['Unknown property data type, ''',Token{1},''', in ', ... ElementNames{i},'.',CurPropertyNames{j},'.']); end else % list type if ( 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}; else fclose(fid); error(['Unknown property data type, ''list ',Token{2},' ',Token{3},''', in ', ... ElementNames{i},'.',CurPropertyNames{j},'.']); end else fclose(fid); error(['Invalid list syntax in ',ElementNames{i},'.',CurPropertyNames{j},'.']); end end end % read file if ( ~ListFlag ) % % No list types, all the same type (fast) % if ( SameFlag ) Data = fread(fid,[NumProperties,ElementCount(i)],Type{1})'; % % No list types, mixed type. % else Data = zeros(ElementCount(i),NumProperties); for j = 1 : ElementCount(i) for k = 1 : NumProperties Data(j,k) = fread(fid,1,Type{k}); end end end else ListData = cell(NumProperties,1); for k = 1 : NumProperties ListData{k} = cell(ElementCount(i),1); end if ( 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 SkipNum fseek(fid,Position + TypeSize(1),-1); % seek back to after first count if ( isempty(Miss) ) % all counts are SkipNum Buf = fread(fid,[SkipNum,BufSize],[int2str(SkipNum),'*',Type2{1}],TypeSize(1))'; fseek(fid,-TypeSize(1),0); % undo last skip for k = 1:BufSize ListData{1}{j+k} = Buf(k,:); end j = 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)-1 ListData{1}{j+k} = Buf2(k,:); end j = 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); end end else % % List type(s), multiple properties (slow) % Data = zeros(ElementCount(i),NumProperties); for j = 1:ElementCount(i) for k = 1:NumProperties if ( isempty(Type2{k}) ) Data(j,k) = fread(fid,1,Type{k}); else tmp = fread(fid,1,Type{k}); ListData{k}{j} = fread(fid,[1,tmp],Type2{k}); end end end end end end % % Put data into Elements structure % for k = 1 : NumProperties if ( ( ~Format & ~Type(k) ) || (Format & isempty(Type2{k})) ) eval(['Elements.',ElementNames{i},'.',CurPropertyNames{k},'=Data(:,k);']); else eval(['Elements.',ElementNames{i},'.',CurPropertyNames{k},'=ListData{k};']); end end end clear Data clear 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; end end if ( any(strcmp(Names,'x')) & any(strcmp(Names,'y')) & any(strcmp(Names,'z')) ) eval(['varargout{1}=[Elements.',Name,'.x,Elements.',Name,'.y,Elements.',Name,'.z];']); else varargout{1} = zeros(1,3); end varargout{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; end end if ( ~isempty(Names) ) % find vertex indices property subfield PropertyName = {'vertex_indices','vertex_indexes','vertex_index','indices','indexes'}; for i = 1 : length(PropertyName) if ( any(strcmp(Names,PropertyName{i})) ) PropertyName = PropertyName{i}; break; end end % % 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 : N Elements(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); end end % % Add 1 to each vertex value; PLY vertices are zero based. % Elements = Elements(:,1:N+Extra) + 1; end end else varargout{1} = Comments; end return 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'; end end [ 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 : NumElements eval(['tmp=isa(Elements.',ElementNames{i},',''struct'');']); if ( tmp ) eval(['PropertyNames{i}=fieldnames(Elements.',ElementNames{i},');']); else PropertyNames{i} = []; end if ( ~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); else ElementCount(i) = 0; end fprintf(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.'); end if ( iscell(Data{i}{j}) ) Type{i}(j) = numTypes + 1; % Seth Billings %Type{i}(j) = 9; Data{i}{j} = Data{i}{j}{1}; end for k = 1 : length(MatlabTypeNames) if ( isa(Data{i}{j},MatlabTypeNames{k}) ) Type{i}(j) = Type{i}(j) + k; break; end end if ( ~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 integer MinValue = min(min(Data{i}{j})); MaxValue = max(max(Data{i}{j})); % 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; end end end else % cell array data eval(['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}); end if tmp % data is integer MinValue = 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; end end end % convert double to single if specified if 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; end if Type{i}(j) <= numTypes % Seth Billings %if Type{i}(j) <= 8 fprintf(fid,'property %s %s\n',PlyTypeNames{Type{i}(j)},PropertyNames{i}{j}); else fprintf(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}); end end end fprintf(fid,'end_header\n'); switch Format case '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; end for i = 1 : NumElements if ~isempty(PropertyNames{i}) if ~Format % write ASCII data for k = 1:ElementCount(i) for j = 1:length(PropertyNames{i}) if Type{i}(j) <= numTypes % Seth Billings %if Type{i}(j) <= 8 fprintf(fid,[PrintfTypeChar{Type{i}(j)},' '],Data{i}{j}(k)); else fprintf(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})); end end fprintf(fid,'\n'); end else % write binary data if 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}(:)'; end fwrite(fid,tmp,FWriteTypeNames{Type{i}(j)}); elseif all(Type{i} > numTypes) % Seth Billings %elseif all(Type{i} > 8) % only list types Type{i} = Type{i} - (numTypes+1); % Seth Billings %Type{i} = Type{i} - 9; if length(PropertyNames{i}) == 1 % only one list property tmp = FWriteTypeNames{Type{i}(1)}; for k = 1:ElementCount(i) fwrite(fid,length(Data{i}{1}{k}),'uchar'); fwrite(fid,Data{i}{1}{k},tmp); end else % multiple list properties for 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)}); end end end else % mixed type for k = 1:ElementCount(i) for j = 1:length(PropertyNames{i}) if Type{i}(j) <= numTypes % Seth Billings %if Type{i}(j) <= 8 fwrite(fid,Data{i}{j}(k),FWriteTypeNames{Type{i}(j)}); else fwrite(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}); end end end end end end end fclose ( fid ); return end
相关文章推荐
- Matlab GUI的文件打开和保存uigetfile uigetdir
- MATLAB图像处理工具箱
- Matlab: 新学到的函数
- harris角点检测计算详细步骤
- matlab 三个向量数据绘制曲面图
- 图解在Matlab中初步操作一下3D图形学算法
- 决策树--matlab自带函数
- Matlab:基本数据类型[转载]
- Matlab实现决策树算法进行数字识别
- Matlab + VS | Matlab2014a + VS2010 Win7 混编调试
- DAV 入门之 MATLAB (6):Simulink
- DAV 入门之 MATLAB (5):保存代码
- DAV 入门之 MATLAB (4):明确设计
- MATLAB三维图形的投影
- DAV 入门之 MATLAB (2):命令行窗口,最方便的平台
- 混沌时间序列的几个例子
- MATLAB的solve函数
- DAV 入门之 MATLAB (1):不一样的入门
- 对cell赋值 matlab
- 样本不同特征构成的协方差矩阵