@webex/ladon-ts 5.2.0 → 5.4.2
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.
- package/CHANGELOG.md +192 -149
- package/LICENSE +5 -5
- package/README.md +34 -36
- package/build/module/config.json.js +1 -1
- package/build/module/index.d.ts +10 -10
- package/build/module/index.js +17 -16
- package/build/module/lib/config-builder.d.ts +179 -180
- package/build/module/lib/config-types.d.ts +101 -101
- package/build/module/lib/config.d.ts +28 -29
- package/build/module/lib/generator.d.ts +73 -74
- package/build/module/lib/generator.js +52 -40
- package/build/module/lib/generator.js.map +1 -1
- package/build/module/lib/pipeline.d.ts +82 -83
- package/build/module/lib/preload.d.ts +7 -8
- package/build/module/lib/renderer/blur-renderer.d.ts +17 -18
- package/build/module/lib/renderer/ladon-renderer.d.ts +5 -6
- package/build/module/lib/renderer/passthrough-renderer.d.ts +10 -11
- package/build/module/lib/renderer/replacement-renderer.d.ts +14 -15
- package/build/module/lib/renderer/webgl-renderer.d.ts +23 -24
- package/build/module/lib/renderer.d.ts +5 -5
- package/build/module/lib/shared-resource-manager.d.ts +92 -92
- package/build/module/lib/shared-resource-manager.js +37 -21
- package/build/module/lib/shared-resource-manager.js.map +1 -1
- package/build/module/lib/util.d.ts +64 -63
- package/build/module/lib/util.js +83 -64
- package/build/module/lib/util.js.map +1 -1
- package/build/module/lib/version.d.ts +1 -1
- package/build/module/lib/version.js +1 -1
- package/build/module/lib/version.js.map +1 -1
- package/build/worker/ort-wasm-simd-threaded.wasm +0 -0
- package/build/worker/segmentation.js +1475 -13968
- package/build/worker/segmentation.js.map +1 -0
- package/package.json +101 -95
|
@@ -1,75 +1,74 @@
|
|
|
1
1
|
import { PipelineConfig } from './config-types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
private
|
|
32
|
-
private
|
|
33
|
-
private
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* @param {
|
|
42
|
-
* @
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
private
|
|
66
|
-
private
|
|
67
|
-
private
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
2
|
+
declare global {
|
|
3
|
+
interface ImportMeta {
|
|
4
|
+
url: string;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export type FrameData = Uint8ClampedArray | HTMLVideoElement;
|
|
8
|
+
export interface FacesAndLandmarks {
|
|
9
|
+
data: Float32Array;
|
|
10
|
+
dims: readonly number[];
|
|
11
|
+
}
|
|
12
|
+
export interface LadonOutput {
|
|
13
|
+
data: Float32Array;
|
|
14
|
+
facesAndLandmarks: FacesAndLandmarks;
|
|
15
|
+
gesture: Float32Array;
|
|
16
|
+
motion: number;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
warm: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface MaskGenerator {
|
|
21
|
+
getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput>;
|
|
22
|
+
load(): Promise<void>;
|
|
23
|
+
isLoaded(): boolean;
|
|
24
|
+
postRender(input: Uint8ClampedArray, timestamp: number): Promise<void>;
|
|
25
|
+
destroy(): void;
|
|
26
|
+
}
|
|
27
|
+
export declare class LocalGenerator implements MaskGenerator {
|
|
28
|
+
readonly config: PipelineConfig;
|
|
29
|
+
private lastResult;
|
|
30
|
+
private lastMask;
|
|
31
|
+
private maskModel?;
|
|
32
|
+
private lastMaskGenerationTime;
|
|
33
|
+
private output?;
|
|
34
|
+
constructor(config: PipelineConfig);
|
|
35
|
+
/**
|
|
36
|
+
* This method preprocesses an input Uint8ClampedArray to a Float32Array
|
|
37
|
+
* while maintaining memory efficiency by reusing a class-scoped output buffer.
|
|
38
|
+
* If the model rank is 4 (e.g., newer tiny model), it sets an alpha channel value.
|
|
39
|
+
*
|
|
40
|
+
* @param {Uint8ClampedArray} input - The input data to be preprocessed
|
|
41
|
+
* @param {Float32Array} alpha - The alpha channel data
|
|
42
|
+
* @returns {Float32Array} - The processed data
|
|
43
|
+
*/
|
|
44
|
+
private preprocess;
|
|
45
|
+
getTimeSinceLastGeneration(): number;
|
|
46
|
+
getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput>;
|
|
47
|
+
load(): Promise<void>;
|
|
48
|
+
isLoaded(): boolean;
|
|
49
|
+
postRender(_: Uint8ClampedArray): Promise<void>;
|
|
50
|
+
destroy(): void;
|
|
51
|
+
}
|
|
52
|
+
export declare class NullGenerator implements MaskGenerator {
|
|
53
|
+
readonly config: PipelineConfig;
|
|
54
|
+
private lastMask;
|
|
55
|
+
constructor(config: PipelineConfig);
|
|
56
|
+
getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput>;
|
|
57
|
+
load(): Promise<void>;
|
|
58
|
+
isLoaded(): boolean;
|
|
59
|
+
postRender(_: Uint8ClampedArray): Promise<void>;
|
|
60
|
+
destroy(): void;
|
|
61
|
+
}
|
|
62
|
+
export declare class WorkerGenerator implements MaskGenerator {
|
|
63
|
+
readonly config: PipelineConfig;
|
|
64
|
+
private lastMask;
|
|
65
|
+
private newMask;
|
|
66
|
+
private worker?;
|
|
67
|
+
private lastResult;
|
|
68
|
+
constructor(config: PipelineConfig);
|
|
69
|
+
getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput>;
|
|
70
|
+
load(): Promise<void>;
|
|
71
|
+
isLoaded(): boolean;
|
|
72
|
+
postRender(input: Uint8ClampedArray, timestamp: number): Promise<void>;
|
|
73
|
+
destroy(): void;
|
|
74
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as c from "onnxruntime-web";
|
|
2
|
-
import { sharedResourceManager as
|
|
2
|
+
import { sharedResourceManager as d } from "./shared-resource-manager.js";
|
|
3
3
|
class R {
|
|
4
4
|
constructor(t) {
|
|
5
5
|
this.config = t, this.lastMaskGenerationTime = 0;
|
|
@@ -30,19 +30,19 @@ class R {
|
|
|
30
30
|
preprocess(t, a) {
|
|
31
31
|
const {
|
|
32
32
|
modelRank: e,
|
|
33
|
-
inputSize:
|
|
33
|
+
inputSize: l,
|
|
34
34
|
outputSize: s
|
|
35
|
-
} = this.config.mask, { height:
|
|
36
|
-
this.output ?? (this.output = new Float32Array(
|
|
35
|
+
} = this.config.mask, { height: r, width: i } = l, o = r * i;
|
|
36
|
+
this.output ?? (this.output = new Float32Array(o * e));
|
|
37
37
|
const k = t.length / 4;
|
|
38
|
-
for (let
|
|
39
|
-
for (let
|
|
40
|
-
this.output[
|
|
41
|
-
const w = s.width /
|
|
42
|
-
for (let
|
|
43
|
-
const
|
|
44
|
-
for (let
|
|
45
|
-
const f = Math.floor(
|
|
38
|
+
for (let n = 0; n < 3; n++)
|
|
39
|
+
for (let m = 0; m < k; m++)
|
|
40
|
+
this.output[m + n * o] = t[m * 4 + (2 - n)];
|
|
41
|
+
const w = s.width / i, g = s.height / r;
|
|
42
|
+
for (let n = 0; n < i; n++) {
|
|
43
|
+
const m = Math.floor(n * w);
|
|
44
|
+
for (let h = 0; h < r; h++) {
|
|
45
|
+
const f = Math.floor(h * g), p = m + f * s.width, M = n + h * i + 3 * o, y = Math.min(Math.max(a[p], 0), 255);
|
|
46
46
|
this.output[M] = y;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -52,7 +52,7 @@ class R {
|
|
|
52
52
|
return Date.now() - this.lastMaskGenerationTime;
|
|
53
53
|
}
|
|
54
54
|
async getLadonOutput(t, a) {
|
|
55
|
-
var s,
|
|
55
|
+
var s, r, i, o;
|
|
56
56
|
if (!this.maskModel)
|
|
57
57
|
throw new Error("[ladon-ts] - mask model not loaded.");
|
|
58
58
|
if (this.getTimeSinceLastGeneration() < this.config.mask.generationIntervalMs)
|
|
@@ -70,25 +70,25 @@ class R {
|
|
|
70
70
|
this.config.mask.modelRank,
|
|
71
71
|
this.config.mask.inputSize.height,
|
|
72
72
|
this.config.mask.inputSize.width
|
|
73
|
-
]),
|
|
74
|
-
return this.lastMask =
|
|
73
|
+
]), l = await this.maskModel.run({ input: e });
|
|
74
|
+
return this.lastMask = l.segmentation, this.lastResult = {
|
|
75
75
|
data: this.lastMask.data ?? new Float32Array(0),
|
|
76
76
|
facesAndLandmarks: {
|
|
77
|
-
data: ((s =
|
|
78
|
-
dims: ((
|
|
77
|
+
data: ((s = l.faces_and_landmarks) == null ? void 0 : s.data) ?? new Float32Array(0),
|
|
78
|
+
dims: ((r = l.faces_and_landmarks) == null ? void 0 : r.dims) ?? []
|
|
79
79
|
},
|
|
80
|
-
gesture: ((
|
|
81
|
-
motion: ((
|
|
80
|
+
gesture: ((i = l.gesture) == null ? void 0 : i.data) ?? new Float32Array(0),
|
|
81
|
+
motion: ((o = l.motion) == null ? void 0 : o.data[0]) ?? 0,
|
|
82
82
|
timestamp: a,
|
|
83
83
|
warm: !0
|
|
84
84
|
}, this.lastResult;
|
|
85
85
|
}
|
|
86
86
|
async load() {
|
|
87
|
-
const t = await
|
|
87
|
+
const t = await d.resolveUri(
|
|
88
88
|
this.config,
|
|
89
89
|
this.config.mask.modelUri
|
|
90
90
|
);
|
|
91
|
-
if (this.maskModel =
|
|
91
|
+
if (this.maskModel = d.getModelSession(t), this.maskModel ?? (this.maskModel = await d.loadModel(this.config)), !this.maskModel)
|
|
92
92
|
throw new Error("Failed to load the ONNX model.");
|
|
93
93
|
}
|
|
94
94
|
isLoaded() {
|
|
@@ -154,9 +154,36 @@ class F {
|
|
|
154
154
|
return this.newMask = !1, a;
|
|
155
155
|
}
|
|
156
156
|
async load() {
|
|
157
|
-
const t = await
|
|
158
|
-
if (this.worker =
|
|
157
|
+
const t = await d.prepareWorkerConfig(this.config);
|
|
158
|
+
if (this.worker = d.getWorker(), this.worker ?? (this.worker = await d.initializeWorker(t)), !this.worker)
|
|
159
159
|
throw new Error("[ladon-ts] - worker is not defined.");
|
|
160
|
+
this.worker.onmessage = (s) => {
|
|
161
|
+
if (s.data.type === "log") {
|
|
162
|
+
const { message: r, severity: i } = s.data, o = `[ladon-ts] Message received from worker: ${r}`;
|
|
163
|
+
switch (i) {
|
|
164
|
+
case "warn":
|
|
165
|
+
console.warn(o);
|
|
166
|
+
break;
|
|
167
|
+
case "error":
|
|
168
|
+
console.error(o);
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
console.log(o);
|
|
172
|
+
}
|
|
173
|
+
} else 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 r = d.getWorkerUrl();
|
|
184
|
+
r && URL.revokeObjectURL(r), e == null || e();
|
|
185
|
+
}
|
|
186
|
+
};
|
|
160
187
|
const a = {
|
|
161
188
|
baseUrl: t.baseUrl,
|
|
162
189
|
input: t.input,
|
|
@@ -166,24 +193,9 @@ class F {
|
|
|
166
193
|
};
|
|
167
194
|
this.worker.postMessage({ type: "init", config: a });
|
|
168
195
|
let e;
|
|
169
|
-
|
|
196
|
+
return new Promise((s) => {
|
|
170
197
|
e = s;
|
|
171
198
|
});
|
|
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
199
|
}
|
|
188
200
|
isLoaded() {
|
|
189
201
|
return !!this.worker;
|
|
@@ -201,7 +213,7 @@ class F {
|
|
|
201
213
|
);
|
|
202
214
|
}
|
|
203
215
|
destroy() {
|
|
204
|
-
|
|
216
|
+
d.terminateWorker();
|
|
205
217
|
}
|
|
206
218
|
}
|
|
207
219
|
export {
|
|
@@ -1 +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
|
+
{"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 this.worker.onmessage = (event) => {\n if (event.data.type === 'log') {\n // Forward log messages from the worker to the console.\n const { message, severity } = event.data;\n const msg = `[ladon-ts] Message received from worker: ${message}`;\n switch (severity) {\n case 'warn':\n console.warn(msg);\n break;\n case 'error':\n console.error(msg);\n break;\n default:\n console.log(msg);\n }\n } else if (event.data.status === 'generated') {\n // Update the last mask and result with the new data from the worker.\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 // Clean up the worker and revoke the URL when the worker is finished\n const workerUrl = sharedResourceManager.getWorkerUrl();\n if (workerUrl) {\n URL.revokeObjectURL(workerUrl);\n }\n resolutionCb?.();\n }\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 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","event","message","severity","msg","workerUrl","resolutionCb","workerConfig","resolve"],"mappings":"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"}
|
|
@@ -1,85 +1,84 @@
|
|
|
1
1
|
import { PipelineConfig } from './config-types';
|
|
2
2
|
import { FacesAndLandmarks } from './generator';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
readonly
|
|
21
|
-
private
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
private
|
|
26
|
-
private
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* @param
|
|
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
|
-
* @param {
|
|
62
|
-
* @
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
3
|
+
export interface IFrameInferenceResult {
|
|
4
|
+
facesAndLandmarks: FacesAndLandmarks;
|
|
5
|
+
gesture: Float32Array;
|
|
6
|
+
motion: number;
|
|
7
|
+
skipped: boolean;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
}
|
|
10
|
+
export interface IPipeline {
|
|
11
|
+
onFrame(timestamp: number, maskNeeded?: boolean): Promise<IFrameInferenceResult>;
|
|
12
|
+
isLoaded(): boolean;
|
|
13
|
+
load(): Promise<void>;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare class Pipeline implements IPipeline {
|
|
17
|
+
private inputCanvas;
|
|
18
|
+
private outputCanvas;
|
|
19
|
+
readonly config: PipelineConfig;
|
|
20
|
+
private readonly videoElement?;
|
|
21
|
+
private generator?;
|
|
22
|
+
private renderer?;
|
|
23
|
+
private loaded;
|
|
24
|
+
private inputCanvasCtx;
|
|
25
|
+
private lastMaskResult?;
|
|
26
|
+
private frameQueue;
|
|
27
|
+
private maskQueue;
|
|
28
|
+
constructor(inputCanvas: HTMLCanvasElement, outputCanvas: HTMLCanvasElement, config: PipelineConfig, videoElement?: HTMLVideoElement | undefined);
|
|
29
|
+
/**
|
|
30
|
+
* Processes a single frame and returns the inference result.
|
|
31
|
+
*
|
|
32
|
+
* @param timestamp - The timestamp of the frame.
|
|
33
|
+
* @param performInference - Flag to perform mask inference.
|
|
34
|
+
* @returns The result of the frame processing.
|
|
35
|
+
* @throws If the pipeline (generator or renderer) is not loaded.
|
|
36
|
+
*/
|
|
37
|
+
onFrame(timestamp: number, performInference?: boolean): Promise<IFrameInferenceResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Synchronizes frames and masks to ensure they are rendered together.
|
|
40
|
+
*/
|
|
41
|
+
private renderSyncedFrameAndMask;
|
|
42
|
+
/**
|
|
43
|
+
* Gets the raw image data from the input canvas context.
|
|
44
|
+
*
|
|
45
|
+
* @param needFreshImageData - Flag to indicate if fresh image data is needed.
|
|
46
|
+
*
|
|
47
|
+
* @returns The raw image data.
|
|
48
|
+
*/
|
|
49
|
+
private getInputFrameData;
|
|
50
|
+
/**
|
|
51
|
+
* Resizes the image data if the model expects a fixed size input.
|
|
52
|
+
*
|
|
53
|
+
* @param {Uint8ClampedArray} rawImageData - The raw image data.
|
|
54
|
+
* @returns {Uint8ClampedArray} - The processed mask image data.
|
|
55
|
+
*/
|
|
56
|
+
private getMaskImageData;
|
|
57
|
+
/**
|
|
58
|
+
* Creates the inference result object.
|
|
59
|
+
*
|
|
60
|
+
* @param {number} timestamp - The timestamp of the frame.
|
|
61
|
+
* @param {boolean} performedInference - Indicates if the inference was performed.
|
|
62
|
+
* @returns {IFrameInferenceResult} - The result object containing inference details.
|
|
63
|
+
*/
|
|
64
|
+
private createInferenceResult;
|
|
65
|
+
/**
|
|
66
|
+
* Checks if the pipeline is loaded.
|
|
67
|
+
*
|
|
68
|
+
* @returns True if the pipeline is loaded, false otherwise.
|
|
69
|
+
*/
|
|
70
|
+
isLoaded(): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Loads the pipeline components such as the generator and renderer.
|
|
73
|
+
*/
|
|
74
|
+
load(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Resets the frame and mask queues.
|
|
77
|
+
*/
|
|
78
|
+
private resetQueues;
|
|
79
|
+
reset(): void;
|
|
80
|
+
/**
|
|
81
|
+
* Destroys the pipeline and cleans up resources.
|
|
82
|
+
*/
|
|
83
|
+
destroy(): void;
|
|
84
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { PreloadConfig } from './config-types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare const preload: (config: PreloadConfig) => Promise<void>;
|
|
2
|
+
/**
|
|
3
|
+
* Preload the resources using the provided configuration. This function is used to preload the model
|
|
4
|
+
* and the worker before creating the pipeline.
|
|
5
|
+
*
|
|
6
|
+
* @param config - The configuration object.
|
|
7
|
+
*/
|
|
8
|
+
export declare const preload: (config: PreloadConfig) => Promise<void>;
|
|
@@ -2,21 +2,20 @@ import { PipelineConfig } from '../config-types';
|
|
|
2
2
|
import { FrameData, LadonOutput } from '../generator';
|
|
3
3
|
import { LadonRenderer } from './ladon-renderer';
|
|
4
4
|
import { WebGLRenderer } from './webgl-renderer';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
private
|
|
10
|
-
private
|
|
11
|
-
private
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
5
|
+
export declare class BlurRenderer extends WebGLRenderer implements LadonRenderer {
|
|
6
|
+
output_canvas: HTMLCanvasElement;
|
|
7
|
+
readonly config: PipelineConfig;
|
|
8
|
+
private program_1;
|
|
9
|
+
private program_2;
|
|
10
|
+
private framebuffer;
|
|
11
|
+
private transfer_texture;
|
|
12
|
+
private u_blur;
|
|
13
|
+
private fragment_shader_common;
|
|
14
|
+
private fragment_shader_pass_1_src;
|
|
15
|
+
fragment_shader_pass_2_src: string;
|
|
16
|
+
constructor(output_canvas: HTMLCanvasElement, config: PipelineConfig);
|
|
17
|
+
render(input: FrameData, mask?: LadonOutput): Promise<void>;
|
|
18
|
+
load(): Promise<void>;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
private getBlurKernel;
|
|
21
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { FrameData, LadonOutput } from '../generator';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
2
|
+
export interface LadonRenderer {
|
|
3
|
+
render(input: FrameData, mask?: LadonOutput): Promise<void>;
|
|
4
|
+
load(): Promise<void>;
|
|
5
|
+
destroy(): void;
|
|
6
|
+
}
|