@webex/ladon-ts 4.5.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/build/module/config.json.js +26 -0
  3. package/build/module/config.json.js.map +1 -0
  4. package/build/module/index.d.ts +3 -0
  5. package/build/module/index.js +41 -8
  6. package/build/module/index.js.map +1 -0
  7. package/build/module/lib/config-builder.d.ts +180 -0
  8. package/build/module/lib/config-builder.js +336 -0
  9. package/build/module/lib/config-builder.js.map +1 -0
  10. package/build/module/lib/config-types.d.ts +98 -0
  11. package/build/module/lib/config-types.js +6 -0
  12. package/build/module/lib/config-types.js.map +1 -0
  13. package/build/module/lib/config.d.ts +30 -105
  14. package/build/module/lib/config.js +22 -151
  15. package/build/module/lib/config.js.map +1 -0
  16. package/build/module/lib/generator.d.ts +3 -1
  17. package/build/module/lib/generator.js +212 -273
  18. package/build/module/lib/generator.js.map +1 -0
  19. package/build/module/lib/pipeline.d.ts +11 -8
  20. package/build/module/lib/pipeline.js +158 -213
  21. package/build/module/lib/pipeline.js.map +1 -0
  22. package/build/module/lib/preload.d.ts +9 -0
  23. package/build/module/lib/preload.js +8 -0
  24. package/build/module/lib/preload.js.map +1 -0
  25. package/build/module/lib/renderer/blur-renderer.d.ts +6 -5
  26. package/build/module/lib/renderer/blur-renderer.js +102 -126
  27. package/build/module/lib/renderer/blur-renderer.js.map +1 -0
  28. package/build/module/lib/renderer/ladon-renderer.d.ts +3 -2
  29. package/build/module/lib/renderer/passthrough-renderer.d.ts +6 -5
  30. package/build/module/lib/renderer/passthrough-renderer.js +25 -44
  31. package/build/module/lib/renderer/passthrough-renderer.js.map +1 -0
  32. package/build/module/lib/renderer/replacement-renderer.d.ts +9 -6
  33. package/build/module/lib/renderer/replacement-renderer.js +84 -99
  34. package/build/module/lib/renderer/replacement-renderer.js.map +1 -0
  35. package/build/module/lib/renderer/webgl-renderer.d.ts +12 -3
  36. package/build/module/lib/renderer/webgl-renderer.js +168 -115
  37. package/build/module/lib/renderer/webgl-renderer.js.map +1 -0
  38. package/build/module/lib/shared-resource-manager.d.ts +40 -31
  39. package/build/module/lib/shared-resource-manager.js +151 -189
  40. package/build/module/lib/shared-resource-manager.js.map +1 -0
  41. package/build/module/lib/util.d.ts +10 -0
  42. package/build/module/lib/util.js +92 -179
  43. package/build/module/lib/util.js.map +1 -0
  44. package/build/module/lib/version.d.ts +1 -1
  45. package/build/module/lib/version.js +5 -2
  46. package/build/module/lib/version.js.map +1 -0
  47. package/package.json +21 -5
  48. package/build/module/lib/renderer/ladon-renderer.js +0 -2
  49. package/build/module/lib/renderer.js +0 -6
@@ -1,273 +1,212 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import * as ort from 'onnxruntime-web';
11
- import { sharedResourceManager } from './shared-resource-manager';
12
- export class LocalGenerator {
13
- constructor(config) {
14
- this.config = config;
15
- this.lastMaskGenerationTime = 0;
16
- this.lastMask = new ort.Tensor('float32', new Float32Array(this.config.mask.output_size.height * this.config.mask.output_size.width), [1, 1, this.config.mask.output_size.height, this.config.mask.output_size.width]);
17
- this.lastResult = {
18
- data: this.lastMask.data,
19
- facesAndLandmarks: { data: new Float32Array(0), dims: [] },
20
- gesture: new Float32Array(0),
21
- motion: 0,
22
- timestamp: 0,
23
- warm: false,
24
- };
25
- }
26
- /**
27
- * This method preprocesses an input Uint8ClampedArray to a Float32Array
28
- * while maintaining memory efficiency by reusing a class-scoped output buffer.
29
- * If the model rank is 4 (e.g., newer tiny model), it sets an alpha channel value.
30
- *
31
- * @param {Uint8ClampedArray} input - The input data to be preprocessed
32
- * @param {Float32Array} alpha - The alpha channel data
33
- * @returns {Float32Array} - The processed data
34
- */
35
- preprocess(input, alpha) {
36
- var _a;
37
- const { model_rank, input_size, output_size } = this.config.mask;
38
- const { height, width } = input_size;
39
- const numImagePixels = height * width;
40
- // Initialize the output buffer if it is not already set
41
- (_a = this.output) !== null && _a !== void 0 ? _a : (this.output = new Float32Array(numImagePixels * model_rank));
42
- // In-place modification of class-scoped output buffer
43
- const channelFlipOffset = 2;
44
- const numInputPixels = input.length / 4;
45
- // Loop over all color channels in the image
46
- for (let channel = 0; channel < 3; channel++) {
47
- // For each pixel in the input image...
48
- for (let pixel = 0; pixel < numInputPixels; pixel++) {
49
- // ...copy the color channel value from input to output, potentially
50
- // potentially flipping the color channel order for the tiny.
51
- this.output[pixel + channel * numImagePixels] =
52
- input[pixel * 4 + Math.abs(channelFlipOffset - channel)];
53
- }
54
- }
55
- // Scaling factors for width and height based on the ratio of output to input sizes
56
- const widthScale = output_size.width / width;
57
- const heightScale = output_size.height / height;
58
- // Iterate over each pixel in the width of the input image
59
- for (let x = 0; x < width; x++) {
60
- const nearestNeighborX = Math.floor(x * widthScale);
61
- // Iterate over each pixel in the height of the input image
62
- for (let y = 0; y < height; y++) {
63
- const nearestNeighborY = Math.floor(y * heightScale);
64
- const maskIdx = nearestNeighborX + nearestNeighborY * output_size.width;
65
- const outputIdx = x + y * width + 3 * numImagePixels;
66
- // Normalize the alpha value to range between 0 and 1, and scale it to the range of 0-255
67
- // This step is necessary because the rendering pipeline expects alpha values in the [0, 255] range
68
- const normalizedValue = Math.min(Math.max(alpha[maskIdx], 0), 255);
69
- // Assign the normalized value to the output at the computed index
70
- this.output[outputIdx] = normalizedValue;
71
- }
72
- }
73
- return this.output;
74
- }
75
- getTimeSinceLastGeneration() {
76
- return Date.now() - this.lastMaskGenerationTime;
77
- }
78
- getLadonOutput(input, timestamp) {
79
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
80
- return __awaiter(this, void 0, void 0, function* () {
81
- if (!this.maskModel) {
82
- throw new Error('[ladon-ts] - mask model not loaded.');
83
- }
84
- if (this.getTimeSinceLastGeneration() < this.config.mask.generation_interval_ms) {
85
- return {
86
- data: this.lastMask.data,
87
- facesAndLandmarks: this.lastResult.facesAndLandmarks,
88
- gesture: this.lastResult.gesture,
89
- motion: this.lastResult.motion,
90
- timestamp: this.lastResult.timestamp,
91
- warm: false,
92
- };
93
- }
94
- this.lastMaskGenerationTime = Date.now();
95
- const imageTensor = new ort.Tensor('float32', this.preprocess(input, this.lastMask.data), [
96
- 1,
97
- this.config.mask.model_rank,
98
- this.config.mask.input_size.height,
99
- this.config.mask.input_size.width,
100
- ]);
101
- const results = yield this.maskModel.run({ input: imageTensor });
102
- this.lastMask = results.segmentation;
103
- this.lastResult = {
104
- data: (_a = this.lastMask.data) !== null && _a !== void 0 ? _a : new Float32Array(0),
105
- facesAndLandmarks: {
106
- data: (_c = (_b = results.faces_and_landmarks) === null || _b === void 0 ? void 0 : _b.data) !== null && _c !== void 0 ? _c : new Float32Array(0),
107
- dims: (_e = (_d = results.faces_and_landmarks) === null || _d === void 0 ? void 0 : _d.dims) !== null && _e !== void 0 ? _e : [],
108
- },
109
- gesture: (_g = (_f = results.gesture) === null || _f === void 0 ? void 0 : _f.data) !== null && _g !== void 0 ? _g : new Float32Array(0),
110
- motion: (_j = (_h = results.motion) === null || _h === void 0 ? void 0 : _h.data[0]) !== null && _j !== void 0 ? _j : 0,
111
- timestamp,
112
- warm: true,
113
- };
114
- return this.lastResult;
115
- });
116
- }
117
- load() {
118
- var _a;
119
- return __awaiter(this, void 0, void 0, function* () {
120
- const modelUrl = yield sharedResourceManager.getModelUrl(this.config);
121
- // Attempt to retrieve a preloaded InferenceSession from the shared resource manager.
122
- this.maskModel = sharedResourceManager.getModelSession(modelUrl);
123
- // If the model is not preloaded, load it from the provided model URL.
124
- (_a = this.maskModel) !== null && _a !== void 0 ? _a : (this.maskModel = yield sharedResourceManager.preloadModel(this.config));
125
- if (!this.maskModel) {
126
- throw new Error('Failed to load the ONNX model.');
127
- }
128
- });
129
- }
130
- isLoaded() {
131
- return !!this.maskModel;
132
- }
133
- /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
134
- postRender(_) {
135
- return __awaiter(this, void 0, void 0, function* () {
136
- // empty for local generator
137
- });
138
- }
139
- destroy() {
140
- // empty for local generator
141
- }
142
- }
143
- export class NullGenerator {
144
- constructor(config) {
145
- this.config = config;
146
- this.lastMask = new Float32Array(this.config.mask.output_size.height * this.config.mask.output_size.width);
147
- }
148
- /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
149
- getLadonOutput(_) {
150
- return __awaiter(this, void 0, void 0, function* () {
151
- return {
152
- data: this.lastMask,
153
- facesAndLandmarks: { data: new Float32Array(0), dims: [] },
154
- gesture: new Float32Array(0),
155
- motion: 0,
156
- timestamp: 0,
157
- warm: false,
158
- };
159
- });
160
- }
161
- load() {
162
- return __awaiter(this, void 0, void 0, function* () {
163
- // empty for null generator
164
- });
165
- }
166
- isLoaded() {
167
- return true;
168
- }
169
- /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
170
- postRender(_) {
171
- return __awaiter(this, void 0, void 0, function* () {
172
- // empty for null generator
173
- });
174
- }
175
- destroy() {
176
- // empty for null generator
177
- }
178
- }
179
- export class WorkerGenerator {
180
- constructor(config) {
181
- this.config = config;
182
- this.newMask = true;
183
- this.lastMask = new Float32Array(this.config.mask.output_size.height * this.config.mask.output_size.width);
184
- this.lastResult = {
185
- data: this.lastMask,
186
- facesAndLandmarks: { data: new Float32Array(0), dims: [] },
187
- gesture: new Float32Array(0),
188
- motion: 0,
189
- timestamp: 0,
190
- warm: false,
191
- };
192
- }
193
- /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
194
- getLadonOutput(_) {
195
- return __awaiter(this, void 0, void 0, function* () {
196
- const toReturn = {
197
- data: this.lastMask,
198
- facesAndLandmarks: this.lastResult.facesAndLandmarks,
199
- gesture: this.lastResult.gesture,
200
- motion: this.lastResult.motion,
201
- timestamp: this.lastResult.timestamp,
202
- warm: this.newMask,
203
- };
204
- this.newMask = false;
205
- return toReturn;
206
- });
207
- }
208
- load() {
209
- var _a;
210
- return __awaiter(this, void 0, void 0, function* () {
211
- this.worker = sharedResourceManager.getWorker();
212
- (_a = this.worker) !== null && _a !== void 0 ? _a : (this.worker = yield sharedResourceManager.initializeWorker(this.config));
213
- if (!this.worker) {
214
- throw new Error('[ladon-ts] - worker is not defined.');
215
- }
216
- const modelUrl = yield sharedResourceManager.getModelUrl(this.config);
217
- const workerConfig = {
218
- base_url: this.config.base_url,
219
- input: this.config.input,
220
- mask: Object.assign(Object.assign({}, this.config.mask), { model_url_resolver: modelUrl }),
221
- wasm_uri: this.config.wasm_uri,
222
- render: { type: 'passthrough' },
223
- };
224
- this.worker.postMessage({ type: 'init', config: workerConfig });
225
- let resolutionCb;
226
- const result = new Promise((resolve) => {
227
- resolutionCb = resolve;
228
- });
229
- this.worker.onmessage = (event) => {
230
- if (event.data.status === 'generated') {
231
- this.lastMask = event.data.mask;
232
- this.lastResult = {
233
- data: event.data.mask,
234
- facesAndLandmarks: event.data.facesAndLandmarks,
235
- gesture: event.data.gesture,
236
- motion: event.data.motion,
237
- timestamp: event.data.timestamp,
238
- warm: true,
239
- };
240
- this.newMask = true;
241
- }
242
- else {
243
- const workerUrl = sharedResourceManager.getWorkerUrl();
244
- if (workerUrl) {
245
- URL.revokeObjectURL(workerUrl);
246
- }
247
- resolutionCb === null || resolutionCb === void 0 ? void 0 : resolutionCb();
248
- }
249
- };
250
- return result;
251
- });
252
- }
253
- isLoaded() {
254
- return !!this.worker;
255
- }
256
- postRender(input, timestamp) {
257
- return __awaiter(this, void 0, void 0, function* () {
258
- // claim ownership of the input tensor's buffer and forward to worker
259
- if (!this.worker) {
260
- throw new Error('[ladon-ts] - worker is not defined.');
261
- }
262
- this.worker.postMessage({
263
- type: 'generate',
264
- image: input,
265
- timestamp,
266
- }, [input.buffer]);
267
- });
268
- }
269
- destroy() {
270
- sharedResourceManager.terminateWorker();
271
- }
272
- }
273
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxLQUFLLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQztBQUd2QyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQTZCbEUsTUFBTSxPQUFPLGNBQWM7SUFPdkIsWUFBNEIsTUFBc0I7UUFBdEIsV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFIMUMsMkJBQXNCLEdBQUcsQ0FBQyxDQUFDO1FBSS9CLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUMxQixTQUFTLEVBQ1QsSUFBSSxZQUFZLENBQ1osSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUMzRSxFQUNELENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FDbEYsQ0FBQztRQUNGLElBQUksQ0FBQyxVQUFVLEdBQUc7WUFDZCxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJO1lBQ3hCLGlCQUFpQixFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUU7WUFDMUQsT0FBTyxFQUFFLElBQUksWUFBWSxDQUFDLENBQUMsQ0FBQztZQUM1QixNQUFNLEVBQUUsQ0FBQztZQUNULFNBQVMsRUFBRSxDQUFDO1lBQ1osSUFBSSxFQUFFLEtBQUs7U0FDZCxDQUFDO0lBQ04sQ0FBQztJQUVEOzs7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
1
+ import * as c from "onnxruntime-web";
2
+ import { sharedResourceManager as n } from "./shared-resource-manager.js";
3
+ class R {
4
+ constructor(t) {
5
+ this.config = t, this.lastMaskGenerationTime = 0;
6
+ const { height: a, width: e } = this.config.mask.outputSize;
7
+ this.lastMask = new c.Tensor("float32", new Float32Array(a * e), [
8
+ 1,
9
+ 1,
10
+ a,
11
+ e
12
+ ]), this.lastResult = {
13
+ data: this.lastMask.data,
14
+ facesAndLandmarks: { data: new Float32Array(0), dims: [] },
15
+ gesture: new Float32Array(0),
16
+ motion: 0,
17
+ timestamp: 0,
18
+ warm: !1
19
+ };
20
+ }
21
+ /**
22
+ * This method preprocesses an input Uint8ClampedArray to a Float32Array
23
+ * while maintaining memory efficiency by reusing a class-scoped output buffer.
24
+ * If the model rank is 4 (e.g., newer tiny model), it sets an alpha channel value.
25
+ *
26
+ * @param {Uint8ClampedArray} input - The input data to be preprocessed
27
+ * @param {Float32Array} alpha - The alpha channel data
28
+ * @returns {Float32Array} - The processed data
29
+ */
30
+ preprocess(t, a) {
31
+ const {
32
+ modelRank: e,
33
+ inputSize: r,
34
+ outputSize: s
35
+ } = this.config.mask, { height: o, width: l } = r, d = o * l;
36
+ this.output ?? (this.output = new Float32Array(d * e));
37
+ const k = t.length / 4;
38
+ for (let i = 0; i < 3; i++)
39
+ for (let h = 0; h < k; h++)
40
+ this.output[h + i * d] = t[h * 4 + (2 - i)];
41
+ const w = s.width / l, g = s.height / o;
42
+ for (let i = 0; i < l; i++) {
43
+ const h = Math.floor(i * w);
44
+ for (let m = 0; m < o; m++) {
45
+ const f = Math.floor(m * g), p = h + f * s.width, M = i + m * l + 3 * d, y = Math.min(Math.max(a[p], 0), 255);
46
+ this.output[M] = y;
47
+ }
48
+ }
49
+ return this.output;
50
+ }
51
+ getTimeSinceLastGeneration() {
52
+ return Date.now() - this.lastMaskGenerationTime;
53
+ }
54
+ async getLadonOutput(t, a) {
55
+ var s, o, l, d;
56
+ if (!this.maskModel)
57
+ throw new Error("[ladon-ts] - mask model not loaded.");
58
+ if (this.getTimeSinceLastGeneration() < this.config.mask.generationIntervalMs)
59
+ return {
60
+ data: this.lastMask.data,
61
+ facesAndLandmarks: this.lastResult.facesAndLandmarks,
62
+ gesture: this.lastResult.gesture,
63
+ motion: this.lastResult.motion,
64
+ timestamp: this.lastResult.timestamp,
65
+ warm: !1
66
+ };
67
+ this.lastMaskGenerationTime = Date.now();
68
+ const e = new c.Tensor("float32", this.preprocess(t, this.lastMask.data), [
69
+ 1,
70
+ this.config.mask.modelRank,
71
+ this.config.mask.inputSize.height,
72
+ this.config.mask.inputSize.width
73
+ ]), r = await this.maskModel.run({ input: e });
74
+ return this.lastMask = r.segmentation, this.lastResult = {
75
+ data: this.lastMask.data ?? new Float32Array(0),
76
+ facesAndLandmarks: {
77
+ data: ((s = r.faces_and_landmarks) == null ? void 0 : s.data) ?? new Float32Array(0),
78
+ dims: ((o = r.faces_and_landmarks) == null ? void 0 : o.dims) ?? []
79
+ },
80
+ gesture: ((l = r.gesture) == null ? void 0 : l.data) ?? new Float32Array(0),
81
+ motion: ((d = r.motion) == null ? void 0 : d.data[0]) ?? 0,
82
+ timestamp: a,
83
+ warm: !0
84
+ }, this.lastResult;
85
+ }
86
+ async load() {
87
+ const t = await n.resolveUri(
88
+ this.config,
89
+ this.config.mask.modelUri
90
+ );
91
+ if (this.maskModel = n.getModelSession(t), this.maskModel ?? (this.maskModel = await n.loadModel(this.config)), !this.maskModel)
92
+ throw new Error("Failed to load the ONNX model.");
93
+ }
94
+ isLoaded() {
95
+ return !!this.maskModel;
96
+ }
97
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
98
+ async postRender(t) {
99
+ }
100
+ destroy() {
101
+ }
102
+ }
103
+ class L {
104
+ constructor(t) {
105
+ this.config = t, this.lastMask = new Float32Array(
106
+ this.config.mask.outputSize.height * this.config.mask.outputSize.width
107
+ );
108
+ }
109
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
110
+ async getLadonOutput(t) {
111
+ return {
112
+ data: this.lastMask,
113
+ facesAndLandmarks: { data: new Float32Array(0), dims: [] },
114
+ gesture: new Float32Array(0),
115
+ motion: 0,
116
+ timestamp: 0,
117
+ warm: !1
118
+ };
119
+ }
120
+ async load() {
121
+ }
122
+ isLoaded() {
123
+ return !0;
124
+ }
125
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
126
+ async postRender(t) {
127
+ }
128
+ destroy() {
129
+ }
130
+ }
131
+ class F {
132
+ constructor(t) {
133
+ this.config = t, this.newMask = !0, this.lastMask = new Float32Array(
134
+ this.config.mask.outputSize.height * this.config.mask.outputSize.width
135
+ ), this.lastResult = {
136
+ data: this.lastMask,
137
+ facesAndLandmarks: { data: new Float32Array(0), dims: [] },
138
+ gesture: new Float32Array(0),
139
+ motion: 0,
140
+ timestamp: 0,
141
+ warm: !1
142
+ };
143
+ }
144
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
145
+ async getLadonOutput(t) {
146
+ const a = {
147
+ data: this.lastMask,
148
+ facesAndLandmarks: this.lastResult.facesAndLandmarks,
149
+ gesture: this.lastResult.gesture,
150
+ motion: this.lastResult.motion,
151
+ timestamp: this.lastResult.timestamp,
152
+ warm: this.newMask
153
+ };
154
+ return this.newMask = !1, a;
155
+ }
156
+ async load() {
157
+ const t = await n.prepareWorkerConfig(this.config);
158
+ if (this.worker = n.getWorker(), this.worker ?? (this.worker = await n.initializeWorker(t)), !this.worker)
159
+ throw new Error("[ladon-ts] - worker is not defined.");
160
+ const a = {
161
+ baseUrl: t.baseUrl,
162
+ input: t.input,
163
+ mask: t.mask,
164
+ wasmUri: t.wasmUri,
165
+ render: { type: "passthrough" }
166
+ };
167
+ this.worker.postMessage({ type: "init", config: a });
168
+ let e;
169
+ const r = new Promise((s) => {
170
+ e = s;
171
+ });
172
+ return this.worker.onmessage = (s) => {
173
+ if (s.data.status === "generated")
174
+ this.lastMask = s.data.mask, this.lastResult = {
175
+ data: s.data.mask,
176
+ facesAndLandmarks: s.data.facesAndLandmarks,
177
+ gesture: s.data.gesture,
178
+ motion: s.data.motion,
179
+ timestamp: s.data.timestamp,
180
+ warm: !0
181
+ }, this.newMask = !0;
182
+ else {
183
+ const o = n.getWorkerUrl();
184
+ o && URL.revokeObjectURL(o), e == null || e();
185
+ }
186
+ }, r;
187
+ }
188
+ isLoaded() {
189
+ return !!this.worker;
190
+ }
191
+ async postRender(t, a) {
192
+ if (!this.worker)
193
+ throw new Error("[ladon-ts] - worker is not defined.");
194
+ this.worker.postMessage(
195
+ {
196
+ type: "generate",
197
+ image: t,
198
+ timestamp: a
199
+ },
200
+ [t.buffer]
201
+ );
202
+ }
203
+ destroy() {
204
+ n.terminateWorker();
205
+ }
206
+ }
207
+ export {
208
+ R as LocalGenerator,
209
+ L as NullGenerator,
210
+ F as WorkerGenerator
211
+ };
212
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sources":["../../../src/lib/generator.ts"],"sourcesContent":["import * as ort from 'onnxruntime-web';\n\nimport { PipelineConfig } from './config-types';\nimport { sharedResourceManager } from './shared-resource-manager';\n\ndeclare global {\n interface ImportMeta {\n url: string;\n }\n}\n\nexport type FrameData = Uint8ClampedArray | HTMLVideoElement;\n\nexport interface FacesAndLandmarks {\n data: Float32Array;\n dims: readonly number[];\n}\nexport interface LadonOutput {\n data: Float32Array; // 1x1x144x256 or 1x1x360x640\n facesAndLandmarks: FacesAndLandmarks; // 1x1x9x16x1439\n gesture: Float32Array; // 1x9\n motion: number; // 1x1x1x1\n timestamp: number;\n warm: boolean;\n}\n\nexport interface MaskGenerator {\n getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput>;\n load(): Promise<void>;\n isLoaded(): boolean;\n postRender(input: Uint8ClampedArray, timestamp: number): Promise<void>;\n destroy(): void;\n}\n\nexport class LocalGenerator implements MaskGenerator {\n private lastResult: LadonOutput;\n private lastMask: ort.Tensor;\n private maskModel?: ort.InferenceSession;\n private lastMaskGenerationTime = 0;\n private output?: Float32Array;\n\n constructor(public readonly config: PipelineConfig) {\n const { height, width } = this.config.mask.outputSize;\n this.lastMask = new ort.Tensor('float32', new Float32Array(height * width), [\n 1,\n 1,\n height,\n width,\n ]);\n this.lastResult = {\n data: this.lastMask.data,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n /**\n * This method preprocesses an input Uint8ClampedArray to a Float32Array\n * while maintaining memory efficiency by reusing a class-scoped output buffer.\n * If the model rank is 4 (e.g., newer tiny model), it sets an alpha channel value.\n *\n * @param {Uint8ClampedArray} input - The input data to be preprocessed\n * @param {Float32Array} alpha - The alpha channel data\n * @returns {Float32Array} - The processed data\n */\n private preprocess(input: Uint8ClampedArray, alpha: Float32Array): Float32Array {\n const {\n modelRank: model_rank,\n inputSize: input_size,\n outputSize: output_size,\n } = this.config.mask;\n const { height, width } = input_size;\n const numImagePixels = height * width;\n\n // Initialize the output buffer if it is not already set\n this.output ??= new Float32Array(numImagePixels * model_rank);\n\n const numInputPixels = input.length / 4; // Divide by 4 for RGBA\n\n // Directly copy channels (assumes fixed order like BGR or RGB)\n for (let channel = 0; channel < 3; channel++) {\n for (let pixel = 0; pixel < numInputPixels; pixel++) {\n // Map input channels directly to output\n this.output[pixel + channel * numImagePixels] = input[pixel * 4 + (2 - channel)];\n }\n }\n\n // Scaling factors for width and height\n const widthScale = output_size.width / width;\n const heightScale = output_size.height / height;\n\n // Process alpha channel\n for (let x = 0; x < width; x++) {\n const nearestNeighborX = Math.floor(x * widthScale);\n for (let y = 0; y < height; y++) {\n const nearestNeighborY = Math.floor(y * heightScale);\n const maskIdx = nearestNeighborX + nearestNeighborY * output_size.width;\n const outputIdx = x + y * width + 3 * numImagePixels;\n\n // Normalize and scale alpha to [0, 255]\n const normalizedValue = Math.min(Math.max(alpha[maskIdx], 0), 255);\n this.output[outputIdx] = normalizedValue;\n }\n }\n\n return this.output;\n }\n\n public getTimeSinceLastGeneration(): number {\n return Date.now() - this.lastMaskGenerationTime;\n }\n\n public async getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput> {\n if (!this.maskModel) {\n throw new Error('[ladon-ts] - mask model not loaded.');\n }\n\n if (this.getTimeSinceLastGeneration() < this.config.mask.generationIntervalMs) {\n return {\n data: this.lastMask.data,\n facesAndLandmarks: this.lastResult.facesAndLandmarks,\n gesture: this.lastResult.gesture,\n motion: this.lastResult.motion,\n timestamp: this.lastResult.timestamp,\n warm: false,\n };\n }\n\n this.lastMaskGenerationTime = Date.now();\n\n const imageTensor = new ort.Tensor('float32', this.preprocess(input, this.lastMask.data), [\n 1,\n this.config.mask.modelRank,\n this.config.mask.inputSize.height,\n this.config.mask.inputSize.width,\n ]);\n\n const results = await this.maskModel.run({ input: imageTensor });\n this.lastMask = results.segmentation;\n\n this.lastResult = {\n data: this.lastMask.data ?? new Float32Array(0),\n facesAndLandmarks: {\n data: results.faces_and_landmarks?.data ?? new Float32Array(0),\n dims: results.faces_and_landmarks?.dims ?? ([] as readonly number[]),\n },\n gesture: results.gesture?.data ?? new Float32Array(0),\n motion: results.motion?.data[0] ?? 0,\n timestamp,\n warm: true,\n };\n\n return this.lastResult;\n }\n\n async load() {\n const modelUrl = await sharedResourceManager.resolveUri(\n this.config,\n this.config.mask.modelUri\n );\n\n // Attempt to retrieve a preloaded InferenceSession from the shared resource manager.\n this.maskModel = sharedResourceManager.getModelSession(modelUrl);\n // If the model is not preloaded, load it from the provided model URL.\n this.maskModel ??= await sharedResourceManager.loadModel(this.config);\n\n if (!this.maskModel) {\n throw new Error('Failed to load the ONNX model.');\n }\n }\n\n public isLoaded(): boolean {\n return !!this.maskModel;\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async postRender(_: Uint8ClampedArray): Promise<void> {\n // empty for local generator\n }\n\n public destroy(): void {\n // empty for local generator\n }\n}\n\nexport class NullGenerator implements MaskGenerator {\n private lastMask: Float32Array;\n\n constructor(public readonly config: PipelineConfig) {\n this.lastMask = new Float32Array(\n this.config.mask.outputSize.height * this.config.mask.outputSize.width\n );\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput> {\n return {\n data: this.lastMask,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n public async load(): Promise<void> {\n // empty for null generator\n }\n\n public isLoaded(): boolean {\n return true;\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async postRender(_: Uint8ClampedArray): Promise<void> {\n // empty for null generator\n }\n\n public destroy(): void {\n // empty for null generator\n }\n}\n\nexport class WorkerGenerator implements MaskGenerator {\n private lastMask: Float32Array;\n private newMask = true;\n private worker?: Worker;\n private lastResult: LadonOutput;\n\n constructor(public readonly config: PipelineConfig) {\n this.lastMask = new Float32Array(\n this.config.mask.outputSize.height * this.config.mask.outputSize.width\n );\n this.lastResult = {\n data: this.lastMask,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput> {\n const toReturn = {\n data: this.lastMask,\n facesAndLandmarks: this.lastResult.facesAndLandmarks,\n gesture: this.lastResult.gesture,\n motion: this.lastResult.motion,\n timestamp: this.lastResult.timestamp,\n warm: this.newMask,\n };\n\n this.newMask = false;\n\n return toReturn;\n }\n\n public async load(): Promise<void> {\n // Prepare the worker configuration by resolving the final URLs and paths to send to the worker.\n const config = await sharedResourceManager.prepareWorkerConfig(this.config);\n\n this.worker = sharedResourceManager.getWorker();\n this.worker ??= await sharedResourceManager.initializeWorker(config);\n\n if (!this.worker) {\n throw new Error('[ladon-ts] - worker is not defined.');\n }\n\n const workerConfig: PipelineConfig = {\n baseUrl: config.baseUrl,\n input: config.input,\n mask: config.mask,\n wasmUri: config.wasmUri,\n render: { type: 'passthrough' },\n };\n\n this.worker.postMessage({ type: 'init', config: workerConfig });\n\n let resolutionCb: () => void;\n const result = new Promise<void>((resolve) => {\n resolutionCb = resolve;\n });\n\n this.worker.onmessage = (event) => {\n if (event.data.status === 'generated') {\n this.lastMask = event.data.mask;\n this.lastResult = {\n data: event.data.mask,\n facesAndLandmarks: event.data.facesAndLandmarks,\n gesture: event.data.gesture,\n motion: event.data.motion,\n timestamp: event.data.timestamp,\n warm: true,\n };\n this.newMask = true;\n } else {\n const workerUrl = sharedResourceManager.getWorkerUrl();\n\n if (workerUrl) {\n URL.revokeObjectURL(workerUrl);\n }\n\n resolutionCb?.();\n }\n };\n\n return result;\n }\n\n public isLoaded(): boolean {\n return !!this.worker;\n }\n\n public async postRender(input: Uint8ClampedArray, timestamp: number): Promise<void> {\n // claim ownership of the input tensor's buffer and forward to worker\n\n if (!this.worker) {\n throw new Error('[ladon-ts] - worker is not defined.');\n }\n\n this.worker.postMessage(\n {\n type: 'generate',\n image: input,\n timestamp,\n },\n [input.buffer]\n );\n }\n\n public destroy(): void {\n sharedResourceManager.terminateWorker();\n }\n}\n"],"names":["LocalGenerator","config","height","width","ort","input","alpha","model_rank","input_size","output_size","numImagePixels","numInputPixels","channel","pixel","widthScale","heightScale","x","nearestNeighborX","y","nearestNeighborY","maskIdx","outputIdx","normalizedValue","timestamp","imageTensor","results","_a","_b","_c","_d","modelUrl","sharedResourceManager","_","NullGenerator","WorkerGenerator","toReturn","workerConfig","resolutionCb","result","resolve","event","workerUrl"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { PipelineConfig } from './config';
2
- import { FacesAndLandmarks } from './generator';
1
+ import { PipelineConfig } from './config-types';
2
+ import { FacesAndLandmarks } from './generator';
3
+
3
4
  export interface IFrameInferenceResult {
4
5
  facesAndLandmarks: FacesAndLandmarks;
5
6
  gesture: Float32Array;
@@ -26,12 +27,6 @@ export declare class Pipeline implements IPipeline {
26
27
  private frameQueue;
27
28
  private maskQueue;
28
29
  constructor(inputCanvas: HTMLCanvasElement, outputCanvas: HTMLCanvasElement, config: PipelineConfig, videoElement?: HTMLVideoElement | undefined);
29
- /**
30
- * Gets the raw image data from the input canvas context.
31
- *
32
- * @returns The raw image data.
33
- */
34
- private getRawImageDataFromInputCanvas;
35
30
  /**
36
31
  * Processes a single frame and returns the inference result.
37
32
  *
@@ -45,6 +40,14 @@ export declare class Pipeline implements IPipeline {
45
40
  * Synchronizes frames and masks to ensure they are rendered together.
46
41
  */
47
42
  private renderSyncedFrameAndMask;
43
+ /**
44
+ * Gets the raw image data from the input canvas context.
45
+ *
46
+ * @param needFreshImageData - Flag to indicate if fresh image data is needed.
47
+ *
48
+ * @returns The raw image data.
49
+ */
50
+ private getInputFrameData;
48
51
  /**
49
52
  * Resizes the image data if the model expects a fixed size input.
50
53
  *