pcd 文件
参考:PCL:点云数据(*.pcd)文件格式详解
二进制格式
二进制格式的 pcd 文件读取
- 读取 header --> 通过 parsePCDHeader 读取到 header 中每个字段的值
- 计算每个字段的偏移量 --> 通过 header.size 计算 生成 offset
- 将转化为 arraybuffer 后的二进制数据,导入到 DataView 通过遍历生成 position, normal, color 数据
{
"data": "binary",
"headerLen": 216,
"str": "\nVERSION 0.7\nFIELDS x y z intensity label timestamp\nSIZE 4 4 4 1 1 8\nTYPE F F F U U U\nCOUNT 1 1 1 1 1 1\nWIDTH 54513\nHEIGHT 1\nVIEWPOINT 0 0 0 1 0 0 0\nPOINTS 54513\nDATA binary\n",
"version": 0.7,
"fields": [ // 每个字段
"x",
"y",
"z",
"intensity",
"label",
"timestamp"
],
"size": [ // 用字节数指定每一个维度的大小 用来计算偏移量
4,
4,
4,
1,
1,
8
],
"type": [
"F",
"F",
"F",
"U",
"U",
"U"
],
"count": [
1,
1,
1,
1,
1,
1
],
"width": 54513,
"height": 1,
"viewpoint": "0 0 0 1 0 0 0",
"points": 54513,
"offset": { // 每个字段的偏移量 (字节)
"x": 0,
"y": 4,
"z": 8,
"intensity": 12,
"label": 13,
"timestamp": 14
},
"rowSize": 22 // 每行占多少字节
}
生成 position, normal, color 代码
function parsePCDBinary(pcdHeader, data) {
const position = [];
const normal = [];
const color = [];
const dataview = new DataView(data, pcdHeader.headerLen);
const offset = pcdHeader.offset;
for (let i = 0, row = 0; i < pcdHeader.points; i++, row += pcdHeader.rowSize) {
if (offset.x !== void 0) {
position.push(dataview.getFloat32(row + offset.x, LITTLE_ENDIAN));
position.push(dataview.getFloat32(row + offset.y, LITTLE_ENDIAN));
position.push(dataview.getFloat32(row + offset.z, LITTLE_ENDIAN));
}
if (offset.rgb !== void 0) {
color.push(dataview.getUint8(row + offset.rgb + 0));
color.push(dataview.getUint8(row + offset.rgb + 1));
color.push(dataview.getUint8(row + offset.rgb + 2));
}
if (offset.normal_x !== void 0) {
normal.push(dataview.getFloat32(row + offset.normal_x, LITTLE_ENDIAN));
normal.push(dataview.getFloat32(row + offset.normal_y, LITTLE_ENDIAN));
normal.push(dataview.getFloat32(row + offset.normal_z, LITTLE_ENDIAN));
}
}
return { position, normal, color };
}