-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathloadpcd.m
251 lines (213 loc) · 8.49 KB
/
loadpcd.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
%LOADPCD Load a point cloud from a PCD format file
%
% P = LOADPCD(FNAME) is a set of points loaded from the PCD format
% file FNAME.
%
% For an unorganized point cloud the columns of P represent the 3D points,
% and the rows are: x, y, z, r, g, b, a depending on the FIELDS in the file.
%
% For an organized point cloud P is a 3-dimensional matrix (HxWxN) where the
% N planes are: x, y, z, r, g, b, a depending on the FIELDS in the file. This
% format is useful since the planes z, r, g, b, a can be considered as images.
%
% Notes::
% - Only the x y z field format are currently supported
% - The file can be in ascii or binary format, binary_compressed is not
% supported
%
% See also pclviewer, lspcd, loadpcd.
%
% Copyright (C) 2013, by Peter I. Corke
% TODO
% - handle binary_compressed
function points = loadpcd(fname)
verbose = true;
fp = fopen(fname, 'r');
while true
line = fgetl(fp);
if line(1) == '#'
continue;
end
[field,remain] = strtok(line, ' \t');
remain = strtrim(remain);
switch field
case 'VERSION'
continue;
case 'FIELDS'
FIELDS = remain;
case 'TYPE'
TYPE = remain;
case 'SIZE'
sizes = str2num(remain);
case 'WIDTH'
width = str2num(remain);
case 'HEIGHT'
height = str2num(remain);
case 'POINTS'
npoints = str2num(remain);
case 'COUNT'
count = str2num(remain);
case 'DATA'
mode = remain;
break;
otherwise
warning('unknown field %s\n', field);
end
end
% parse out details of the fields
% numFields the number of fields
% sizes vector of field sizes (in bytes)
% types vector of type identifiers (I U F)
% fields vector of field names (x y z rgb rgba etc)
numFields = numel(sizes);
types = cell2mat(regexp(TYPE,'\s+','split'));
fields = regexp(FIELDS,'\s+','split');
if verbose
% the doco says height > 1 means organized, but some old files have
% height = 1 and width > 1
if height > 1 && width > 1
organized = true;
org = 'organized';
else
organized = false;
org = 'unorganized';
end
fprintf('%s: %s, %s, <%s> %dx%d\n', ...
fname, mode, org, FIELDS, width, height);
fprintf(' %s; %s\n', TYPE, num2str(sizes));
end
if any(count > 1)
error('can only handle 1 element per dimension');
end
switch mode
case 'ascii'
format = '';
for j=1:numFields
switch types(j)
case 'I', typ = 'd';
case 'U', typ = 'u';
case 'F', typ = 'f';
end
format = [format '%' typ num2str(sizes(j)*8)];
end
c = textscan(fp, format, npoints);
points = [];
for j=1:length(c)
points = [points; c{j}'];
end
if size(points,2) ~= npoints
error('incorrect number of points in file: was %d, should be %d', ...
size(points,2), npoints);
end
case 'binary'
format = '';
if true || all(types == types(1)) && all(sizes == sizes(1))
% simple case where all fields have the same length and type
% map IUF -> int, uint, float
switch types(1)
case 'I'
fmt = 'int';
case 'U'
fmt = 'uint';
case 'F'
fmt = 'float';
end
format = [format '*' fmt num2str(sizes(1)*8)];
points = fread(fp, [numFields npoints], format);
else
% more complex case where fields have different length and type
% code contributed by Will
startPos_fp = ftell(fp);
% Just initialize the xyz portion for now
points = zeros(3, npoints);
for i=1:numFields
% map each field sequentially, using fread() skip functionality,
% essentially interleaved reading of the file
% map IUF -> int, uint, float
switch types(i)
case 'I'
fmt = 'int';
case 'U'
fmt = 'uint';
case 'F'
fmt = 'float';
end
format = ['*' fmt num2str(sizes(i)*8)];
fseek(fp, startPos_fp + sum(sizes(1:i-1)), 'bof');
data = fread(fp, [1 npoints], format, sum(sizes)-sizes(i));
switch fields{i}
case 'x'
points(1,:) = data;
case 'y'
points(2,:) = data;
case 'z'
points(3,:) = data;
case {'rgb', 'rgba'}
points(4,:) = data;
end
end
end
case 'binary_compressed'
% binary part of the file contains:
% compressed size of data (uint32)
% uncompressed size of data (uint32)
% compressed data
% junk
compressed_size = fread(fp, 1, 'uint32');
uncompressed_size = fread(fp, 1, 'uint32');
compressed_data = fread(fp, compressed_size, 'uint8')';
uncompressed_data = lzfd(compressed_data);
if length(uncompressed_data) ~= uncompressed_size
error('decompression error');
end
% the data is stored unpacked, that is one field for all points,
% then the next field for all points, etc.
start = 1;
for i=1:numFields
len = sizes(i)*npoints;
switch types(1)
case 'I'
fmt = 'int32';
case 'U'
fmt = 'uint32';
case 'F'
fmt = 'single';
end
field = typecast(uncompressed_data(start:start+len-1), fmt);
start = start + len;
switch fields{i}
case 'x'
points(1,:) = field;
case 'y'
points(2,:) = field;
case 'z'
points(3,:) = field;
case {'rgb', 'rgba'}
points(4,:) = field;
end
end
otherwise
error('unknown DATA mode: %s', mode);
end
if size(points,1) > 3
% convert RGB from float to rgb
rgb = typecast(points(4,:), 'uint32');
switch FIELDS
case 'x y z rgb'
R = double(bitand(255, bitshift(rgb, 16))) /255;
G = double(bitand(255, bitshift(rgb, 8))) /255;
B = double(bitand(255, rgb)) /255;
points = [points(1:3,:); R; G; B];
case 'x y z rgba'
R = double(bitand(255, bitshift(rgb, 24))) /255;
G = double(bitand(255, bitshift(rgb, 16))) /255;
B = double(bitand(255, bitshift(rgb, 8))) /255;
A = double(bitand(255, rgb)) /255;
points = [points(1:3,:); R; G; B; A];
end
end
if organized
% data is an organized point cloud, rearrange it into planes
points = permute( reshape( shiftdim(points, 1), width, height, []), [2 1 3]);
end
fclose(fp);