MATLAB用pcread()读取pcd文件失败【Ply file parsing error: Unable to read ‘ply’ from header】
——
最近在做点云处理,用到了matlab,发现网上大多是C++程序,matlab的案例比较少,记录下自己在这其中遇到的一些问题以及解决方案。
问题
a=pcread('test.pcd');
Error using visionPlyRead
Ply file parsing error: Unable to read 'ply' from header.
Error in pcread (line 47)
properties = visionPlyRead(filename,elementName,requiredProperties,optionalProperties);
- 好像是由于.ply文件和.pcd文件头不一样导致的
pcd文件头是这样
2.而ply文件头是这样
解决方案
有两种解决方法
1.matlab 2018以下版本pcread()函数不能处理pcd格式的文件,因此,升级matlab.
2.还有一种方法是先用一个loadpcd函数导进matlab,然后再用工具箱自带的pointCloud函数把导进的三维点云矩阵变成点云对象,就可以进行其他操作了。以下是loadpcd文件代码,是在MATLAB COMMMUNITY中找到了,链接找不到了,如有侵权,请联系我。
%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);
图片: