pose_format/src
index.ts
Description or Title for the TypeScript file
1import {PoseBodyModel, PoseHeaderModel} from "./types";
2import {Buffer} from "buffer";
3import {parsePose} from "./parser";
4import * as fs from "fs";
5
6export * from './types';
7
8export class Pose {
9 constructor(public header: PoseHeaderModel, public body: PoseBodyModel) {
10 }
11
12 static from(buffer: Buffer) {
13 const pose = parsePose(buffer);
14 return new Pose(pose.header, pose.body);
15 }
16
17 static async fromLocal(path: string) {
18 const buffer = fs.readFileSync(path);
19 return Pose.from(buffer);
20 }
21
22 static async fromRemote(url: string, abortController?: AbortController) {
23 const init: RequestInit = {};
24 if (abortController) {
25 init.signal = abortController.signal;
26 }
27 const res = await fetch(url, init);
28 if (!res.ok) {
29 let message = res.statusText ?? String(res.status);
30 try {
31 const json = await res.json();
32 message = json.message;
33 } catch (e) {
34 }
35 throw new Error(message);
36 }
37 const buffer = Buffer.from(await res.arrayBuffer());
38 return Pose.from(buffer);
39 }
40}
parser.ts
Description or Title for the TypeScript file
1import {Parser} from "binary-parser";
2import {PoseBodyFrameModel, PoseBodyModel, PoseHeaderModel, PoseModel} from "./types";
3
4
5function newParser() {
6 return new Parser().endianess("little");
7}
8
9function componentHeaderParser() {
10 const limbParser = newParser()
11 .uint16("from")
12 .uint16("to");
13 const colorParser = newParser()
14 .uint16("R")
15 .uint16("G")
16 .uint16("B");
17
18 const strParser = newParser()
19 .uint16("_chars")
20 .string("text", {length: "_chars"});
21
22
23 return newParser()
24 .uint16("_name")
25 .string("name", {length: "_name"})
26 .uint16("_format",)
27 .string("format", {length: "_format"})
28 .uint16("_points")
29 .uint16("_limbs")
30 .uint16("_colors")
31 .array("points", {
32 type: strParser,
33 formatter: (arr: any) => arr.map((item: any) => item.text),
34 length: "_points"
35 })
36 .array("limbs", {
37 type: limbParser,
38 length: "_limbs"
39 })
40 .array("colors", {
41 type: colorParser,
42 length: "_colors"
43 });
44}
45
46function getHeaderParser() {
47 const componentParser = componentHeaderParser();
48
49 return newParser()
50 .floatle("version")
51 .uint16("width")
52 .uint16("height")
53 .uint16("depth")
54 .uint16("_components")
55 .array("components", {
56 type: componentParser,
57 length: "_components"
58 })
59 // @ts-ignore
60 .saveOffset('headerLength')
61}
62
63
64function getBodyParserV0_0(header: PoseHeaderModel) {
65 let personParser: any = newParser()
66 .int16("id");
67 header.components.forEach(component => {
68 let pointParser: any = newParser();
69 Array.from(component.format).forEach(c => {
70 pointParser = pointParser.floatle(c);
71 });
72
73 personParser = personParser.array(component.name, {
74 "type": pointParser,
75 "length": component._points
76 });
77 });
78
79 const frameParser = newParser()
80 .uint16("_people")
81 .array("people", {
82 type: personParser,
83 length: "_people"
84 });
85
86 return newParser()
87 .seek(header.headerLength)
88 .uint16("fps")
89 .uint16("_frames")
90 .array("frames", {
91 type: frameParser,
92 length: "_frames"
93 })
94}
95
96function parseBodyV0_0(header: PoseHeaderModel, buffer: Buffer): PoseBodyModel {
97 return getBodyParserV0_0(header).parse(buffer) as unknown as PoseBodyModel
98}
99
100function parseBodyV0_1(header: PoseHeaderModel, buffer: Buffer): PoseBodyModel {
101 const _points = header.components.map(c => c.points.length).reduce((a, b) => a + b, 0);
102 const _dims = Math.max(...header.components.map(c => c.format.length)) - 1;
103
104 const infoParser = newParser()
105 .seek(header.headerLength)
106 .uint16("fps")
107 .uint16("_frames")
108 .uint16("_people");
109
110 const info = infoParser.parse(buffer);
111
112 // Issue https://github.com/keichi/binary-parser/issues/208
113 const parseFloat32Array = (length: number, offset: number) => {
114 const dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.length);
115 let currentOffset = offset;
116 const vars = {
117 data: new Float32Array(length),
118 offset: 0
119 };
120
121 for (let i = 0; i < vars.data.length; i++) {
122 let $tmp1 = dataView.getFloat32(currentOffset, true);
123 currentOffset += 4;
124 vars.data[i] = $tmp1
125 }
126 vars.offset = currentOffset;
127
128 return vars;
129 };
130
131 const data = parseFloat32Array(info._frames * info._people * _points * _dims, header.headerLength + 6)
132 const confidence = parseFloat32Array(info._frames * info._people * _points, data.offset)
133
134 function frameRepresentation(i: number) {
135 const people: any[] = new Array(info._people);
136 for (let j = 0; j < info._people; j++) {
137 const person: any = {};
138 people[j] = person;
139 let k = 0;
140 header.components.forEach(component => {
141 person[component.name] = [];
142
143 for (let l = 0; l < component.points.length; l++) {
144 const offset = i * (info._people * _points) + j * _points;
145 const place = offset + k + l;
146 const point: any = {"C": confidence.data[place]};
147 [...component.format].forEach((dim, dimIndex) => {
148 if (dim !== "C") {
149 point[dim] = data.data[place * _dims + dimIndex];
150 }
151 });
152 person[component.name].push(point)
153 }
154 k += component.points.length;
155 });
156 }
157 return {people}
158 }
159
160 const frames = new Proxy({}, {
161 get: function (target: any, name: any) {
162 if (name === 'length') {
163 return info._frames
164 }
165 return frameRepresentation(name);
166 }
167 }) as PoseBodyFrameModel[];
168
169
170 return {
171 ...info,
172 frames
173 } as PoseBodyModel;
174
175}
176
177const headerParser = getHeaderParser();
178
179export function parsePose(buffer: Buffer): PoseModel {
180 const header = headerParser.parse(buffer) as unknown as PoseHeaderModel;
181
182 let body: PoseBodyModel;
183 const version = Math.round(header.version * 1000) / 1000;
184 switch (version) {
185 case 0:
186 body = parseBodyV0_0(header, buffer);
187 break;
188
189 case 0.1:
190 body = parseBodyV0_1(header, buffer);
191 break;
192
193 default:
194 throw new Error("Parsing this body version is not implemented - " + header.version);
195 }
196
197 return {header, body};
198}