expand type safety

pull/293/head
Vladimir Mandic 2022-08-21 15:23:03 -04:00
parent 369026c2b1
commit 5b4a693429
62 changed files with 1671 additions and 1638 deletions

View File

@ -22,13 +22,29 @@
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:@typescript-eslint/strict",
"plugin:import/recommended", "plugin:import/recommended",
"plugin:promise/recommended" "plugin:promise/recommended"
], ],
"rules": { "rules": {
"@typescript-eslint/ban-ts-comment":"off", "@typescript-eslint/ban-ts-comment":"off",
"@typescript-eslint/dot-notation":"off",
"@typescript-eslint/no-empty-interface":"off", "@typescript-eslint/no-empty-interface":"off",
"@typescript-eslint/no-inferrable-types":"off", "@typescript-eslint/no-inferrable-types":"off",
"@typescript-eslint/no-misused-promises":"off",
"@typescript-eslint/no-unnecessary-condition":"off",
"@typescript-eslint/no-unsafe-argument":"off",
"@typescript-eslint/no-unsafe-assignment":"off",
"@typescript-eslint/no-unsafe-call":"off",
"@typescript-eslint/no-unsafe-member-access":"off",
"@typescript-eslint/no-unsafe-return":"off",
"@typescript-eslint/non-nullable-type-assertion-style":"off",
"@typescript-eslint/prefer-for-of":"off",
"@typescript-eslint/prefer-nullish-coalescing":"off",
"@typescript-eslint/prefer-ts-expect-error":"off",
"@typescript-eslint/restrict-plus-operands":"off",
"@typescript-eslint/restrict-template-expressions":"off",
"dot-notation":"off", "dot-notation":"off",
"guard-for-in":"off", "guard-for-in":"off",
"import/extensions": ["off", "always"], "import/extensions": ["off", "always"],
@ -47,6 +63,7 @@
"no-regex-spaces":"off", "no-regex-spaces":"off",
"no-restricted-syntax":"off", "no-restricted-syntax":"off",
"no-return-assign":"off", "no-return-assign":"off",
"no-void":"off",
"object-curly-newline":"off", "object-curly-newline":"off",
"prefer-destructuring":"off", "prefer-destructuring":"off",
"prefer-template":"off", "prefer-template":"off",
@ -130,8 +147,8 @@
"html", "@html-eslint" "html", "@html-eslint"
], ],
"rules": { "rules": {
"@html-eslint/indent": ["error", 2], "@html-eslint/element-newline":"off",
"@html-eslint/element-newline":"off" "@html-eslint/indent": ["error", 2]
} }
} }
], ],

View File

@ -9,7 +9,7 @@
## Changelog ## Changelog
### **HEAD -> main** 2022/08/20 mandic00@live.com ### **HEAD -> main** 2022/08/21 mandic00@live.com
### **2.9.4** 2022/08/20 mandic00@live.com ### **2.9.4** 2022/08/20 mandic00@live.com

View File

@ -66,6 +66,8 @@ Model is supported using `WebGL` backend in browser
- Allow hosting models in **Google Cloud Bucket** - Allow hosting models in **Google Cloud Bucket**
Hosted models can be directly used without downloading to local storage Hosted models can be directly used without downloading to local storage
Example: `modelPath: 'https://storage.googleapis.com/human-models/facemesh.json'` Example: `modelPath: 'https://storage.googleapis.com/human-models/facemesh.json'`
- Stricter linting rules for both **TypeScript** and **JavaScript**
See `./eslintrc.json` for details
- Fix **MobileFaceNet** model as alternative for face embedding/descriptor detection - Fix **MobileFaceNet** model as alternative for face embedding/descriptor detection
Configurable using `config.face.mobilefacenet` config section Configurable using `config.face.mobilefacenet` config section
- Fix **EfficientPose** module as alternative body detection - Fix **EfficientPose** module as alternative body detection

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -103,20 +103,20 @@ async function webCam() { // initialize webcam
const stream: MediaStream = await navigator.mediaDevices.getUserMedia(cameraOptions); const stream: MediaStream = await navigator.mediaDevices.getUserMedia(cameraOptions);
const ready = new Promise((resolve) => { dom.video.onloadeddata = () => resolve(true); }); const ready = new Promise((resolve) => { dom.video.onloadeddata = () => resolve(true); });
dom.video.srcObject = stream; dom.video.srcObject = stream;
dom.video.play(); void dom.video.play();
await ready; await ready;
dom.canvas.width = dom.video.videoWidth; dom.canvas.width = dom.video.videoWidth;
dom.canvas.height = dom.video.videoHeight; dom.canvas.height = dom.video.videoHeight;
if (human.env.initial) log('video:', dom.video.videoWidth, dom.video.videoHeight, '|', stream.getVideoTracks()[0].label); if (human.env.initial) log('video:', dom.video.videoWidth, dom.video.videoHeight, '|', stream.getVideoTracks()[0].label);
dom.canvas.onclick = () => { // pause when clicked on screen and resume on next click dom.canvas.onclick = () => { // pause when clicked on screen and resume on next click
if (dom.video.paused) dom.video.play(); if (dom.video.paused) void dom.video.play();
else dom.video.pause(); else dom.video.pause();
}; };
} }
async function detectionLoop() { // main detection loop async function detectionLoop() { // main detection loop
if (!dom.video.paused) { if (!dom.video.paused) {
if (current.face && current.face.tensor) human.tf.dispose(current.face.tensor); // dispose previous tensor if (current.face?.tensor) human.tf.dispose(current.face.tensor); // dispose previous tensor
await human.detect(dom.video); // actual detection; were not capturing output in a local variable as it can also be reached via human.result await human.detect(dom.video); // actual detection; were not capturing output in a local variable as it can also be reached via human.result
const now = human.now(); const now = human.now();
fps.detect = 1000 / (now - timestamp.detect); fps.detect = 1000 / (now - timestamp.detect);
@ -126,8 +126,8 @@ async function detectionLoop() { // main detection loop
} }
async function validationLoop(): Promise<H.FaceResult> { // main screen refresh loop async function validationLoop(): Promise<H.FaceResult> { // main screen refresh loop
const interpolated = await human.next(human.result); // smoothen result using last-known results const interpolated = human.next(human.result); // smoothen result using last-known results
await human.draw.canvas(dom.video, dom.canvas); // draw canvas to screen human.draw.canvas(dom.video, dom.canvas); // draw canvas to screen
await human.draw.all(dom.canvas, interpolated); // draw labels, boxes, lines, etc. await human.draw.all(dom.canvas, interpolated); // draw labels, boxes, lines, etc.
const now = human.now(); const now = human.now();
fps.draw = 1000 / (now - timestamp.draw); fps.draw = 1000 / (now - timestamp.draw);
@ -135,7 +135,7 @@ async function validationLoop(): Promise<H.FaceResult> { // main screen refresh
printFPS(`fps: ${fps.detect.toFixed(1).padStart(5, ' ')} detect | ${fps.draw.toFixed(1).padStart(5, ' ')} draw`); // write status printFPS(`fps: ${fps.detect.toFixed(1).padStart(5, ' ')} detect | ${fps.draw.toFixed(1).padStart(5, ' ')} draw`); // write status
ok.faceCount = human.result.face.length === 1; // must be exactly detected face ok.faceCount = human.result.face.length === 1; // must be exactly detected face
if (ok.faceCount) { // skip the rest if no face if (ok.faceCount) { // skip the rest if no face
const gestures: string[] = Object.values(human.result.gesture).map((gesture) => (gesture as H.GestureResult).gesture); // flatten all gestures const gestures: string[] = Object.values(human.result.gesture).map((gesture: H.GestureResult) => gesture.gesture); // flatten all gestures
if (gestures.includes('blink left eye') || gestures.includes('blink right eye')) blink.start = human.now(); // blink starts when eyes get closed if (gestures.includes('blink left eye') || gestures.includes('blink right eye')) blink.start = human.now(); // blink starts when eyes get closed
if (blink.start > 0 && !gestures.includes('blink left eye') && !gestures.includes('blink right eye')) blink.end = human.now(); // if blink started how long until eyes are back open if (blink.start > 0 && !gestures.includes('blink left eye') && !gestures.includes('blink right eye')) blink.end = human.now(); // if blink started how long until eyes are back open
ok.blinkDetected = ok.blinkDetected || (Math.abs(blink.end - blink.start) > options.blinkMin && Math.abs(blink.end - blink.start) < options.blinkMax); ok.blinkDetected = ok.blinkDetected || (Math.abs(blink.end - blink.start) > options.blinkMin && Math.abs(blink.end - blink.start) < options.blinkMax);
@ -173,8 +173,8 @@ async function validationLoop(): Promise<H.FaceResult> { // main screen refresh
ok.elapsedMs = Math.trunc(human.now() - startTime); ok.elapsedMs = Math.trunc(human.now() - startTime);
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(async () => { setTimeout(async () => {
const res = await validationLoop(); // run validation loop until conditions are met await validationLoop(); // run validation loop until conditions are met
if (res) resolve(human.result.face[0]); // recursive promise resolve resolve(human.result.face[0]); // recursive promise resolve
}, 30); // use to slow down refresh from max refresh rate to target of 30 fps }, 30); // use to slow down refresh from max refresh rate to target of 30 fps
}); });
} }
@ -210,7 +210,7 @@ async function detectFace() {
} }
const db = await indexDb.load(); const db = await indexDb.load();
const descriptors = db.map((rec) => rec.descriptor).filter((desc) => desc.length > 0); const descriptors = db.map((rec) => rec.descriptor).filter((desc) => desc.length > 0);
const res = await human.match(current.face.embedding, descriptors, matchOptions); const res = human.match(current.face.embedding, descriptors, matchOptions);
current.record = db[res.index] || null; current.record = db[res.index] || null;
if (current.record) { if (current.record) {
log(`best match: ${current.record.name} | id: ${current.record.id} | similarity: ${Math.round(1000 * res.similarity) / 10}%`); log(`best match: ${current.record.name} | id: ${current.record.id} | similarity: ${Math.round(1000 * res.similarity) / 10}%`);

View File

@ -4,6 +4,6 @@
author: <https://github.com/vladmandic>' author: <https://github.com/vladmandic>'
*/ */
import*as c from"../../dist/human.esm.js";var w={async:!1,modelBasePath:"../../models",filter:{enabled:!0,equalization:!1,flip:!1},face:{enabled:!0,detector:{rotation:!1},mesh:{enabled:!0},attention:{enabled:!1},iris:{enabled:!0},description:{enabled:!0},emotion:{enabled:!0}},body:{enabled:!0},hand:{enabled:!0},object:{enabled:!1},gesture:{enabled:!0}},e=new c.Human(w);e.env.perfadd=!1;e.draw.options.font='small-caps 18px "Lato"';e.draw.options.lineHeight=20;var t={video:document.getElementById("video"),canvas:document.getElementById("canvas"),log:document.getElementById("log"),fps:document.getElementById("status"),perf:document.getElementById("performance")},n={detect:0,draw:0,tensors:0,start:0},s={detectFPS:0,drawFPS:0,frames:0,averageMs:0},i=(...a)=>{t.log.innerText+=a.join(" ")+` import*as c from"../../dist/human.esm.js";var w={async:!1,modelBasePath:"../../models",filter:{enabled:!0,equalization:!1,flip:!1},face:{enabled:!0,detector:{rotation:!1},mesh:{enabled:!0},attention:{enabled:!1},iris:{enabled:!0},description:{enabled:!0},emotion:{enabled:!0}},body:{enabled:!0},hand:{enabled:!0},object:{enabled:!1},gesture:{enabled:!0}},e=new c.Human(w);e.env.perfadd=!1;e.draw.options.font='small-caps 18px "Lato"';e.draw.options.lineHeight=20;var t={video:document.getElementById("video"),canvas:document.getElementById("canvas"),log:document.getElementById("log"),fps:document.getElementById("status"),perf:document.getElementById("performance")},n={detect:0,draw:0,tensors:0,start:0},o={detectFPS:0,drawFPS:0,frames:0,averageMs:0},i=(...a)=>{t.log.innerText+=a.join(" ")+`
`,console.log(...a)},r=a=>t.fps.innerText=a,b=a=>t.perf.innerText="tensors:"+e.tf.memory().numTensors+" | performance: "+JSON.stringify(a).replace(/"|{|}/g,"").replace(/,/g," | ");async function h(){r("starting webcam...");let a={audio:!1,video:{facingMode:"user",resizeMode:"none",width:{ideal:document.body.clientWidth},height:{ideal:document.body.clientHeight}}},d=await navigator.mediaDevices.getUserMedia(a),f=new Promise(p=>{t.video.onloadeddata=()=>p(!0)});t.video.srcObject=d,t.video.play(),await f,t.canvas.width=t.video.videoWidth,t.canvas.height=t.video.videoHeight;let o=d.getVideoTracks()[0],v=o.getCapabilities?o.getCapabilities():"",g=o.getSettings?o.getSettings():"",u=o.getConstraints?o.getConstraints():"";i("video:",t.video.videoWidth,t.video.videoHeight,o.label,{stream:d,track:o,settings:g,constraints:u,capabilities:v}),t.canvas.onclick=()=>{t.video.paused?t.video.play():t.video.pause()}}async function l(){if(!t.video.paused){n.start===0&&(n.start=e.now()),await e.detect(t.video);let a=e.tf.memory().numTensors;a-n.tensors!==0&&i("allocated tensors:",a-n.tensors),n.tensors=a,s.detectFPS=Math.round(1e3*1e3/(e.now()-n.detect))/1e3,s.frames++,s.averageMs=Math.round(1e3*(e.now()-n.start)/s.frames)/1e3,s.frames%100===0&&!t.video.paused&&i("performance",{...s,tensors:n.tensors})}n.detect=e.now(),requestAnimationFrame(l)}async function m(){if(!t.video.paused){let d=await e.next(e.result);e.config.filter.flip?await e.draw.canvas(d.canvas,t.canvas):await e.draw.canvas(t.video,t.canvas),await e.draw.all(t.canvas,d),b(d.performance)}let a=e.now();s.drawFPS=Math.round(1e3*1e3/(a-n.draw))/1e3,n.draw=a,r(t.video.paused?"paused":`fps: ${s.detectFPS.toFixed(1).padStart(5," ")} detect | ${s.drawFPS.toFixed(1).padStart(5," ")} draw`),setTimeout(m,30)}async function M(){i("human version:",e.version,"| tfjs version:",e.tf.version["tfjs-core"]),i("platform:",e.env.platform,"| agent:",e.env.agent),r("loading..."),await e.load(),i("backend:",e.tf.getBackend(),"| available:",e.env.backends),i("models stats:",e.getModelStats()),i("models loaded:",Object.values(e.models).filter(a=>a!==null).length),r("initializing..."),await e.warmup(),await h(),await l(),await m()}window.onload=M; `,console.log(...a)},r=a=>t.fps.innerText=a,b=a=>t.perf.innerText="tensors:"+e.tf.memory().numTensors.toString()+" | performance: "+JSON.stringify(a).replace(/"|{|}/g,"").replace(/,/g," | ");async function h(){r("starting webcam...");let a={audio:!1,video:{facingMode:"user",resizeMode:"none",width:{ideal:document.body.clientWidth},height:{ideal:document.body.clientHeight}}},d=await navigator.mediaDevices.getUserMedia(a),f=new Promise(p=>{t.video.onloadeddata=()=>p(!0)});t.video.srcObject=d,t.video.play(),await f,t.canvas.width=t.video.videoWidth,t.canvas.height=t.video.videoHeight;let s=d.getVideoTracks()[0],v=s.getCapabilities?s.getCapabilities():"",g=s.getSettings?s.getSettings():"",u=s.getConstraints?s.getConstraints():"";i("video:",t.video.videoWidth,t.video.videoHeight,s.label,{stream:d,track:s,settings:g,constraints:u,capabilities:v}),t.canvas.onclick=()=>{t.video.paused?t.video.play():t.video.pause()}}async function l(){if(!t.video.paused){n.start===0&&(n.start=e.now()),await e.detect(t.video);let a=e.tf.memory().numTensors;a-n.tensors!==0&&i("allocated tensors:",a-n.tensors),n.tensors=a,o.detectFPS=Math.round(1e3*1e3/(e.now()-n.detect))/1e3,o.frames++,o.averageMs=Math.round(1e3*(e.now()-n.start)/o.frames)/1e3,o.frames%100===0&&!t.video.paused&&i("performance",{...o,tensors:n.tensors})}n.detect=e.now(),requestAnimationFrame(l)}async function m(){if(!t.video.paused){let d=e.next(e.result);e.config.filter.flip?e.draw.canvas(d.canvas,t.canvas):e.draw.canvas(t.video,t.canvas),await e.draw.all(t.canvas,d),b(d.performance)}let a=e.now();o.drawFPS=Math.round(1e3*1e3/(a-n.draw))/1e3,n.draw=a,r(t.video.paused?"paused":`fps: ${o.detectFPS.toFixed(1).padStart(5," ")} detect | ${o.drawFPS.toFixed(1).padStart(5," ")} draw`),setTimeout(m,30)}async function M(){i("human version:",e.version,"| tfjs version:",e.tf.version["tfjs-core"]),i("platform:",e.env.platform,"| agent:",e.env.agent),r("loading..."),await e.load(),i("backend:",e.tf.getBackend(),"| available:",e.env.backends),i("models stats:",e.getModelStats()),i("models loaded:",Object.values(e.models).filter(a=>a!==null).length),r("initializing..."),await e.warmup(),await h(),await l(),await m()}window.onload=M;
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@ -45,7 +45,7 @@ const log = (...msg) => { // helper method to output messages
console.log(...msg); // eslint-disable-line no-console console.log(...msg); // eslint-disable-line no-console
}; };
const status = (msg) => dom.fps.innerText = msg; // print status element const status = (msg) => dom.fps.innerText = msg; // print status element
const perf = (msg) => dom.perf.innerText = 'tensors:' + human.tf.memory().numTensors + ' | performance: ' + JSON.stringify(msg).replace(/"|{|}/g, '').replace(/,/g, ' | '); // print performance element const perf = (msg) => dom.perf.innerText = 'tensors:' + (human.tf.memory().numTensors as number).toString() + ' | performance: ' + JSON.stringify(msg).replace(/"|{|}/g, '').replace(/,/g, ' | '); // print performance element
async function webCam() { // initialize webcam async function webCam() { // initialize webcam
status('starting webcam...'); status('starting webcam...');
@ -54,7 +54,7 @@ async function webCam() { // initialize webcam
const stream: MediaStream = await navigator.mediaDevices.getUserMedia(options); const stream: MediaStream = await navigator.mediaDevices.getUserMedia(options);
const ready = new Promise((resolve) => { dom.video.onloadeddata = () => resolve(true); }); const ready = new Promise((resolve) => { dom.video.onloadeddata = () => resolve(true); });
dom.video.srcObject = stream; dom.video.srcObject = stream;
dom.video.play(); void dom.video.play();
await ready; await ready;
dom.canvas.width = dom.video.videoWidth; dom.canvas.width = dom.video.videoWidth;
dom.canvas.height = dom.video.videoHeight; dom.canvas.height = dom.video.videoHeight;
@ -64,7 +64,7 @@ async function webCam() { // initialize webcam
const constraints: MediaTrackConstraints | string = track.getConstraints ? track.getConstraints() : ''; const constraints: MediaTrackConstraints | string = track.getConstraints ? track.getConstraints() : '';
log('video:', dom.video.videoWidth, dom.video.videoHeight, track.label, { stream, track, settings, constraints, capabilities }); log('video:', dom.video.videoWidth, dom.video.videoHeight, track.label, { stream, track, settings, constraints, capabilities });
dom.canvas.onclick = () => { // pause when clicked on screen and resume on next click dom.canvas.onclick = () => { // pause when clicked on screen and resume on next click
if (dom.video.paused) dom.video.play(); if (dom.video.paused) void dom.video.play();
else dom.video.pause(); else dom.video.pause();
}; };
} }
@ -88,9 +88,9 @@ async function detectionLoop() { // main detection loop
async function drawLoop() { // main screen refresh loop async function drawLoop() { // main screen refresh loop
if (!dom.video.paused) { if (!dom.video.paused) {
const interpolated = await human.next(human.result); // smoothen result using last-known results const interpolated = human.next(human.result); // smoothen result using last-known results
if (human.config.filter.flip) await human.draw.canvas(interpolated.canvas as HTMLCanvasElement, dom.canvas); // draw processed image to screen canvas if (human.config.filter.flip) human.draw.canvas(interpolated.canvas as HTMLCanvasElement, dom.canvas); // draw processed image to screen canvas
else await human.draw.canvas(dom.video, dom.canvas); // draw original video to screen canvas // better than using procesed image as this loop happens faster than processing loop else human.draw.canvas(dom.video, dom.canvas); // draw original video to screen canvas // better than using procesed image as this loop happens faster than processing loop
await human.draw.all(dom.canvas, interpolated); // draw labels, boxes, lines, etc. await human.draw.all(dom.canvas, interpolated); // draw labels, boxes, lines, etc.
perf(interpolated.performance); // write performance data perf(interpolated.performance); // write performance data
} }

14
dist/human.d.ts vendored
View File

@ -28,7 +28,7 @@ declare interface ArrayMap {
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu']; export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */ /** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): void;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose; export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
@ -140,7 +140,7 @@ declare function browserFiles(files: File[]): IOHandler;
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler; declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */ /** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>; declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): void;
/** /**
* Concatenate a number of ArrayBuffers into one. * Concatenate a number of ArrayBuffers into one.
@ -509,7 +509,7 @@ export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' |
export declare type ExternalCanvas = typeof env.Canvas; export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */ /** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): void;
/** Anti-spoofing part of face configuration */ /** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig { export declare interface FaceAntiSpoofConfig extends GenericConfig {
@ -780,7 +780,7 @@ export declare interface GenericConfig {
} }
/** draw detected gestures */ /** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): void;
/** Controlls gesture detection */ /** Controlls gesture detection */
export declare interface GestureConfig { export declare interface GestureConfig {
@ -1038,7 +1038,7 @@ export declare class GraphModel<ModelURL extends Url = string | io.IOHandler> im
} }
/** draw detected hands */ /** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all hand detection specific options */ /** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig { export declare interface HandConfig extends GenericConfig {
@ -2022,7 +2022,7 @@ declare type NamedTensorsMap = {
declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64'; declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64';
/** draw detected objects */ /** draw detected objects */
declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all object detection specific options */ /** Configures all object detection specific options */
export declare interface ObjectConfig extends GenericConfig { export declare interface ObjectConfig extends GenericConfig {
@ -2065,7 +2065,7 @@ declare type OnProgressCallback = (fraction: number) => void;
declare const options: DrawOptions; declare const options: DrawOptions;
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): void;
/** Person getter /** Person getter
* - Triggers combining all individual results into a virtual person object * - Triggers combining all individual results into a virtual person object

View File

@ -28,7 +28,7 @@ declare interface ArrayMap {
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu']; export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */ /** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): void;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose; export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
@ -140,7 +140,7 @@ declare function browserFiles(files: File[]): IOHandler;
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler; declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */ /** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>; declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): void;
/** /**
* Concatenate a number of ArrayBuffers into one. * Concatenate a number of ArrayBuffers into one.
@ -509,7 +509,7 @@ export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' |
export declare type ExternalCanvas = typeof env.Canvas; export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */ /** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): void;
/** Anti-spoofing part of face configuration */ /** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig { export declare interface FaceAntiSpoofConfig extends GenericConfig {
@ -780,7 +780,7 @@ export declare interface GenericConfig {
} }
/** draw detected gestures */ /** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): void;
/** Controlls gesture detection */ /** Controlls gesture detection */
export declare interface GestureConfig { export declare interface GestureConfig {
@ -1038,7 +1038,7 @@ export declare class GraphModel<ModelURL extends Url = string | io.IOHandler> im
} }
/** draw detected hands */ /** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all hand detection specific options */ /** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig { export declare interface HandConfig extends GenericConfig {
@ -2022,7 +2022,7 @@ declare type NamedTensorsMap = {
declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64'; declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64';
/** draw detected objects */ /** draw detected objects */
declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all object detection specific options */ /** Configures all object detection specific options */
export declare interface ObjectConfig extends GenericConfig { export declare interface ObjectConfig extends GenericConfig {
@ -2065,7 +2065,7 @@ declare type OnProgressCallback = (fraction: number) => void;
declare const options: DrawOptions; declare const options: DrawOptions;
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): void;
/** Person getter /** Person getter
* - Triggers combining all individual results into a virtual person object * - Triggers combining all individual results into a virtual person object

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

14
dist/human.esm.d.ts vendored
View File

@ -28,7 +28,7 @@ declare interface ArrayMap {
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu']; export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */ /** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): void;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose; export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
@ -140,7 +140,7 @@ declare function browserFiles(files: File[]): IOHandler;
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler; declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */ /** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>; declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): void;
/** /**
* Concatenate a number of ArrayBuffers into one. * Concatenate a number of ArrayBuffers into one.
@ -509,7 +509,7 @@ export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' |
export declare type ExternalCanvas = typeof env.Canvas; export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */ /** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): void;
/** Anti-spoofing part of face configuration */ /** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig { export declare interface FaceAntiSpoofConfig extends GenericConfig {
@ -780,7 +780,7 @@ export declare interface GenericConfig {
} }
/** draw detected gestures */ /** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): void;
/** Controlls gesture detection */ /** Controlls gesture detection */
export declare interface GestureConfig { export declare interface GestureConfig {
@ -1038,7 +1038,7 @@ export declare class GraphModel<ModelURL extends Url = string | io.IOHandler> im
} }
/** draw detected hands */ /** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all hand detection specific options */ /** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig { export declare interface HandConfig extends GenericConfig {
@ -2022,7 +2022,7 @@ declare type NamedTensorsMap = {
declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64'; declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64';
/** draw detected objects */ /** draw detected objects */
declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all object detection specific options */ /** Configures all object detection specific options */
export declare interface ObjectConfig extends GenericConfig { export declare interface ObjectConfig extends GenericConfig {
@ -2065,7 +2065,7 @@ declare type OnProgressCallback = (fraction: number) => void;
declare const options: DrawOptions; declare const options: DrawOptions;
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): void;
/** Person getter /** Person getter
* - Triggers combining all individual results into a virtual person object * - Triggers combining all individual results into a virtual person object

128
dist/human.esm.js vendored
View File

@ -72546,7 +72546,7 @@ var GLProgram = class {
this.gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
this.gl.compileShader(shader); this.gl.compileShader(shader);
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
log(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`); log(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader) || "unknown"}`);
return null; return null;
} }
return shader; return shader;
@ -72565,7 +72565,7 @@ var GLProgram = class {
this.gl.attachShader(this.id, fragmentShader); this.gl.attachShader(this.id, fragmentShader);
this.gl.linkProgram(this.id); this.gl.linkProgram(this.id);
if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS)) { if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS)) {
log(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`); log(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id) || "unknown"}`);
return; return;
} }
this.gl.useProgram(this.id); this.gl.useProgram(this.id);
@ -73187,6 +73187,7 @@ function copy(input2, output) {
return outputCanvas; return outputCanvas;
} }
async function process2(input2, config3, getTensor2 = true) { async function process2(input2, config3, getTensor2 = true) {
var _a, _b;
if (!input2) { if (!input2) {
if (config3.debug) if (config3.debug)
log("input error: input is missing"); log("input error: input is missing");
@ -73217,7 +73218,7 @@ async function process2(input2, config3, getTensor2 = true) {
} }
} }
if (tensor3 == null || tensor3.shape.length !== 4 || tensor3.shape[0] !== 1 || tensor3.shape[3] !== 3) if (tensor3 == null || tensor3.shape.length !== 4 || tensor3.shape[0] !== 1 || tensor3.shape[3] !== 3)
throw new Error(`input error: attempted to use tensor with unrecognized shape: ${input2.shape}`); throw new Error(`input error: attempted to use tensor with unrecognized shape: ${input2.shape.toString()}`);
if (tensor3.dtype === "int32") { if (tensor3.dtype === "int32") {
const cast7 = cast(tensor3, "float32"); const cast7 = cast(tensor3, "float32");
dispose(tensor3); dispose(tensor3);
@ -73247,9 +73248,9 @@ async function process2(input2, config3, getTensor2 = true) {
targetHeight = maxSize; targetHeight = maxSize;
targetWidth = Math.trunc(targetHeight * originalWidth / originalHeight); targetWidth = Math.trunc(targetHeight * originalWidth / originalHeight);
} }
if ((config3.filter.width || 0) > 0) if ((((_a = config3.filter) == null ? void 0 : _a.width) || 0) > 0)
targetWidth = config3.filter.width; targetWidth = config3.filter.width;
else if ((config3.filter.height || 0) > 0) else if ((((_b = config3.filter) == null ? void 0 : _b.height) || 0) > 0)
targetWidth = originalWidth * ((config3.filter.height || 0) / originalHeight); targetWidth = originalWidth * ((config3.filter.height || 0) / originalHeight);
if ((config3.filter.height || 0) > 0) if ((config3.filter.height || 0) > 0)
targetHeight = config3.filter.height; targetHeight = config3.filter.height;
@ -73466,9 +73467,9 @@ var Env = class {
this.worker = this.browser && this.offscreen ? typeof WorkerGlobalScope !== "undefined" : void 0; this.worker = this.browser && this.offscreen ? typeof WorkerGlobalScope !== "undefined" : void 0;
if (typeof navigator !== "undefined") { if (typeof navigator !== "undefined") {
const raw = navigator.userAgent.match(/\(([^()]+)\)/g); const raw = navigator.userAgent.match(/\(([^()]+)\)/g);
if (raw && raw[0]) { if (raw == null ? void 0 : raw[0]) {
const platformMatch = raw[0].match(/\(([^()]+)\)/g); const platformMatch = raw[0].match(/\(([^()]+)\)/g);
this.platform = platformMatch && platformMatch[0] ? platformMatch[0].replace(/\(|\)/g, "") : ""; this.platform = (platformMatch == null ? void 0 : platformMatch[0]) ? platformMatch[0].replace(/\(|\)/g, "") : "";
this.agent = navigator.userAgent.replace(raw[0], ""); this.agent = navigator.userAgent.replace(raw[0], "");
if (this.platform[1]) if (this.platform[1])
this.agent = this.agent.replace(raw[1], ""); this.agent = this.agent.replace(raw[1], "");
@ -77669,7 +77670,7 @@ var inputSize2 = 224;
var anchorTensor; var anchorTensor;
var numLayers = 5; var numLayers = 5;
var strides = [8, 16, 32, 32, 32]; var strides = [8, 16, 32, 32, 32];
async function createAnchors() { function createAnchors() {
const anchors3 = []; const anchors3 = [];
let layerId = 0; let layerId = 0;
while (layerId < numLayers) { while (layerId < numLayers) {
@ -77748,7 +77749,7 @@ async function loadDetect(config3) {
inputSize3.detector[1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0; inputSize3.detector[1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
} else if (config3.debug && models2.detector) } else if (config3.debug && models2.detector)
log("cached model:", models2.detector["modelUrl"]); log("cached model:", models2.detector["modelUrl"]);
await createAnchors(); createAnchors();
return models2.detector; return models2.detector;
} }
async function loadPose(config3) { async function loadPose(config3) {
@ -77763,7 +77764,7 @@ async function loadPose(config3) {
log("cached model:", models2.landmarks["modelUrl"]); log("cached model:", models2.landmarks["modelUrl"]);
return models2.landmarks; return models2.landmarks;
} }
async function prepareImage(input2, size2) { function prepareImage(input2, size2) {
const t2 = {}; const t2 = {};
if (!input2.shape || !input2.shape[1] || !input2.shape[2]) if (!input2.shape || !input2.shape[1] || !input2.shape[2])
return input2; return input2;
@ -77823,7 +77824,7 @@ function rescaleKeypoints(keypoints, outputSize2) {
} }
return keypoints; return keypoints;
} }
async function fixKeypoints(keypoints) { function fixKeypoints(keypoints) {
const leftPalm = keypoints.find((k) => k.part === "leftPalm"); const leftPalm = keypoints.find((k) => k.part === "leftPalm");
const leftWrist = keypoints.find((k) => k.part === "leftWrist"); const leftWrist = keypoints.find((k) => k.part === "leftWrist");
const leftIndex = keypoints.find((k) => k.part === "leftIndex"); const leftIndex = keypoints.find((k) => k.part === "leftIndex");
@ -77880,7 +77881,7 @@ async function predict5(input2, config3) {
skipped5++; skipped5++;
} else { } else {
const t2 = {}; const t2 = {};
t2.landmarks = await prepareImage(input2, 256); t2.landmarks = prepareImage(input2, 256);
cache = await detectLandmarks(t2.landmarks, config3, outputSize2); cache = await detectLandmarks(t2.landmarks, config3, outputSize2);
Object.keys(t2).forEach((tensor2) => dispose(t2[tensor2])); Object.keys(t2).forEach((tensor2) => dispose(t2[tensor2]));
lastTime5 = now(); lastTime5 = now();
@ -79006,7 +79007,7 @@ async function predict12(image2, config3, idx, count3) {
const resT = model14 == null ? void 0 : model14.execute(enhanced); const resT = model14 == null ? void 0 : model14.execute(enhanced);
lastTime11 = now(); lastTime11 = now();
dispose(enhanced); dispose(enhanced);
const genderT = await resT.find((t2) => t2.shape[1] === 1); const genderT = resT.find((t2) => t2.shape[1] === 1);
const gender2 = await genderT.data(); const gender2 = await genderT.data();
const confidence = Math.trunc(200 * Math.abs(gender2[0] - 0.5)) / 100; const confidence = Math.trunc(200 * Math.abs(gender2[0] - 0.5)) / 100;
if (confidence > (config3.face.description.minConfidence || 0)) { if (confidence > (config3.face.description.minConfidence || 0)) {
@ -82099,10 +82100,11 @@ var HandDetector = class {
__publicField(this, "inputSize"); __publicField(this, "inputSize");
__publicField(this, "inputSizeTensor"); __publicField(this, "inputSizeTensor");
__publicField(this, "doubleInputSizeTensor"); __publicField(this, "doubleInputSizeTensor");
var _a, _b, _c, _d;
this.model = model20; this.model = model20;
this.anchors = anchors2.map((anchor) => [anchor.x, anchor.y]); this.anchors = anchors2.map((anchor) => [anchor.x, anchor.y]);
this.anchorsTensor = tensor2d(this.anchors); this.anchorsTensor = tensor2d(this.anchors);
this.inputSize = this.model && this.model.inputs && this.model.inputs[0].shape ? this.model.inputs[0].shape[2] : 0; this.inputSize = ((_d = (_c = (_b = (_a = this == null ? void 0 : this.model) == null ? void 0 : _a.inputs) == null ? void 0 : _b[0]) == null ? void 0 : _c.shape) == null ? void 0 : _d[2]) || 0;
this.inputSizeTensor = tensor1d([this.inputSize, this.inputSize]); this.inputSizeTensor = tensor1d([this.inputSize, this.inputSize]);
this.doubleInputSizeTensor = tensor1d([this.inputSize * 2, this.inputSize * 2]); this.doubleInputSizeTensor = tensor1d([this.inputSize * 2, this.inputSize * 2]);
} }
@ -82125,12 +82127,13 @@ var HandDetector = class {
const t2 = {}; const t2 = {};
t2.reshape = reshape(rawPalmLandmarks, [-1, 7, 2]); t2.reshape = reshape(rawPalmLandmarks, [-1, 7, 2]);
t2.div = div(t2.reshape, this.inputSizeTensor); t2.div = div(t2.reshape, this.inputSizeTensor);
t2.landmarks = add2(t2.div, this.anchors[index2]); t2.landmarks = add2(t2.div, this.anchors[index2] ? this.anchors[index2] : 0);
const res = mul(t2.landmarks, this.inputSizeTensor); const res = mul(t2.landmarks, this.inputSizeTensor);
Object.keys(t2).forEach((tensor2) => dispose(t2[tensor2])); Object.keys(t2).forEach((tensor2) => dispose(t2[tensor2]));
return res; return res;
} }
async predict(input2, config3) { async predict(input2, config3) {
var _a;
const t2 = {}; const t2 = {};
t2.resize = image.resizeBilinear(input2, [this.inputSize, this.inputSize]); t2.resize = image.resizeBilinear(input2, [this.inputSize, this.inputSize]);
t2.div = div(t2.resize, constants.tf127); t2.div = div(t2.resize, constants.tf127);
@ -82143,7 +82146,7 @@ var HandDetector = class {
const scores = await t2.scores.data(); const scores = await t2.scores.data();
t2.boxes = slice(t2.predictions, [0, 1], [-1, 4]); t2.boxes = slice(t2.predictions, [0, 1], [-1, 4]);
t2.norm = this.normalizeBoxes(t2.boxes); t2.norm = this.normalizeBoxes(t2.boxes);
t2.nms = await image.nonMaxSuppressionAsync(t2.norm, t2.scores, 3 * config3.hand.maxDetected, config3.hand.iouThreshold, config3.hand.minConfidence); t2.nms = await image.nonMaxSuppressionAsync(t2.norm, t2.scores, 3 * (((_a = config3.hand) == null ? void 0 : _a.maxDetected) || 1), config3.hand.iouThreshold, config3.hand.minConfidence);
const nms = await t2.nms.array(); const nms = await t2.nms.array();
const hands = []; const hands = [];
for (const index2 of nms) { for (const index2 of nms) {
@ -82157,7 +82160,7 @@ var HandDetector = class {
const endPoint = box.slice(2, 4); const endPoint = box.slice(2, 4);
const palmLandmarks = await p2.palmLandmarks.array(); const palmLandmarks = await p2.palmLandmarks.array();
const hand3 = { startPoint, endPoint, palmLandmarks, confidence: scores[index2] }; const hand3 = { startPoint, endPoint, palmLandmarks, confidence: scores[index2] };
const scaled = scaleBoxCoordinates2(hand3, [input2.shape[2] / this.inputSize, input2.shape[1] / this.inputSize]); const scaled = scaleBoxCoordinates2(hand3, [(input2.shape[2] || 1) / this.inputSize, (input2.shape[1] || 0) / this.inputSize]);
hands.push(scaled); hands.push(scaled);
Object.keys(p2).forEach((tensor2) => dispose(p2[tensor2])); Object.keys(p2).forEach((tensor2) => dispose(p2[tensor2]));
} }
@ -82181,9 +82184,10 @@ var HandPipeline = class {
__publicField(this, "storedBoxes"); __publicField(this, "storedBoxes");
__publicField(this, "skipped"); __publicField(this, "skipped");
__publicField(this, "detectedHands"); __publicField(this, "detectedHands");
var _a, _b, _c;
this.handDetector = handDetector; this.handDetector = handDetector;
this.handPoseModel = handPoseModel2; this.handPoseModel = handPoseModel2;
this.inputSize = this.handPoseModel && this.handPoseModel.inputs[0].shape ? this.handPoseModel.inputs[0].shape[2] : 0; this.inputSize = ((_c = (_b = (_a = this.handPoseModel) == null ? void 0 : _a.inputs) == null ? void 0 : _b[0].shape) == null ? void 0 : _c[2]) || 0;
this.storedBoxes = []; this.storedBoxes = [];
this.skipped = Number.MAX_SAFE_INTEGER; this.skipped = Number.MAX_SAFE_INTEGER;
this.detectedHands = 0; this.detectedHands = 0;
@ -82803,8 +82807,9 @@ async function load14(config3) {
if (config3.debug) if (config3.debug)
log("cached model:", handPoseModel["modelUrl"]); log("cached model:", handPoseModel["modelUrl"]);
} }
const handDetector = new HandDetector(handDetectorModel); const handDetector = handDetectorModel ? new HandDetector(handDetectorModel) : void 0;
handPipeline = new HandPipeline(handDetector, handPoseModel); if (handDetector && handPoseModel)
handPipeline = new HandPipeline(handDetector, handPoseModel);
return [handDetectorModel, handPoseModel]; return [handDetectorModel, handPoseModel];
} }
@ -82832,7 +82837,7 @@ function extensions() {
return; return;
config2.extensions = gl.getSupportedExtensions(); config2.extensions = gl.getSupportedExtensions();
} }
async function register(instance2) { function register(instance2) {
if (instance2.config.backend !== "humangl") if (instance2.config.backend !== "humangl")
return; return;
if (config2.name in engine().registry && (!config2.gl || !config2.gl.getParameter(config2.gl.VERSION))) { if (config2.name in engine().registry && (!config2.gl || !config2.gl.getParameter(config2.gl.VERSION))) {
@ -82841,7 +82846,7 @@ async function register(instance2) {
} }
if (!findBackend(config2.name)) { if (!findBackend(config2.name)) {
try { try {
config2.canvas = await canvas(100, 100); config2.canvas = canvas(100, 100);
} catch (err) { } catch (err) {
log("error: cannot create canvas:", err); log("error: cannot create canvas:", err);
return; return;
@ -82859,7 +82864,7 @@ async function register(instance2) {
return; return;
} }
if (config2.canvas) { if (config2.canvas) {
config2.canvas.addEventListener("webglcontextlost", async (e2) => { config2.canvas.addEventListener("webglcontextlost", (e2) => {
log("error: humangl:", e2.type); log("error: humangl:", e2.type);
log("possible browser memory leak using webgl or conflict with multiple backend registrations"); log("possible browser memory leak using webgl or conflict with multiple backend registrations");
instance2.emit("error"); instance2.emit("error");
@ -82933,7 +82938,7 @@ function registerCustomOps() {
const kernelMod = { const kernelMod = {
kernelName: "FloorMod", kernelName: "FloorMod",
backendName: getBackend(), backendName: getBackend(),
kernelFunc: (op2) => tidy(() => floorDiv(op2.inputs.a / op2.inputs.b) * op2.inputs.b + mod(op2.inputs.a, op2.inputs.b)) kernelFunc: (op2) => tidy(() => add2(mul(floorDiv(op2.inputs.a / op2.inputs.b), op2.inputs.b), mod(op2.inputs.a, op2.inputs.b)))
}; };
registerKernel(kernelMod); registerKernel(kernelMod);
env2.kernels.push("floormod"); env2.kernels.push("floormod");
@ -82976,7 +82981,7 @@ async function check(instance2, force = false) {
} }
} }
if (instance2.config.backend === "humangl") if (instance2.config.backend === "humangl")
await register(instance2); register(instance2);
const available = Object.keys(engine().registryFactory); const available = Object.keys(engine().registryFactory);
if (instance2.config.debug) if (instance2.config.debug)
log("available backends:", available); log("available backends:", available);
@ -82994,7 +82999,7 @@ async function check(instance2, force = false) {
if (instance2.config.debug) if (instance2.config.debug)
log("wasm path:", instance2.config.wasmPath); log("wasm path:", instance2.config.wasmPath);
if (typeof setWasmPaths !== "undefined") if (typeof setWasmPaths !== "undefined")
await setWasmPaths(instance2.config.wasmPath, instance2.config.wasmPlatformFetch); setWasmPaths(instance2.config.wasmPath, instance2.config.wasmPlatformFetch);
else else
throw new Error("backend error: attempting to use wasm backend but wasm path is not set"); throw new Error("backend error: attempting to use wasm backend but wasm path is not set");
let mt = false; let mt = false;
@ -83421,7 +83426,7 @@ function padInput(input2, inputSize10) {
return final; return final;
} }
function rescaleBody(body4, outputSize2) { function rescaleBody(body4, outputSize2) {
body4.keypoints = body4.keypoints.filter((kpt4) => kpt4 && kpt4.position); body4.keypoints = body4.keypoints.filter((kpt4) => kpt4 == null ? void 0 : kpt4.position);
for (const kpt4 of body4.keypoints) { for (const kpt4 of body4.keypoints) {
kpt4.position = [ kpt4.position = [
kpt4.position[0] * (outputSize2[0] + cache5.padding[2][0] + cache5.padding[2][1]) / outputSize2[0] - cache5.padding[2][0], kpt4.position[0] * (outputSize2[0] + cache5.padding[2][0] + cache5.padding[2][1]) / outputSize2[0] - cache5.padding[2][0],
@ -83460,7 +83465,7 @@ async function load16(config3) {
inputSize8 = 256; inputSize8 = 256;
return model16; return model16;
} }
async function parseSinglePose(res, config3, image2) { function parseSinglePose(res, config3, image2) {
const kpt4 = res[0][0]; const kpt4 = res[0][0];
const keypoints = []; const keypoints = [];
let score = 0; let score = 0;
@ -83498,7 +83503,7 @@ async function parseSinglePose(res, config3, image2) {
bodies.push(body4); bodies.push(body4);
return bodies; return bodies;
} }
async function parseMultiPose(res, config3, image2) { function parseMultiPose(res, config3, image2) {
const bodies = []; const bodies = [];
for (let id = 0; id < res[0].length; id++) { for (let id = 0; id < res[0].length; id++) {
const kpt4 = res[0][id]; const kpt4 = res[0][id];
@ -83557,7 +83562,7 @@ async function predict16(input2, config3) {
t2.res = model16 == null ? void 0 : model16.execute(t2.input); t2.res = model16 == null ? void 0 : model16.execute(t2.input);
cache6.last = now(); cache6.last = now();
const res = await t2.res.array(); const res = await t2.res.array();
cache6.bodies = t2.res.shape[2] === 17 ? await parseSinglePose(res, config3, input2) : await parseMultiPose(res, config3, input2); cache6.bodies = t2.res.shape[2] === 17 ? parseSinglePose(res, config3, input2) : parseMultiPose(res, config3, input2);
for (const body4 of cache6.bodies) { for (const body4 of cache6.bodies) {
rescaleBody(body4, [input2.shape[2] || 1, input2.shape[1] || 1]); rescaleBody(body4, [input2.shape[2] || 1, input2.shape[1] || 1]);
jitter(body4.keypoints); jitter(body4.keypoints);
@ -83995,7 +84000,7 @@ async function predict18(input2, config3) {
const buffers = await Promise.all(res.map((tensor2) => tensor2.buffer())); const buffers = await Promise.all(res.map((tensor2) => tensor2.buffer()));
for (const t2 of res) for (const t2 of res)
dispose(t2); dispose(t2);
const decoded = await decode(buffers[0], buffers[1], buffers[2], buffers[3], config3.body.maxDetected, config3.body.minConfidence); const decoded = decode(buffers[0], buffers[1], buffers[2], buffers[3], config3.body.maxDetected, config3.body.minConfidence);
if (!model18.inputs[0].shape) if (!model18.inputs[0].shape)
return []; return [];
const scaled = scalePoses(decoded, [input2.shape[1], input2.shape[2]], [model18.inputs[0].shape[2], model18.inputs[0].shape[1]]); const scaled = scalePoses(decoded, [input2.shape[1], input2.shape[2]], [model18.inputs[0].shape[2], model18.inputs[0].shape[1]]);
@ -84207,6 +84212,7 @@ async function load20(instance2) {
} }
var instance; var instance;
function validateModel(newInstance, model20, name) { function validateModel(newInstance, model20, name) {
var _a;
if (newInstance) if (newInstance)
instance = newInstance; instance = newInstance;
if (!model20) if (!model20)
@ -84221,7 +84227,7 @@ function validateModel(newInstance, model20, name) {
const missing = []; const missing = [];
const url = model20["modelUrl"]; const url = model20["modelUrl"];
const executor = model20["executor"]; const executor = model20["executor"];
if (executor && executor.graph.nodes) { if ((_a = executor == null ? void 0 : executor.graph) == null ? void 0 : _a.nodes) {
for (const kernel of Object.values(executor.graph.nodes)) { for (const kernel of Object.values(executor.graph.nodes)) {
const op2 = kernel.op.toLowerCase(); const op2 = kernel.op.toLowerCase();
if (!ops.includes(op2)) if (!ops.includes(op2))
@ -84321,7 +84327,7 @@ async function loadModel(modelPath) {
log("error saving model:", modelUrl, err); log("error saving model:", modelUrl, err);
} }
} }
validateModel(null, model20, `${modelPath}`); validateModel(null, model20, `${modelPath || ""}`);
return model20; return model20;
} }
@ -84477,6 +84483,7 @@ var options3 = {
// src/draw/face.ts // src/draw/face.ts
var opt; var opt;
function drawLabels(f, ctx) { function drawLabels(f, ctx) {
var _a, _b;
if (opt.drawLabels) { if (opt.drawLabels) {
const labels2 = []; const labels2 = [];
labels2.push(`face: ${Math.trunc(100 * f.score)}%`); labels2.push(`face: ${Math.trunc(100 * f.score)}%`);
@ -84496,7 +84503,7 @@ function drawLabels(f, ctx) {
emotion2.length = 3; emotion2.length = 3;
labels2.push(emotion2.join(" ")); labels2.push(emotion2.join(" "));
} }
if (f.rotation && f.rotation.angle && f.rotation.gaze) { if (((_a = f.rotation) == null ? void 0 : _a.angle) && ((_b = f.rotation) == null ? void 0 : _b.gaze)) {
if (f.rotation.angle.roll) if (f.rotation.angle.roll)
labels2.push(`roll: ${rad2deg(f.rotation.angle.roll)}\xB0 yaw:${rad2deg(f.rotation.angle.yaw)}\xB0 pitch:${rad2deg(f.rotation.angle.pitch)}\xB0`); labels2.push(`roll: ${rad2deg(f.rotation.angle.roll)}\xB0 yaw:${rad2deg(f.rotation.angle.yaw)}\xB0 pitch:${rad2deg(f.rotation.angle.pitch)}\xB0`);
if (f.rotation.gaze.bearing) if (f.rotation.gaze.bearing)
@ -84518,7 +84525,8 @@ function drawLabels(f, ctx) {
} }
} }
function drawIrisElipse(f, ctx) { function drawIrisElipse(f, ctx) {
if (f.annotations && f.annotations.leftEyeIris && f.annotations.leftEyeIris[0]) { var _a, _b, _c, _d;
if (((_a = f.annotations) == null ? void 0 : _a.leftEyeIris) && ((_b = f.annotations) == null ? void 0 : _b.leftEyeIris[0])) {
ctx.strokeStyle = opt.useDepth ? "rgba(255, 200, 255, 0.3)" : opt.color; ctx.strokeStyle = opt.useDepth ? "rgba(255, 200, 255, 0.3)" : opt.color;
ctx.beginPath(); ctx.beginPath();
const sizeX = Math.abs(f.annotations.leftEyeIris[3][0] - f.annotations.leftEyeIris[1][0]) / 2; const sizeX = Math.abs(f.annotations.leftEyeIris[3][0] - f.annotations.leftEyeIris[1][0]) / 2;
@ -84530,7 +84538,7 @@ function drawIrisElipse(f, ctx) {
ctx.fill(); ctx.fill();
} }
} }
if (f.annotations && f.annotations.rightEyeIris && f.annotations.rightEyeIris[0]) { if (((_c = f.annotations) == null ? void 0 : _c.rightEyeIris) && ((_d = f.annotations) == null ? void 0 : _d.rightEyeIris[0])) {
ctx.strokeStyle = opt.useDepth ? "rgba(255, 200, 255, 0.3)" : opt.color; ctx.strokeStyle = opt.useDepth ? "rgba(255, 200, 255, 0.3)" : opt.color;
ctx.beginPath(); ctx.beginPath();
const sizeX = Math.abs(f.annotations.rightEyeIris[3][0] - f.annotations.rightEyeIris[1][0]) / 2; const sizeX = Math.abs(f.annotations.rightEyeIris[3][0] - f.annotations.rightEyeIris[1][0]) / 2;
@ -84614,7 +84622,7 @@ function drawFaceBoxes(f, ctx) {
rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3], opt); rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3], opt);
} }
} }
async function face(inCanvas2, result, drawOptions) { function face(inCanvas2, result, drawOptions) {
opt = mergeDeep(options3, drawOptions); opt = mergeDeep(options3, drawOptions);
if (!result || !inCanvas2) if (!result || !inCanvas2)
return; return;
@ -84637,7 +84645,7 @@ async function face(inCanvas2, result, drawOptions) {
} }
// src/draw/body.ts // src/draw/body.ts
async function body(inCanvas2, result, drawOptions) { function body(inCanvas2, result, drawOptions) {
const localOptions = mergeDeep(options3, drawOptions); const localOptions = mergeDeep(options3, drawOptions);
if (!result || !inCanvas2) if (!result || !inCanvas2)
return; return;
@ -84688,7 +84696,7 @@ async function body(inCanvas2, result, drawOptions) {
} }
// src/draw/hand.ts // src/draw/hand.ts
async function hand(inCanvas2, result, drawOptions) { function hand(inCanvas2, result, drawOptions) {
const localOptions = mergeDeep(options3, drawOptions); const localOptions = mergeDeep(options3, drawOptions);
if (!result || !inCanvas2) if (!result || !inCanvas2)
return; return;
@ -84760,7 +84768,7 @@ async function hand(inCanvas2, result, drawOptions) {
} }
// src/draw/object.ts // src/draw/object.ts
async function object(inCanvas2, result, drawOptions) { function object(inCanvas2, result, drawOptions) {
const localOptions = mergeDeep(options3, drawOptions); const localOptions = mergeDeep(options3, drawOptions);
if (!result || !inCanvas2) if (!result || !inCanvas2)
return; return;
@ -84789,7 +84797,7 @@ async function object(inCanvas2, result, drawOptions) {
} }
// src/draw/gesture.ts // src/draw/gesture.ts
async function gesture(inCanvas2, result, drawOptions) { function gesture(inCanvas2, result, drawOptions) {
const localOptions = mergeDeep(options3, drawOptions); const localOptions = mergeDeep(options3, drawOptions);
if (!result || !inCanvas2) if (!result || !inCanvas2)
return; return;
@ -84821,7 +84829,7 @@ async function gesture(inCanvas2, result, drawOptions) {
// src/draw/draw.ts // src/draw/draw.ts
var drawTime = 0; var drawTime = 0;
async function person(inCanvas2, result, drawOptions) { function person(inCanvas2, result, drawOptions) {
const localOptions = mergeDeep(options3, drawOptions); const localOptions = mergeDeep(options3, drawOptions);
if (!result || !inCanvas2) if (!result || !inCanvas2)
return; return;
@ -84848,7 +84856,7 @@ async function person(inCanvas2, result, drawOptions) {
} }
} }
} }
async function canvas2(input2, output) { function canvas2(input2, output) {
if (!input2 || !output) if (!input2 || !output)
return; return;
const ctx = getCanvasContext(output); const ctx = getCanvasContext(output);
@ -85008,7 +85016,7 @@ var calculateFaceAngle = (face4, imageSize) => {
// src/face/face.ts // src/face/face.ts
var detectFace = async (instance2, input2) => { var detectFace = async (instance2, input2) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w; var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
let timeStamp = now(); let timeStamp = now();
let ageRes; let ageRes;
let gearRes; let gearRes;
@ -85151,8 +85159,8 @@ var detectFace = async (instance2, input2) => {
} }
if (!((_v = instance2.config.face.iris) == null ? void 0 : _v.enabled)) { if (!((_v = instance2.config.face.iris) == null ? void 0 : _v.enabled)) {
} }
const irisSize = faces[i2].annotations && faces[i2].annotations.leftEyeIris && faces[i2].annotations.leftEyeIris[0] && faces[i2].annotations.rightEyeIris && faces[i2].annotations.rightEyeIris[0] && faces[i2].annotations.leftEyeIris.length > 0 && faces[i2].annotations.rightEyeIris.length > 0 && faces[i2].annotations.leftEyeIris[0] !== null && faces[i2].annotations.rightEyeIris[0] !== null ? Math.max(Math.abs(faces[i2].annotations.leftEyeIris[3][0] - faces[i2].annotations.leftEyeIris[1][0]), Math.abs(faces[i2].annotations.rightEyeIris[4][1] - faces[i2].annotations.rightEyeIris[2][1])) / input2.shape[2] : 0; const irisSize = ((_y = (_x = (_w = faces[i2]) == null ? void 0 : _w.annotations) == null ? void 0 : _x.leftEyeIris) == null ? void 0 : _y[0]) && ((_B = (_A = (_z = faces[i2]) == null ? void 0 : _z.annotations) == null ? void 0 : _A.rightEyeIris) == null ? void 0 : _B[0]) && faces[i2].annotations.leftEyeIris.length > 0 && faces[i2].annotations.rightEyeIris.length > 0 && faces[i2].annotations.leftEyeIris[0] !== null && faces[i2].annotations.rightEyeIris[0] !== null ? Math.max(Math.abs(faces[i2].annotations.leftEyeIris[3][0] - faces[i2].annotations.leftEyeIris[1][0]), Math.abs(faces[i2].annotations.rightEyeIris[4][1] - faces[i2].annotations.rightEyeIris[2][1])) / input2.shape[2] : 0;
const tensor2 = ((_w = instance2.config.face.detector) == null ? void 0 : _w.return) ? squeeze(faces[i2].tensor) : null; const tensor2 = ((_C = instance2.config.face.detector) == null ? void 0 : _C.return) ? squeeze(faces[i2].tensor) : null;
dispose(faces[i2].tensor); dispose(faces[i2].tensor);
if (faces[i2].tensor) if (faces[i2].tensor)
delete faces[i2].tensor; delete faces[i2].tensor;
@ -85324,7 +85332,7 @@ var hand2 = (res) => {
var bufferedResult = { face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0, error: null }; var bufferedResult = { face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0, error: null };
var interpolateTime = 0; var interpolateTime = 0;
function calc2(newResult, config3) { function calc2(newResult, config3) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n; var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
const t0 = now(); const t0 = now();
if (!newResult) if (!newResult)
return { face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0, error: null }; return { face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0, error: null };
@ -85398,7 +85406,7 @@ function calc2(newResult, config3) {
annotations2 = bufferedResult.hand[i2].annotations; annotations2 = bufferedResult.hand[i2].annotations;
} else if (newResult.hand[i2].annotations) { } else if (newResult.hand[i2].annotations) {
for (const key of Object.keys(newResult.hand[i2].annotations)) { for (const key of Object.keys(newResult.hand[i2].annotations)) {
annotations2[key] = newResult.hand[i2].annotations[key] && newResult.hand[i2].annotations[key][0] ? newResult.hand[i2].annotations[key].map((val, j) => val.map((coord, k) => ((bufferedFactor - 1) * bufferedResult.hand[i2].annotations[key][j][k] + coord) / bufferedFactor)) : null; annotations2[key] = ((_f = (_e = (_d = newResult.hand[i2]) == null ? void 0 : _d.annotations) == null ? void 0 : _e[key]) == null ? void 0 : _f[0]) ? newResult.hand[i2].annotations[key].map((val, j) => val.map((coord, k) => ((bufferedFactor - 1) * bufferedResult.hand[i2].annotations[key][j][k] + coord) / bufferedFactor)) : null;
} }
} }
bufferedResult.hand[i2] = { ...newResult.hand[i2], box, boxRaw, keypoints, annotations: annotations2 }; bufferedResult.hand[i2] = { ...newResult.hand[i2], box, boxRaw, keypoints, annotations: annotations2 };
@ -85412,15 +85420,15 @@ function calc2(newResult, config3) {
const boxRaw = newResult.face[i2].boxRaw.map((b, j) => ((bufferedFactor - 1) * bufferedResult.face[i2].boxRaw[j] + b) / bufferedFactor); const boxRaw = newResult.face[i2].boxRaw.map((b, j) => ((bufferedFactor - 1) * bufferedResult.face[i2].boxRaw[j] + b) / bufferedFactor);
if (newResult.face[i2].rotation) { if (newResult.face[i2].rotation) {
const rotation = { matrix: [0, 0, 0, 0, 0, 0, 0, 0, 0], angle: { roll: 0, yaw: 0, pitch: 0 }, gaze: { bearing: 0, strength: 0 } }; const rotation = { matrix: [0, 0, 0, 0, 0, 0, 0, 0, 0], angle: { roll: 0, yaw: 0, pitch: 0 }, gaze: { bearing: 0, strength: 0 } };
rotation.matrix = (_d = newResult.face[i2].rotation) == null ? void 0 : _d.matrix; rotation.matrix = (_g = newResult.face[i2].rotation) == null ? void 0 : _g.matrix;
rotation.angle = { rotation.angle = {
roll: ((bufferedFactor - 1) * (((_e = bufferedResult.face[i2].rotation) == null ? void 0 : _e.angle.roll) || 0) + (((_f = newResult.face[i2].rotation) == null ? void 0 : _f.angle.roll) || 0)) / bufferedFactor, roll: ((bufferedFactor - 1) * (((_h = bufferedResult.face[i2].rotation) == null ? void 0 : _h.angle.roll) || 0) + (((_i = newResult.face[i2].rotation) == null ? void 0 : _i.angle.roll) || 0)) / bufferedFactor,
yaw: ((bufferedFactor - 1) * (((_g = bufferedResult.face[i2].rotation) == null ? void 0 : _g.angle.yaw) || 0) + (((_h = newResult.face[i2].rotation) == null ? void 0 : _h.angle.yaw) || 0)) / bufferedFactor, yaw: ((bufferedFactor - 1) * (((_j = bufferedResult.face[i2].rotation) == null ? void 0 : _j.angle.yaw) || 0) + (((_k = newResult.face[i2].rotation) == null ? void 0 : _k.angle.yaw) || 0)) / bufferedFactor,
pitch: ((bufferedFactor - 1) * (((_i = bufferedResult.face[i2].rotation) == null ? void 0 : _i.angle.pitch) || 0) + (((_j = newResult.face[i2].rotation) == null ? void 0 : _j.angle.pitch) || 0)) / bufferedFactor pitch: ((bufferedFactor - 1) * (((_l = bufferedResult.face[i2].rotation) == null ? void 0 : _l.angle.pitch) || 0) + (((_m = newResult.face[i2].rotation) == null ? void 0 : _m.angle.pitch) || 0)) / bufferedFactor
}; };
rotation.gaze = { rotation.gaze = {
bearing: ((bufferedFactor - 1) * (((_k = bufferedResult.face[i2].rotation) == null ? void 0 : _k.gaze.bearing) || 0) + (((_l = newResult.face[i2].rotation) == null ? void 0 : _l.gaze.bearing) || 0)) / bufferedFactor, bearing: ((bufferedFactor - 1) * (((_n = bufferedResult.face[i2].rotation) == null ? void 0 : _n.gaze.bearing) || 0) + (((_o = newResult.face[i2].rotation) == null ? void 0 : _o.gaze.bearing) || 0)) / bufferedFactor,
strength: ((bufferedFactor - 1) * (((_m = bufferedResult.face[i2].rotation) == null ? void 0 : _m.gaze.strength) || 0) + (((_n = newResult.face[i2].rotation) == null ? void 0 : _n.gaze.strength) || 0)) / bufferedFactor strength: ((bufferedFactor - 1) * (((_p = bufferedResult.face[i2].rotation) == null ? void 0 : _p.gaze.strength) || 0) + (((_q = newResult.face[i2].rotation) == null ? void 0 : _q.gaze.strength) || 0)) / bufferedFactor
}; };
bufferedResult.face[i2] = { ...newResult.face[i2], rotation, box, boxRaw }; bufferedResult.face[i2] = { ...newResult.face[i2], rotation, box, boxRaw };
} }
@ -85554,7 +85562,7 @@ function join2(faces, bodies, hands, gestures, shape) {
const minX = Math.min(...x); const minX = Math.min(...x);
const minY = Math.min(...y); const minY = Math.min(...y);
person2.box = [minX, minY, Math.max(...x) - minX, Math.max(...y) - minY]; person2.box = [minX, minY, Math.max(...x) - minX, Math.max(...y) - minY];
if (shape && shape[1] && shape[2]) if ((shape == null ? void 0 : shape[1]) && (shape == null ? void 0 : shape[2]))
person2.boxRaw = [person2.box[0] / shape[2], person2.box[1] / shape[1], person2.box[2] / shape[2], person2.box[3] / shape[1]]; person2.boxRaw = [person2.box[0] / shape[2], person2.box[1] / shape[1], person2.box[2] / shape[2], person2.box[3] / shape[1]];
persons.push(person2); persons.push(person2);
} }
@ -86358,7 +86366,7 @@ async function warmupNode(instance2) {
let res; let res;
if ("node" in tfjs_esm_exports && getBackend() === "tensorflow") { if ("node" in tfjs_esm_exports && getBackend() === "tensorflow") {
const data = (void 0).decodeJpeg(img); const data = (void 0).decodeJpeg(img);
const expanded = data.expandDims(0); const expanded = expandDims(data, 0);
instance2.tf.dispose(data); instance2.tf.dispose(data);
res = await instance2.detect(expanded, instance2.config); res = await instance2.detect(expanded, instance2.config);
instance2.tf.dispose(expanded); instance2.tf.dispose(expanded);
@ -86379,6 +86387,7 @@ async function runInference(instance2) {
return res; return res;
} }
async function runCompile(allModels) { async function runCompile(allModels) {
var _a, _b, _c, _d;
if (!env().flagRegistry.ENGINE_COMPILE_ONLY) if (!env().flagRegistry.ENGINE_COMPILE_ONLY)
return; return;
const backendType = getBackend(); const backendType = getBackend();
@ -86390,8 +86399,8 @@ async function runCompile(allModels) {
const numTensorsStart = engine().state.numTensors; const numTensorsStart = engine().state.numTensors;
const compiledModels = []; const compiledModels = [];
for (const [modelName, model20] of Object.entries(allModels).filter(([key, val]) => key !== null && val !== null)) { for (const [modelName, model20] of Object.entries(allModels).filter(([key, val]) => key !== null && val !== null)) {
const shape = model20.inputs && model20.inputs[0] && model20.inputs[0].shape ? [...model20.inputs[0].shape] : [1, 64, 64, 3]; const shape = ((_b = (_a = model20.inputs) == null ? void 0 : _a[0]) == null ? void 0 : _b.shape) ? [...model20.inputs[0].shape] : [1, 64, 64, 3];
const dtype = model20.inputs && model20.inputs[0] && model20.inputs[0].dtype ? model20.inputs[0].dtype : "float32"; const dtype = ((_d = (_c = model20.inputs) == null ? void 0 : _c[0]) == null ? void 0 : _d.dtype) ? model20.inputs[0].dtype : "float32";
for (let dim = 0; dim < shape.length; dim++) { for (let dim = 0; dim < shape.length; dim++) {
if (shape[dim] === -1) if (shape[dim] === -1)
shape[dim] = dim === 0 ? 1 : 64; shape[dim] = dim === 0 ? 1 : 64;
@ -86486,7 +86495,8 @@ var Human = class {
__publicField(this, "distance", distance); __publicField(this, "distance", distance);
__publicField(this, "match", match2); __publicField(this, "match", match2);
__publicField(this, "emit", (event) => { __publicField(this, "emit", (event) => {
if (this.events && this.events.dispatchEvent) var _a;
if ((_a = this.events) == null ? void 0 : _a.dispatchEvent)
this.events.dispatchEvent(new Event(event)); this.events.dispatchEvent(new Event(event));
}); });
this.env = env2; this.env = env2;

File diff suppressed because one or more lines are too long

570
dist/human.js vendored

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@ declare interface ArrayMap {
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu']; export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */ /** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): void;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose; export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
@ -140,7 +140,7 @@ declare function browserFiles(files: File[]): IOHandler;
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler; declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */ /** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>; declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): void;
/** /**
* Concatenate a number of ArrayBuffers into one. * Concatenate a number of ArrayBuffers into one.
@ -509,7 +509,7 @@ export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' |
export declare type ExternalCanvas = typeof env.Canvas; export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */ /** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): void;
/** Anti-spoofing part of face configuration */ /** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig { export declare interface FaceAntiSpoofConfig extends GenericConfig {
@ -780,7 +780,7 @@ export declare interface GenericConfig {
} }
/** draw detected gestures */ /** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): void;
/** Controlls gesture detection */ /** Controlls gesture detection */
export declare interface GestureConfig { export declare interface GestureConfig {
@ -1038,7 +1038,7 @@ export declare class GraphModel<ModelURL extends Url = string | io.IOHandler> im
} }
/** draw detected hands */ /** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all hand detection specific options */ /** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig { export declare interface HandConfig extends GenericConfig {
@ -2022,7 +2022,7 @@ declare type NamedTensorsMap = {
declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64'; declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64';
/** draw detected objects */ /** draw detected objects */
declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all object detection specific options */ /** Configures all object detection specific options */
export declare interface ObjectConfig extends GenericConfig { export declare interface ObjectConfig extends GenericConfig {
@ -2065,7 +2065,7 @@ declare type OnProgressCallback = (fraction: number) => void;
declare const options: DrawOptions; declare const options: DrawOptions;
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): void;
/** Person getter /** Person getter
* - Triggers combining all individual results into a virtual person object * - Triggers combining all individual results into a virtual person object

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@ declare interface ArrayMap {
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu']; export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */ /** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): void;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose; export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
@ -140,7 +140,7 @@ declare function browserFiles(files: File[]): IOHandler;
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler; declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */ /** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>; declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): void;
/** /**
* Concatenate a number of ArrayBuffers into one. * Concatenate a number of ArrayBuffers into one.
@ -509,7 +509,7 @@ export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' |
export declare type ExternalCanvas = typeof env.Canvas; export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */ /** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): void;
/** Anti-spoofing part of face configuration */ /** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig { export declare interface FaceAntiSpoofConfig extends GenericConfig {
@ -780,7 +780,7 @@ export declare interface GenericConfig {
} }
/** draw detected gestures */ /** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): void;
/** Controlls gesture detection */ /** Controlls gesture detection */
export declare interface GestureConfig { export declare interface GestureConfig {
@ -1038,7 +1038,7 @@ export declare class GraphModel<ModelURL extends Url = string | io.IOHandler> im
} }
/** draw detected hands */ /** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all hand detection specific options */ /** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig { export declare interface HandConfig extends GenericConfig {
@ -2022,7 +2022,7 @@ declare type NamedTensorsMap = {
declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64'; declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64';
/** draw detected objects */ /** draw detected objects */
declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all object detection specific options */ /** Configures all object detection specific options */
export declare interface ObjectConfig extends GenericConfig { export declare interface ObjectConfig extends GenericConfig {
@ -2065,7 +2065,7 @@ declare type OnProgressCallback = (fraction: number) => void;
declare const options: DrawOptions; declare const options: DrawOptions;
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): void;
/** Person getter /** Person getter
* - Triggers combining all individual results into a virtual person object * - Triggers combining all individual results into a virtual person object

File diff suppressed because one or more lines are too long

14
dist/human.node.d.ts vendored
View File

@ -28,7 +28,7 @@ declare interface ArrayMap {
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu']; export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */ /** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): void;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose; export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
@ -140,7 +140,7 @@ declare function browserFiles(files: File[]): IOHandler;
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler; declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */ /** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>; declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): void;
/** /**
* Concatenate a number of ArrayBuffers into one. * Concatenate a number of ArrayBuffers into one.
@ -509,7 +509,7 @@ export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' |
export declare type ExternalCanvas = typeof env.Canvas; export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */ /** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): void;
/** Anti-spoofing part of face configuration */ /** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig { export declare interface FaceAntiSpoofConfig extends GenericConfig {
@ -780,7 +780,7 @@ export declare interface GenericConfig {
} }
/** draw detected gestures */ /** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): void;
/** Controlls gesture detection */ /** Controlls gesture detection */
export declare interface GestureConfig { export declare interface GestureConfig {
@ -1038,7 +1038,7 @@ export declare class GraphModel<ModelURL extends Url = string | io.IOHandler> im
} }
/** draw detected hands */ /** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all hand detection specific options */ /** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig { export declare interface HandConfig extends GenericConfig {
@ -2022,7 +2022,7 @@ declare type NamedTensorsMap = {
declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64'; declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64';
/** draw detected objects */ /** draw detected objects */
declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all object detection specific options */ /** Configures all object detection specific options */
export declare interface ObjectConfig extends GenericConfig { export declare interface ObjectConfig extends GenericConfig {
@ -2065,7 +2065,7 @@ declare type OnProgressCallback = (fraction: number) => void;
declare const options: DrawOptions; declare const options: DrawOptions;
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): void;
/** Person getter /** Person getter
* - Triggers combining all individual results into a virtual person object * - Triggers combining all individual results into a virtual person object

20
dist/human.node.js vendored

File diff suppressed because one or more lines are too long

View File

@ -38,7 +38,7 @@ export async function loadDetect(config: Config): Promise<GraphModel> {
inputSize.detector[0] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[1].size) : 0; inputSize.detector[0] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[1].size) : 0;
inputSize.detector[1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0; inputSize.detector[1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
} else if (config.debug && models.detector) log('cached model:', models.detector['modelUrl']); } else if (config.debug && models.detector) log('cached model:', models.detector['modelUrl']);
await detect.createAnchors(); detect.createAnchors();
return models.detector as GraphModel; return models.detector as GraphModel;
} }
@ -59,7 +59,7 @@ export async function load(config: Config): Promise<[GraphModel | null, GraphMod
return [models.detector, models.landmarks]; return [models.detector, models.landmarks];
} }
async function prepareImage(input: Tensor, size: number): Promise<Tensor> { function prepareImage(input: Tensor, size: number): Tensor {
const t: Record<string, Tensor> = {}; const t: Record<string, Tensor> = {};
if (!input.shape || !input.shape[1] || !input.shape[2]) return input; if (!input.shape || !input.shape[1] || !input.shape[2]) return input;
let final: Tensor; let final: Tensor;
@ -120,7 +120,7 @@ function rescaleKeypoints(keypoints: BodyKeypoint[], outputSize: [number, number
return keypoints; return keypoints;
} }
async function fixKeypoints(keypoints: BodyKeypoint[]) { function fixKeypoints(keypoints: BodyKeypoint[]) {
// palm z-coord is incorrect around near-zero so we approximate it // palm z-coord is incorrect around near-zero so we approximate it
const leftPalm = keypoints.find((k) => k.part === 'leftPalm') as BodyKeypoint; const leftPalm = keypoints.find((k) => k.part === 'leftPalm') as BodyKeypoint;
const leftWrist = keypoints.find((k) => k.part === 'leftWrist') as BodyKeypoint; const leftWrist = keypoints.find((k) => k.part === 'leftWrist') as BodyKeypoint;
@ -220,7 +220,7 @@ export async function predict(input: Tensor, config: Config): Promise<BodyResult
const boxes = await detectBoxes(t.detector, config, outputSize); const boxes = await detectBoxes(t.detector, config, outputSize);
} }
*/ */
t.landmarks = await prepareImage(input, 256); // padded and resized t.landmarks = prepareImage(input, 256); // padded and resized
cache = await detectLandmarks(t.landmarks, config, outputSize); cache = await detectLandmarks(t.landmarks, config, outputSize);
/* /*
cropBox = [0, 0, 1, 1]; // reset crop coordinates cropBox = [0, 0, 1, 1]; // reset crop coordinates

View File

@ -10,7 +10,7 @@ let anchorTensor: { x, y };
const numLayers = 5; const numLayers = 5;
const strides = [8, 16, 32, 32, 32]; const strides = [8, 16, 32, 32, 32];
export async function createAnchors() { export function createAnchors() {
const anchors: { x: number, y: number }[] = []; const anchors: { x: number, y: number }[] = [];
let layerId = 0; let layerId = 0;
while (layerId < numLayers) { while (layerId < numLayers) {
@ -62,7 +62,7 @@ export async function decode(boxesTensor: Tensor, logitsTensor: Tensor, config:
const i = (await t.argmax.data())[0]; const i = (await t.argmax.data())[0];
const scores = await t.scores.data(); const scores = await t.scores.data();
const detected: { box: Box, boxRaw: Box, score: number }[] = []; const detected: { box: Box, boxRaw: Box, score: number }[] = [];
const minScore = (config.body['detector'] && config.body['detector'].minConfidence) ? config.body['detector'].minConfidence : 0; const minScore = config.body?.['detector']?.minConfidence || 0;
if (scores[i] >= minScore) { if (scores[i] >= minScore) {
const boxes = await t.boxes.array(); const boxes = await t.boxes.array();
const boxRaw: Box = boxes[i]; const boxRaw: Box = boxes[i];

View File

@ -42,7 +42,7 @@ export async function load(config: Config): Promise<GraphModel> {
return model; return model;
} }
async function parseSinglePose(res, config, image) { function parseSinglePose(res, config, image) {
const kpt = res[0][0]; const kpt = res[0][0];
const keypoints: BodyKeypoint[] = []; const keypoints: BodyKeypoint[] = [];
let score = 0; let score = 0;
@ -80,7 +80,7 @@ async function parseSinglePose(res, config, image) {
return bodies; return bodies;
} }
async function parseMultiPose(res, config, image) { function parseMultiPose(res, config, image) {
const bodies: BodyResult[] = []; const bodies: BodyResult[] = [];
for (let id = 0; id < res[0].length; id++) { for (let id = 0; id < res[0].length; id++) {
const kpt = res[0][id]; const kpt = res[0][id];
@ -174,8 +174,8 @@ export async function predict(input: Tensor, config: Config): Promise<BodyResult
cache.last = now(); cache.last = now();
const res = await t.res.array(); const res = await t.res.array();
cache.bodies = (t.res.shape[2] === 17) cache.bodies = (t.res.shape[2] === 17)
? await parseSinglePose(res, config, input) ? parseSinglePose(res, config, input)
: await parseMultiPose(res, config, input); : parseMultiPose(res, config, input);
for (const body of cache.bodies) { for (const body of cache.bodies) {
fix.rescaleBody(body, [input.shape[2] || 1, input.shape[1] || 1]); fix.rescaleBody(body, [input.shape[2] || 1, input.shape[1] || 1]);
fix.jitter(body.keypoints); fix.jitter(body.keypoints);

View File

@ -90,7 +90,7 @@ export function padInput(input: Tensor, inputSize: number): Tensor {
} }
export function rescaleBody(body: BodyResult, outputSize: [number, number]): BodyResult { export function rescaleBody(body: BodyResult, outputSize: [number, number]): BodyResult {
body.keypoints = body.keypoints.filter((kpt) => kpt && kpt.position); // filter invalid keypoints body.keypoints = body.keypoints.filter((kpt) => kpt?.position); // filter invalid keypoints
for (const kpt of body.keypoints) { for (const kpt of body.keypoints) {
kpt.position = [ kpt.position = [
kpt.position[0] * (outputSize[0] + cache.padding[2][0] + cache.padding[2][1]) / outputSize[0] - cache.padding[2][0], kpt.position[0] * (outputSize[0] + cache.padding[2][0] + cache.padding[2][1]) / outputSize[0] - cache.padding[2][0],

View File

@ -19,7 +19,7 @@ const localMaximumRadius = 1;
const outputStride = 16; const outputStride = 16;
const squaredNmsRadius = 50 ** 2; const squaredNmsRadius = 50 ** 2;
function traverse(edgeId, sourceKeypoint, targetId, scores, offsets, displacements, offsetRefineStep = 2) { function traverse(edgeId: number, sourceKeypoint, targetId, scores, offsets, displacements, offsetRefineStep = 2) {
const getDisplacement = (point) => ({ const getDisplacement = (point) => ({
y: displacements.get(point.y, point.x, edgeId), y: displacements.get(point.y, point.x, edgeId),
x: displacements.get(point.y, point.x, (displacements.shape[2] / 2) + edgeId), x: displacements.get(point.y, point.x, (displacements.shape[2] / 2) + edgeId),
@ -81,8 +81,8 @@ export function decodePose(root, scores, offsets, displacementsFwd, displacement
return keypoints; return keypoints;
} }
function scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, scores) { function scoreIsMaximumInLocalWindow(keypointId, score: number, heatmapY: number, heatmapX: number, scores) {
const [height, width] = scores.shape; const [height, width]: [number, number] = scores.shape;
let localMaximum = true; let localMaximum = true;
const yStart = Math.max(heatmapY - localMaximumRadius, 0); const yStart = Math.max(heatmapY - localMaximumRadius, 0);
const yEnd = Math.min(heatmapY + localMaximumRadius + 1, height); const yEnd = Math.min(heatmapY + localMaximumRadius + 1, height);
@ -172,7 +172,7 @@ export async function predict(input: Tensor, config: Config): Promise<BodyResult
const buffers = await Promise.all(res.map((tensor: Tensor) => tensor.buffer())); const buffers = await Promise.all(res.map((tensor: Tensor) => tensor.buffer()));
for (const t of res) tf.dispose(t); for (const t of res) tf.dispose(t);
const decoded = await decode(buffers[0], buffers[1], buffers[2], buffers[3], config.body.maxDetected, config.body.minConfidence); const decoded = decode(buffers[0], buffers[1], buffers[2], buffers[3], config.body.maxDetected, config.body.minConfidence);
if (!model.inputs[0].shape) return []; if (!model.inputs[0].shape) return [];
const scaled = utils.scalePoses(decoded, [input.shape[1], input.shape[2]], [model.inputs[0].shape[2], model.inputs[0].shape[1]]); const scaled = utils.scalePoses(decoded, [input.shape[1], input.shape[2]], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
return scaled; return scaled;

View File

@ -154,14 +154,14 @@ export class MaxHeap {
} }
} }
export function getOffsetPoint(y, x, keypoint, offsets) { export function getOffsetPoint(y, x, keypoint: number, offsets) {
return { return {
y: offsets.get(y, x, keypoint), y: offsets.get(y, x, keypoint),
x: offsets.get(y, x, keypoint + count), x: offsets.get(y, x, keypoint + count),
}; };
} }
export function getImageCoords(part, outputStride, offsets) { export function getImageCoords(part, outputStride: number, offsets) {
const { heatmapY, heatmapX, id: keypoint } = part; const { heatmapY, heatmapX, id: keypoint } = part;
const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets); const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets);
return { return {
@ -190,7 +190,7 @@ export function squaredDistance(y1, x1, y2, x2) {
return dy * dy + dx * dx; return dy * dy + dx * dx;
} }
export function addVectors(a, b) { export function addVectors(a: { x: number, y: number }, b: { x: number, y: number }) {
return { x: a.x + b.x, y: a.y + b.y }; return { x: a.x + b.x, y: a.y + b.y };
} }

View File

@ -5,8 +5,8 @@ import type { BodyResult } from '../result';
import type { AnyCanvas, DrawOptions } from '../exports'; import type { AnyCanvas, DrawOptions } from '../exports';
/** draw detected bodies */ /** draw detected bodies */
export async function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>) { export function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>) {
const localOptions = mergeDeep(options, drawOptions); const localOptions: DrawOptions = mergeDeep(options, drawOptions);
if (!result || !inCanvas) return; if (!result || !inCanvas) return;
const ctx = getCanvasContext(inCanvas); const ctx = getCanvasContext(inCanvas);
if (!ctx) return; if (!ctx) return;

View File

@ -24,8 +24,8 @@ export { object } from './object';
export { gesture } from './gesture'; export { gesture } from './gesture';
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
export async function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>) { export function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>) {
const localOptions = mergeDeep(options, drawOptions); const localOptions: DrawOptions = mergeDeep(options, drawOptions);
if (!result || !inCanvas) return; if (!result || !inCanvas) return;
const ctx = getCanvasContext(inCanvas); const ctx = getCanvasContext(inCanvas);
if (!ctx) return; if (!ctx) return;
@ -52,7 +52,7 @@ export async function person(inCanvas: AnyCanvas, result: PersonResult[], drawOp
} }
/** draw processed canvas */ /** draw processed canvas */
export async function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas) { export function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas) {
if (!input || !output) return; if (!input || !output) return;
const ctx = getCanvasContext(output); const ctx = getCanvasContext(output);
if (!ctx) return; if (!ctx) return;

View File

@ -23,7 +23,7 @@ function drawLabels(f: FaceResult, ctx: CanvasRenderingContext2D | OffscreenCanv
if (emotion.length > 3) emotion.length = 3; if (emotion.length > 3) emotion.length = 3;
labels.push(emotion.join(' ')); labels.push(emotion.join(' '));
} }
if (f.rotation && f.rotation.angle && f.rotation.gaze) { if (f.rotation?.angle && f.rotation?.gaze) {
if (f.rotation.angle.roll) labels.push(`roll: ${rad2deg(f.rotation.angle.roll)}° yaw:${rad2deg(f.rotation.angle.yaw)}° pitch:${rad2deg(f.rotation.angle.pitch)}°`); if (f.rotation.angle.roll) labels.push(`roll: ${rad2deg(f.rotation.angle.roll)}° yaw:${rad2deg(f.rotation.angle.yaw)}° pitch:${rad2deg(f.rotation.angle.pitch)}°`);
if (f.rotation.gaze.bearing) labels.push(`gaze: ${rad2deg(f.rotation.gaze.bearing)}°`); if (f.rotation.gaze.bearing) labels.push(`gaze: ${rad2deg(f.rotation.gaze.bearing)}°`);
} }
@ -44,7 +44,7 @@ function drawLabels(f: FaceResult, ctx: CanvasRenderingContext2D | OffscreenCanv
function drawIrisElipse(f: FaceResult, ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D) { function drawIrisElipse(f: FaceResult, ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D) {
// iris: array[center, left, top, right, bottom] // iris: array[center, left, top, right, bottom]
if (f.annotations && f.annotations.leftEyeIris && f.annotations.leftEyeIris[0]) { if (f.annotations?.leftEyeIris && f.annotations?.leftEyeIris[0]) {
ctx.strokeStyle = opt.useDepth ? 'rgba(255, 200, 255, 0.3)' : opt.color; ctx.strokeStyle = opt.useDepth ? 'rgba(255, 200, 255, 0.3)' : opt.color;
ctx.beginPath(); ctx.beginPath();
const sizeX = Math.abs(f.annotations.leftEyeIris[3][0] - f.annotations.leftEyeIris[1][0]) / 2; const sizeX = Math.abs(f.annotations.leftEyeIris[3][0] - f.annotations.leftEyeIris[1][0]) / 2;
@ -56,7 +56,7 @@ function drawIrisElipse(f: FaceResult, ctx: CanvasRenderingContext2D | Offscreen
ctx.fill(); ctx.fill();
} }
} }
if (f.annotations && f.annotations.rightEyeIris && f.annotations.rightEyeIris[0]) { if (f.annotations?.rightEyeIris && f.annotations?.rightEyeIris[0]) {
ctx.strokeStyle = opt.useDepth ? 'rgba(255, 200, 255, 0.3)' : opt.color; ctx.strokeStyle = opt.useDepth ? 'rgba(255, 200, 255, 0.3)' : opt.color;
ctx.beginPath(); ctx.beginPath();
const sizeX = Math.abs(f.annotations.rightEyeIris[3][0] - f.annotations.rightEyeIris[1][0]) / 2; const sizeX = Math.abs(f.annotations.rightEyeIris[3][0] - f.annotations.rightEyeIris[1][0]) / 2;
@ -149,7 +149,7 @@ function drawFaceBoxes(f: FaceResult, ctx) {
} }
/** draw detected faces */ /** draw detected faces */
export async function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>) { export function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>) {
opt = mergeDeep(options, drawOptions); opt = mergeDeep(options, drawOptions);
if (!result || !inCanvas) return; if (!result || !inCanvas) return;
const ctx = getCanvasContext(inCanvas); const ctx = getCanvasContext(inCanvas);

View File

@ -5,8 +5,8 @@ import type { GestureResult } from '../result';
import type { AnyCanvas, DrawOptions } from '../exports'; import type { AnyCanvas, DrawOptions } from '../exports';
/** draw detected gestures */ /** draw detected gestures */
export async function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>) { export function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>) {
const localOptions = mergeDeep(options, drawOptions); const localOptions: DrawOptions = mergeDeep(options, drawOptions);
if (!result || !inCanvas) return; if (!result || !inCanvas) return;
if (localOptions.drawGestures) { if (localOptions.drawGestures) {
const ctx = getCanvasContext(inCanvas); const ctx = getCanvasContext(inCanvas);

View File

@ -5,8 +5,8 @@ import type { HandResult } from '../result';
import type { AnyCanvas, DrawOptions, Point } from '../exports'; import type { AnyCanvas, DrawOptions, Point } from '../exports';
/** draw detected hands */ /** draw detected hands */
export async function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>) { export function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>) {
const localOptions = mergeDeep(options, drawOptions); const localOptions: DrawOptions = mergeDeep(options, drawOptions);
if (!result || !inCanvas) return; if (!result || !inCanvas) return;
const ctx = getCanvasContext(inCanvas); const ctx = getCanvasContext(inCanvas);
if (!ctx) return; if (!ctx) return;

View File

@ -5,8 +5,8 @@ import type { ObjectResult } from '../result';
import type { AnyCanvas, DrawOptions } from '../exports'; import type { AnyCanvas, DrawOptions } from '../exports';
/** draw detected objects */ /** draw detected objects */
export async function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>) { export function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>) {
const localOptions = mergeDeep(options, drawOptions); const localOptions: DrawOptions = mergeDeep(options, drawOptions);
if (!result || !inCanvas) return; if (!result || !inCanvas) return;
const ctx = getCanvasContext(inCanvas); const ctx = getCanvasContext(inCanvas);
if (!ctx) return; if (!ctx) return;

View File

@ -44,23 +44,23 @@ export interface DrawOptions {
/** currently set draw options {@link DrawOptions} */ /** currently set draw options {@link DrawOptions} */
export const options: DrawOptions = { export const options: DrawOptions = {
color: <string>'rgba(173, 216, 230, 0.6)', // 'lightblue' with light alpha channel color: 'rgba(173, 216, 230, 0.6)' as string, // 'lightblue' with light alpha channel
labelColor: <string>'rgba(173, 216, 230, 1)', // 'lightblue' with dark alpha channel labelColor: 'rgba(173, 216, 230, 1)' as string, // 'lightblue' with dark alpha channel
shadowColor: <string>'black', shadowColor: 'black' as string,
alpha: 0.5, alpha: 0.5 as number,
font: <string>'small-caps 16px "Segoe UI"', font: 'small-caps 16px "Segoe UI"' as string,
lineHeight: <number>18, lineHeight: 18 as number,
lineWidth: <number>4, lineWidth: 4 as number,
pointSize: <number>2, pointSize: 2 as number,
roundRect: <number>8, roundRect: 8 as number,
drawPoints: <boolean>false, drawPoints: false as boolean,
drawLabels: <boolean>true, drawLabels: true as boolean,
drawBoxes: <boolean>true, drawBoxes: true as boolean,
drawAttention: <boolean>true, drawAttention: true as boolean,
drawGestures: <boolean>true, drawGestures: true as boolean,
drawPolygons: <boolean>true, drawPolygons: true as boolean,
drawGaze: <boolean>true, drawGaze: true as boolean,
fillPolygons: <boolean>false, fillPolygons: false as boolean,
useDepth: <boolean>true, useDepth: true as boolean,
useCurves: <boolean>false, useCurves: false as boolean,
}; };

View File

@ -200,7 +200,7 @@ export const detectFace = async (instance: Human /* instance of human */, input:
// if (faces[i]?.annotations?.leftEyeIris) delete faces[i].annotations.leftEyeIris; // if (faces[i]?.annotations?.leftEyeIris) delete faces[i].annotations.leftEyeIris;
// if (faces[i]?.annotations?.rightEyeIris) delete faces[i].annotations.rightEyeIris; // if (faces[i]?.annotations?.rightEyeIris) delete faces[i].annotations.rightEyeIris;
} }
const irisSize = (faces[i].annotations && faces[i].annotations.leftEyeIris && faces[i].annotations.leftEyeIris[0] && faces[i].annotations.rightEyeIris && faces[i].annotations.rightEyeIris[0] const irisSize = (faces[i]?.annotations?.leftEyeIris?.[0] && faces[i]?.annotations?.rightEyeIris?.[0]
&& (faces[i].annotations.leftEyeIris.length > 0) && (faces[i].annotations.rightEyeIris.length > 0) && (faces[i].annotations.leftEyeIris.length > 0) && (faces[i].annotations.rightEyeIris.length > 0)
&& (faces[i].annotations.leftEyeIris[0] !== null) && (faces[i].annotations.rightEyeIris[0] !== null)) && (faces[i].annotations.leftEyeIris[0] !== null) && (faces[i].annotations.rightEyeIris[0] !== null))
? Math.max(Math.abs(faces[i].annotations.leftEyeIris[3][0] - faces[i].annotations.leftEyeIris[1][0]), Math.abs(faces[i].annotations.rightEyeIris[4][1] - faces[i].annotations.rightEyeIris[2][1])) / input.shape[2] ? Math.max(Math.abs(faces[i].annotations.leftEyeIris[3][0] - faces[i].annotations.leftEyeIris[1][0]), Math.abs(faces[i].annotations.rightEyeIris[4][1] - faces[i].annotations.rightEyeIris[2][1])) / input.shape[2]

View File

@ -56,11 +56,11 @@ export class FaceBoxes {
} }
} }
export async function load(config) { export async function load(config: Config) {
const model = await loadModel(config.face.detector?.modelPath); const model = await loadModel(config.face.detector?.modelPath);
if (config.debug) log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`); if (config.face.detector?.modelPath && config.debug) log(`load model: ${config.face.detector.modelPath?.match(/\/(.*)\./)?.[1] || ''}`);
const faceboxes = new FaceBoxes(model, config); const faceboxes = new FaceBoxes(model, config);
if (config.face.mesh.enabled && config.debug) log(`load model: ${config.face.mesh.modelPath.match(/\/(.*)\./)[1]}`); if (config.face.mesh?.enabled && config.face.mesh?.modelPath && config.debug) log(`load model: ${config.face.mesh.modelPath.match(/\/(.*)\./)?.[1] || ''}`);
if (config.face.iris.enabled && config.debug) log(`load model: ${config.face.iris.modelPath.match(/\/(.*)\./)[1]}`); if (config.face.iris?.enabled && config.face.iris?.modelPath && config.debug) log(`load model: ${config.face.iris.modelPath?.match(/\/(.*)\./)?.[1] || ''}`);
return faceboxes; return faceboxes;
} }

View File

@ -69,7 +69,7 @@ export const calculateLandmarksBoundingBox = (landmarks) => {
export const fixedRotationMatrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; export const fixedRotationMatrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
export const normalizeRadians = (angle) => angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI)); export const normalizeRadians = (angle: number) => angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));
export const computeRotation = (point1, point2) => normalizeRadians(Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0])); export const computeRotation = (point1, point2) => normalizeRadians(Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]));
@ -120,7 +120,7 @@ export const rotatePoint = (homogeneousCoordinate, rotationMatrix) => [dot(homog
export const xyDistanceBetweenPoints = (a, b) => Math.sqrt(((a[0] - b[0]) ** 2) + ((a[1] - b[1]) ** 2)); export const xyDistanceBetweenPoints = (a, b) => Math.sqrt(((a[0] - b[0]) ** 2) + ((a[1] - b[1]) ** 2));
export function generateAnchors(inputSize) { export function generateAnchors(inputSize: number) {
const spec = inputSize === 192 const spec = inputSize === 192
? { strides: [4], anchors: [1] } // facemesh-detector ? { strides: [4], anchors: [1] } // facemesh-detector
: { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] }; // blazeface : { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] }; // blazeface

View File

@ -40,8 +40,8 @@ export async function load(config: Config): Promise<GraphModel> {
export function enhance(input): Tensor { export function enhance(input): Tensor {
const tensor = (input.image || input.tensor || input) as Tensor; // input received from detector is already normalized to 0..1, input is also assumed to be straightened const tensor = (input.image || input.tensor || input) as Tensor; // input received from detector is already normalized to 0..1, input is also assumed to be straightened
if (!model?.inputs[0].shape) return tensor; // model has no shape so no point continuing if (!model?.inputs[0].shape) return tensor; // model has no shape so no point continuing
const crop = tf.image.resizeBilinear(tensor, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false); const crop: Tensor = tf.image.resizeBilinear(tensor, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);
const norm = tf.mul(crop, constants.tf255); const norm: Tensor = tf.mul(crop, constants.tf255);
tf.dispose(crop); tf.dispose(crop);
return norm; return norm;
/* /*
@ -74,10 +74,10 @@ export async function predict(image: Tensor, config: Config, idx: number, count:
skipped = 0; skipped = 0;
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
const obj = { const obj = {
age: <number>0, age: 0 as number,
gender: <Gender>'unknown', gender: 'unknown' as Gender,
genderScore: <number>0, genderScore: 0 as number,
descriptor: <number[]>[], descriptor: [] as number[],
}; };
if (config.face.description?.enabled) { if (config.face.description?.enabled) {
@ -85,7 +85,7 @@ export async function predict(image: Tensor, config: Config, idx: number, count:
const resT = model?.execute(enhanced) as Tensor[]; const resT = model?.execute(enhanced) as Tensor[];
lastTime = now(); lastTime = now();
tf.dispose(enhanced); tf.dispose(enhanced);
const genderT = await resT.find((t) => t.shape[1] === 1) as Tensor; const genderT = resT.find((t) => t.shape[1] === 1) as Tensor;
const gender = await genderT.data(); const gender = await genderT.data();
const confidence = Math.trunc(200 * Math.abs((gender[0] - 0.5))) / 100; const confidence = Math.trunc(200 * Math.abs((gender[0] - 0.5))) / 100;
if (confidence > (config.face.description.minConfidence || 0)) { if (confidence > (config.face.description.minConfidence || 0)) {
@ -93,7 +93,7 @@ export async function predict(image: Tensor, config: Config, idx: number, count:
obj.genderScore = Math.min(0.99, confidence); obj.genderScore = Math.min(0.99, confidence);
} }
const argmax = tf.argMax(resT.find((t) => t.shape[1] === 100), 1); const argmax = tf.argMax(resT.find((t) => t.shape[1] === 100), 1);
const age = (await argmax.data())[0]; const age: number = (await argmax.data())[0];
tf.dispose(argmax); tf.dispose(argmax);
const ageT = resT.find((t) => t.shape[1] === 100) as Tensor; const ageT = resT.find((t) => t.shape[1] === 100) as Tensor;
const all = await ageT.data(); const all = await ageT.data();
@ -102,7 +102,7 @@ export async function predict(image: Tensor, config: Config, idx: number, count:
const desc = resT.find((t) => t.shape[1] === 1024); const desc = resT.find((t) => t.shape[1] === 1024);
// const reshape = desc.reshape([128, 8]); // reshape large 1024-element descriptor to 128 x 8 // const reshape = desc.reshape([128, 8]); // reshape large 1024-element descriptor to 128 x 8
// const reduce = reshape.logSumExp(1); // reduce 2nd dimension by calculating logSumExp on it which leaves us with 128-element descriptor // const reduce = reshape.logSumExp(1); // reduce 2nd dimension by calculating logSumExp on it which leaves us with 128-element descriptor
const descriptor = desc ? await desc.data() : <number[]>[]; const descriptor = desc ? await desc.data() : [] as number[];
obj.descriptor = Array.from(descriptor); obj.descriptor = Array.from(descriptor);
resT.forEach((t) => tf.dispose(t)); resT.forEach((t) => tf.dispose(t));
} }

View File

@ -96,7 +96,7 @@ export async function load(config: Config): Promise<[GraphModel | null, GraphMod
if (config.debug) log('cached model:', handDetectorModel['modelUrl']); if (config.debug) log('cached model:', handDetectorModel['modelUrl']);
if (config.debug) log('cached model:', handPoseModel['modelUrl']); if (config.debug) log('cached model:', handPoseModel['modelUrl']);
} }
const handDetector = new handdetector.HandDetector(handDetectorModel); const handDetector = handDetectorModel ? new handdetector.HandDetector(handDetectorModel) : undefined;
handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel); if (handDetector && handPoseModel) handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel);
return [handDetectorModel, handPoseModel]; return [handDetectorModel, handPoseModel];
} }

View File

@ -9,6 +9,7 @@ import * as anchors from './handposeanchors';
import { constants } from '../tfjs/constants'; import { constants } from '../tfjs/constants';
import type { Tensor, GraphModel } from '../tfjs/types'; import type { Tensor, GraphModel } from '../tfjs/types';
import type { Point } from '../result'; import type { Point } from '../result';
import type { Config } from '../config';
export class HandDetector { export class HandDetector {
model: GraphModel; model: GraphModel;
@ -18,11 +19,11 @@ export class HandDetector {
inputSizeTensor: Tensor; inputSizeTensor: Tensor;
doubleInputSizeTensor: Tensor; doubleInputSizeTensor: Tensor;
constructor(model) { constructor(model: GraphModel) {
this.model = model; this.model = model;
this.anchors = anchors.anchors.map((anchor) => [anchor.x, anchor.y]); this.anchors = anchors.anchors.map((anchor) => [anchor.x, anchor.y]);
this.anchorsTensor = tf.tensor2d(this.anchors); this.anchorsTensor = tf.tensor2d(this.anchors);
this.inputSize = (this.model && this.model.inputs && this.model.inputs[0].shape) ? this.model.inputs[0].shape[2] : 0; this.inputSize = this?.model?.inputs?.[0]?.shape?.[2] || 0;
this.inputSizeTensor = tf.tensor1d([this.inputSize, this.inputSize]); this.inputSizeTensor = tf.tensor1d([this.inputSize, this.inputSize]);
this.doubleInputSizeTensor = tf.tensor1d([this.inputSize * 2, this.inputSize * 2]); this.doubleInputSizeTensor = tf.tensor1d([this.inputSize * 2, this.inputSize * 2]);
} }
@ -40,20 +41,20 @@ export class HandDetector {
t.endPoints = tf.mul(t.add, this.inputSizeTensor); t.endPoints = tf.mul(t.add, this.inputSizeTensor);
const res = tf.concat2d([t.startPoints, t.endPoints], 1); const res = tf.concat2d([t.startPoints, t.endPoints], 1);
Object.keys(t).forEach((tensor) => tf.dispose(t[tensor])); Object.keys(t).forEach((tensor) => tf.dispose(t[tensor]));
return res; return res as Tensor;
} }
normalizeLandmarks(rawPalmLandmarks, index) { normalizeLandmarks(rawPalmLandmarks, index: number) {
const t: Record<string, Tensor> = {}; const t: Record<string, Tensor> = {};
t.reshape = tf.reshape(rawPalmLandmarks, [-1, 7, 2]); t.reshape = tf.reshape(rawPalmLandmarks, [-1, 7, 2]);
t.div = tf.div(t.reshape, this.inputSizeTensor); t.div = tf.div(t.reshape, this.inputSizeTensor);
t.landmarks = tf.add(t.div, this.anchors[index]); t.landmarks = tf.add(t.div, this.anchors[index] ? this.anchors[index] : 0);
const res = tf.mul(t.landmarks, this.inputSizeTensor); const res = tf.mul(t.landmarks, this.inputSizeTensor);
Object.keys(t).forEach((tensor) => tf.dispose(t[tensor])); Object.keys(t).forEach((tensor) => tf.dispose(t[tensor]));
return res; return res as Tensor;
} }
async predict(input, config): Promise<{ startPoint: Point; endPoint: Point, palmLandmarks: Point[]; confidence: number }[]> { async predict(input: Tensor, config: Config): Promise<{ startPoint: Point; endPoint: Point, palmLandmarks: Point[]; confidence: number }[]> {
const t: Record<string, Tensor> = {}; const t: Record<string, Tensor> = {};
t.resize = tf.image.resizeBilinear(input, [this.inputSize, this.inputSize]); t.resize = tf.image.resizeBilinear(input, [this.inputSize, this.inputSize]);
t.div = tf.div(t.resize, constants.tf127); t.div = tf.div(t.resize, constants.tf127);
@ -67,7 +68,7 @@ export class HandDetector {
t.boxes = tf.slice(t.predictions, [0, 1], [-1, 4]); t.boxes = tf.slice(t.predictions, [0, 1], [-1, 4]);
t.norm = this.normalizeBoxes(t.boxes); t.norm = this.normalizeBoxes(t.boxes);
// box detection is flaky so we look for 3x boxes than we need results // box detection is flaky so we look for 3x boxes than we need results
t.nms = await tf.image.nonMaxSuppressionAsync(t.norm, t.scores, 3 * config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence); t.nms = await tf.image.nonMaxSuppressionAsync(t.norm, t.scores, 3 * (config.hand?.maxDetected || 1), config.hand.iouThreshold, config.hand.minConfidence);
const nms = await t.nms.array() as number[]; const nms = await t.nms.array() as number[];
const hands: { startPoint: Point; endPoint: Point; palmLandmarks: Point[]; confidence: number }[] = []; const hands: { startPoint: Point; endPoint: Point; palmLandmarks: Point[]; confidence: number }[] = [];
for (const index of nms) { for (const index of nms) {
@ -81,7 +82,7 @@ export class HandDetector {
const endPoint = box.slice(2, 4) as unknown as Point; const endPoint = box.slice(2, 4) as unknown as Point;
const palmLandmarks = await p.palmLandmarks.array(); const palmLandmarks = await p.palmLandmarks.array();
const hand = { startPoint, endPoint, palmLandmarks, confidence: scores[index] }; const hand = { startPoint, endPoint, palmLandmarks, confidence: scores[index] };
const scaled = util.scaleBoxCoordinates(hand, [input.shape[2] / this.inputSize, input.shape[1] / this.inputSize]); const scaled = util.scaleBoxCoordinates(hand, [(input.shape[2] || 1) / this.inputSize, (input.shape[1] || 0) / this.inputSize]);
hands.push(scaled); hands.push(scaled);
Object.keys(p).forEach((tensor) => tf.dispose(p[tensor])); Object.keys(p).forEach((tensor) => tf.dispose(p[tensor]));
} }

View File

@ -30,7 +30,7 @@ export class HandPipeline {
constructor(handDetector, handPoseModel) { constructor(handDetector, handPoseModel) {
this.handDetector = handDetector; this.handDetector = handDetector;
this.handPoseModel = handPoseModel; this.handPoseModel = handPoseModel;
this.inputSize = this.handPoseModel && this.handPoseModel.inputs[0].shape ? this.handPoseModel.inputs[0].shape[2] : 0; this.inputSize = this.handPoseModel?.inputs?.[0].shape?.[2] || 0;
this.storedBoxes = []; this.storedBoxes = [];
this.skipped = Number.MAX_SAFE_INTEGER; this.skipped = Number.MAX_SAFE_INTEGER;
this.detectedHands = 0; this.detectedHands = 0;

View File

@ -295,7 +295,7 @@ export class Human {
if (this.env.initial) { // print version info on first run and check for correct backend setup if (this.env.initial) { // print version info on first run and check for correct backend setup
if (this.config.debug) log(`version: ${this.version}`); if (this.config.debug) log(`version: ${this.version}`);
if (this.config.debug) log(`tfjs version: ${this.tf.version['tfjs-core']}`); if (this.config.debug) log(`tfjs version: ${this.tf.version['tfjs-core'] as string}`);
if (!await backend.check(this)) log('error: backend check failed'); if (!await backend.check(this)) log('error: backend check failed');
await tf.ready(); await tf.ready();
if (this.env.browser) { if (this.env.browser) {
@ -321,7 +321,7 @@ export class Human {
/** emit event */ /** emit event */
emit = (event: string) => { emit = (event: string) => {
if (this.events && this.events.dispatchEvent) this.events.dispatchEvent(new Event(event)); if (this.events?.dispatchEvent) this.events.dispatchEvent(new Event(event));
}; };
/** Runs interpolation using last known result and returns smoothened result /** Runs interpolation using last known result and returns smoothened result

View File

@ -20,5 +20,5 @@ export async function histogramEqualization(inputImage: Tensor): Promise<Tensor>
const rgb = tf.stack([enh[0], enh[1], enh[2]], 2); const rgb = tf.stack([enh[0], enh[1], enh[2]], 2);
const reshape = tf.reshape(rgb, [1, squeeze.shape[0], squeeze.shape[1], 3]); const reshape = tf.reshape(rgb, [1, squeeze.shape[0], squeeze.shape[1], 3]);
tf.dispose([...channels, ...min, ...max, ...sub, ...range, ...fact, ...enh, rgb, squeeze]); tf.dispose([...channels, ...min, ...max, ...sub, ...range, ...fact, ...enh, rgb, squeeze]);
return reshape; // output shape is [1, height, width, 3] return reshape as Tensor; // output shape is [1, height, width, 3]
} }

View File

@ -25,7 +25,7 @@ const last: { inputSum: number, cacheDiff: number, sumMethod: number, inputTenso
}; };
export function canvas(width: number, height: number): AnyCanvas { export function canvas(width: number, height: number): AnyCanvas {
let c; let c: AnyCanvas;
if (env.browser) { // browser defines canvas object if (env.browser) { // browser defines canvas object
if (env.worker) { // if runing in web worker use OffscreenCanvas if (env.worker) { // if runing in web worker use OffscreenCanvas
if (typeof OffscreenCanvas === 'undefined') throw new Error('canvas error: attempted to run in web worker but OffscreenCanvas is not supported'); if (typeof OffscreenCanvas === 'undefined') throw new Error('canvas error: attempted to run in web worker but OffscreenCanvas is not supported');
@ -42,6 +42,7 @@ export function canvas(width: number, height: number): AnyCanvas {
else if (typeof globalThis.Canvas !== 'undefined') c = new globalThis.Canvas(width, height); else if (typeof globalThis.Canvas !== 'undefined') c = new globalThis.Canvas(width, height);
// else throw new Error('canvas error: attempted to use canvas in nodejs without canvas support installed'); // else throw new Error('canvas error: attempted to use canvas in nodejs without canvas support installed');
} }
// @ts-ignore its either defined or we already threw an error
return c; return c;
} }
@ -98,7 +99,7 @@ export async function process(input: Input, config: Config, getTensor: boolean =
} }
} }
// at the end shape must be [1, height, width, 3] // at the end shape must be [1, height, width, 3]
if (tensor == null || (tensor as Tensor).shape.length !== 4 || (tensor as Tensor).shape[0] !== 1 || (tensor as Tensor).shape[3] !== 3) throw new Error(`input error: attempted to use tensor with unrecognized shape: ${(input as Tensor).shape}`); if (tensor == null || tensor.shape.length !== 4 || tensor.shape[0] !== 1 || tensor.shape[3] !== 3) throw new Error(`input error: attempted to use tensor with unrecognized shape: ${((input as Tensor).shape).toString()}`);
if ((tensor).dtype === 'int32') { if ((tensor).dtype === 'int32') {
const cast = tf.cast(tensor, 'float32'); const cast = tf.cast(tensor, 'float32');
tf.dispose(tensor); tf.dispose(tensor);
@ -111,14 +112,14 @@ export async function process(input: Input, config: Config, getTensor: boolean =
if (config.debug) log('input stream is not ready'); if (config.debug) log('input stream is not ready');
return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize
} }
const originalWidth = input['naturalWidth'] || input['videoWidth'] || input['width'] || (input['shape'] && (input['shape'][1] > 0)); const originalWidth: number = input['naturalWidth'] || input['videoWidth'] || input['width'] || (input['shape'] && (input['shape'][1] > 0));
const originalHeight = input['naturalHeight'] || input['videoHeight'] || input['height'] || (input['shape'] && (input['shape'][2] > 0)); const originalHeight: number = input['naturalHeight'] || input['videoHeight'] || input['height'] || (input['shape'] && (input['shape'][2] > 0));
if (!originalWidth || !originalHeight) { if (!originalWidth || !originalHeight) {
if (config.debug) log('cannot determine input dimensions'); if (config.debug) log('cannot determine input dimensions');
return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize
} }
let targetWidth = originalWidth; let targetWidth: number = originalWidth;
let targetHeight = originalHeight; let targetHeight: number = originalHeight;
if (targetWidth > maxSize) { if (targetWidth > maxSize) {
targetWidth = maxSize; targetWidth = maxSize;
targetHeight = Math.trunc(targetWidth * originalHeight / originalWidth); targetHeight = Math.trunc(targetWidth * originalHeight / originalWidth);
@ -129,9 +130,9 @@ export async function process(input: Input, config: Config, getTensor: boolean =
} }
// create our canvas and resize it if needed // create our canvas and resize it if needed
if ((config.filter.width || 0) > 0) targetWidth = config.filter.width; if ((config.filter?.width || 0) > 0) targetWidth = config.filter.width as number;
else if ((config.filter.height || 0) > 0) targetWidth = originalWidth * ((config.filter.height || 0) / originalHeight); else if ((config.filter?.height || 0) > 0) targetWidth = originalWidth * ((config.filter.height || 0) / originalHeight);
if ((config.filter.height || 0) > 0) targetHeight = config.filter.height; if ((config.filter.height || 0) > 0) targetHeight = config.filter.height as number;
else if ((config.filter.width || 0) > 0) targetHeight = originalHeight * ((config.filter.width || 0) / originalWidth); else if ((config.filter.width || 0) > 0) targetHeight = originalHeight * ((config.filter.width || 0) / originalWidth);
if (!targetWidth || !targetHeight) throw new Error('input error: cannot determine dimension'); if (!targetWidth || !targetHeight) throw new Error('input error: cannot determine dimension');
if (!inCanvas || (inCanvas.width !== targetWidth) || (inCanvas.height !== targetHeight)) inCanvas = canvas(targetWidth, targetHeight); if (!inCanvas || (inCanvas.width !== targetWidth) || (inCanvas.height !== targetHeight)) inCanvas = canvas(targetWidth, targetHeight);
@ -227,8 +228,8 @@ export async function process(input: Input, config: Config, getTensor: boolean =
pixels = rgb; pixels = rgb;
} }
if (!pixels) throw new Error('input error: cannot create tensor'); if (!pixels) throw new Error('input error: cannot create tensor');
const casted = tf.cast(pixels, 'float32'); const casted: Tensor = tf.cast(pixels, 'float32');
const tensor = config.filter.equalization ? await enhance.histogramEqualization(casted) : tf.expandDims(casted, 0); const tensor: Tensor = config.filter.equalization ? await enhance.histogramEqualization(casted) : tf.expandDims(casted, 0);
tf.dispose([pixels, casted]); tf.dispose([pixels, casted]);
return { tensor, canvas: (config.filter.return ? outCanvas : null) }; return { tensor, canvas: (config.filter.return ? outCanvas : null) };
} }

View File

@ -9,7 +9,7 @@ import * as shaders from './imagefxshaders';
import { canvas } from './image'; import { canvas } from './image';
import { log } from '../util/util'; import { log } from '../util/util';
const collect = (source, prefix, collection) => { const collect = (source, prefix: string, collection) => {
const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig'); const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig');
source.replace(r, (match, name) => { source.replace(r, (match, name) => {
collection[name] = 0; collection[name] = 0;
@ -37,7 +37,7 @@ class GLProgram {
this.gl.attachShader(this.id, fragmentShader); this.gl.attachShader(this.id, fragmentShader);
this.gl.linkProgram(this.id); this.gl.linkProgram(this.id);
if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS)) { if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS)) {
log(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`); log(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id) || 'unknown'}`);
return; return;
} }
this.gl.useProgram(this.id); this.gl.useProgram(this.id);
@ -57,7 +57,7 @@ class GLProgram {
this.gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
this.gl.compileShader(shader); this.gl.compileShader(shader);
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
log(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`); log(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader) || 'unknown'}`);
return null; return null;
} }
return shader; return shader;
@ -174,7 +174,7 @@ export function GLImageFilter() {
} }
const filter = { const filter = {
colorMatrix: (matrix) => { // general color matrix filter colorMatrix: (matrix: number[]) => { // general color matrix filter
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
m[4] /= 255; m[4] /= 255;
m[9] /= 255; m[9] /= 255;
@ -189,7 +189,7 @@ export function GLImageFilter() {
draw(); draw();
}, },
brightness: (brightness) => { brightness: (brightness: number) => {
const b = (brightness || 0) + 1; const b = (brightness || 0) + 1;
filter.colorMatrix([ filter.colorMatrix([
b, 0, 0, 0, 0, b, 0, 0, 0, 0,
@ -199,7 +199,7 @@ export function GLImageFilter() {
]); ]);
}, },
saturation: (amount) => { saturation: (amount: number) => {
const x = (amount || 0) * 2 / 3 + 1; const x = (amount || 0) * 2 / 3 + 1;
const y = ((x - 1) * -0.5); const y = ((x - 1) * -0.5);
filter.colorMatrix([ filter.colorMatrix([
@ -214,7 +214,7 @@ export function GLImageFilter() {
filter.saturation(-1); filter.saturation(-1);
}, },
contrast: (amount) => { contrast: (amount: number) => {
const v = (amount || 0) + 1; const v = (amount || 0) + 1;
const o = -128 * (v - 1); const o = -128 * (v - 1);
filter.colorMatrix([ filter.colorMatrix([
@ -229,7 +229,7 @@ export function GLImageFilter() {
filter.contrast(-2); filter.contrast(-2);
}, },
hue: (rotation) => { hue: (rotation: number) => {
rotation = (rotation || 0) / 180 * Math.PI; rotation = (rotation || 0) / 180 * Math.PI;
const cos = Math.cos(rotation); const cos = Math.cos(rotation);
const sin = Math.sin(rotation); const sin = Math.sin(rotation);
@ -316,7 +316,7 @@ export function GLImageFilter() {
]); ]);
}, },
convolution: (matrix) => { // general convolution Filter convolution: (matrix: number[]) => { // general convolution Filter
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
const pixelSizeX = 1 / fxcanvas.width; const pixelSizeX = 1 / fxcanvas.width;
const pixelSizeY = 1 / fxcanvas.height; const pixelSizeY = 1 / fxcanvas.height;
@ -364,7 +364,7 @@ export function GLImageFilter() {
]); ]);
}, },
emboss: (size) => { emboss: (size: number) => {
const s = size || 1; const s = size || 1;
// @ts-ignore this // @ts-ignore this
filter.convolution.call(this, [ filter.convolution.call(this, [
@ -374,7 +374,7 @@ export function GLImageFilter() {
]); ]);
}, },
blur: (size) => { blur: (size: number) => {
const blurSizeX = (size / 7) / fxcanvas.width; const blurSizeX = (size / 7) / fxcanvas.width;
const blurSizeY = (size / 7) / fxcanvas.height; const blurSizeY = (size / 7) / fxcanvas.height;
const program = compileShader(shaders.blur); const program = compileShader(shaders.blur);
@ -387,7 +387,7 @@ export function GLImageFilter() {
draw(); draw();
}, },
pixelate: (size) => { pixelate: (size: number) => {
const blurSizeX = (size) / fxcanvas.width; const blurSizeX = (size) / fxcanvas.width;
const blurSizeY = (size) / fxcanvas.height; const blurSizeY = (size) / fxcanvas.height;
const program = compileShader(shaders.pixelate); const program = compileShader(shaders.pixelate);

View File

@ -158,7 +158,7 @@ export function validateModel(newInstance: Human | null, model: GraphModel | nul
interface Op { name: string, category: string, op: string } interface Op { name: string, category: string, op: string }
const url = model['modelUrl'] as string; const url = model['modelUrl'] as string;
const executor = model['executor']; const executor = model['executor'];
if (executor && executor.graph.nodes) { if (executor?.graph?.nodes) {
for (const kernel of Object.values(executor.graph.nodes)) { for (const kernel of Object.values(executor.graph.nodes)) {
const op = (kernel as Op).op.toLowerCase(); const op = (kernel as Op).op.toLowerCase();
if (!ops.includes(op)) ops.push(op); if (!ops.includes(op)) ops.push(op);

View File

@ -21,7 +21,7 @@ function registerCustomOps() {
const kernelMod = { const kernelMod = {
kernelName: 'FloorMod', kernelName: 'FloorMod',
backendName: tf.getBackend(), backendName: tf.getBackend(),
kernelFunc: (op) => tf.tidy(() => tf.floorDiv(op.inputs.a / op.inputs.b) * op.inputs.b + tf.mod(op.inputs.a, op.inputs.b)), kernelFunc: (op) => tf.tidy(() => tf.add(tf.mul(tf.floorDiv(op.inputs.a / op.inputs.b), op.inputs.b), tf.mod(op.inputs.a, op.inputs.b))),
}; };
tf.registerKernel(kernelMod); tf.registerKernel(kernelMod);
env.kernels.push('floormod'); env.kernels.push('floormod');
@ -71,8 +71,8 @@ export async function check(instance: Human, force = false) {
} }
// check available backends // check available backends
if (instance.config.backend === 'humangl') await humangl.register(instance); if (instance.config.backend === 'humangl') humangl.register(instance);
const available = Object.keys(tf.engine().registryFactory); const available = Object.keys(tf.engine().registryFactory as Record<string, unknown>);
if (instance.config.debug) log('available backends:', available); if (instance.config.debug) log('available backends:', available);
if (!available.includes(instance.config.backend)) { if (!available.includes(instance.config.backend)) {
@ -87,7 +87,7 @@ export async function check(instance: Human, force = false) {
if (instance.config.backend === 'wasm') { if (instance.config.backend === 'wasm') {
if (tf.env().flagRegistry.CANVAS2D_WILL_READ_FREQUENTLY) tf.env().set('CANVAS2D_WILL_READ_FREQUENTLY', true); if (tf.env().flagRegistry.CANVAS2D_WILL_READ_FREQUENTLY) tf.env().set('CANVAS2D_WILL_READ_FREQUENTLY', true);
if (instance.config.debug) log('wasm path:', instance.config.wasmPath); if (instance.config.debug) log('wasm path:', instance.config.wasmPath);
if (typeof tf.setWasmPaths !== 'undefined') await tf.setWasmPaths(instance.config.wasmPath, instance.config.wasmPlatformFetch); if (typeof tf.setWasmPaths !== 'undefined') tf.setWasmPaths(instance.config.wasmPath, instance.config.wasmPlatformFetch);
else throw new Error('backend error: attempting to use wasm backend but wasm path is not set'); else throw new Error('backend error: attempting to use wasm backend but wasm path is not set');
let mt = false; let mt = false;
let simd = false; let simd = false;
@ -127,7 +127,7 @@ export async function check(instance: Human, force = false) {
} }
if (tf.backend().getGPGPUContext) { if (tf.backend().getGPGPUContext) {
const gl = await tf.backend().getGPGPUContext().gl; const gl = await tf.backend().getGPGPUContext().gl;
if (instance.config.debug) log(`gl version:${gl.getParameter(gl.VERSION)} renderer:${gl.getParameter(gl.RENDERER)}`); if (instance.config.debug) log(`gl version:${gl.getParameter(gl.VERSION) as string} renderer:${gl.getParameter(gl.RENDERER) as string}`);
} }
} }
@ -165,5 +165,5 @@ export function fakeOps(kernelNames: string[], config) {
}; };
tf.registerKernel(kernelConfig); tf.registerKernel(kernelConfig);
} }
env.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => kernel.kernelName.toLowerCase()); // re-scan registered ops env.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => (kernel.kernelName as string).toLowerCase()); // re-scan registered ops
} }

View File

@ -11,9 +11,9 @@ import type { AnyCanvas } from '../exports';
export const config = { export const config = {
name: 'humangl', name: 'humangl',
priority: 999, priority: 999,
canvas: <null | AnyCanvas>null, canvas: null as null | AnyCanvas,
gl: <null | WebGL2RenderingContext>null, gl: null as null | WebGL2RenderingContext,
extensions: <string[] | null> [], extensions: [] as string[] | null,
webGLattr: { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2 webGLattr: { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2
alpha: false, alpha: false,
antialias: false, antialias: false,
@ -42,7 +42,7 @@ function extensions(): void {
* *
* @returns void * @returns void
*/ */
export async function register(instance: Human): Promise<void> { export function register(instance: Human): void {
// force backend reload if gl context is not valid // force backend reload if gl context is not valid
if (instance.config.backend !== 'humangl') return; if (instance.config.backend !== 'humangl') return;
if ((config.name in tf.engine().registry) && (!config.gl || !config.gl.getParameter(config.gl.VERSION))) { if ((config.name in tf.engine().registry) && (!config.gl || !config.gl.getParameter(config.gl.VERSION))) {
@ -56,7 +56,7 @@ export async function register(instance: Human): Promise<void> {
} }
if (!tf.findBackend(config.name)) { if (!tf.findBackend(config.name)) {
try { try {
config.canvas = await image.canvas(100, 100); config.canvas = image.canvas(100, 100);
} catch (err) { } catch (err) {
log('error: cannot create canvas:', err); log('error: cannot create canvas:', err);
return; return;
@ -74,7 +74,7 @@ export async function register(instance: Human): Promise<void> {
return; return;
} }
if (config.canvas) { if (config.canvas) {
config.canvas.addEventListener('webglcontextlost', async (e) => { config.canvas.addEventListener('webglcontextlost', (e) => {
log('error: humangl:', e.type); log('error: humangl:', e.type);
log('possible browser memory leak using webgl or conflict with multiple backend registrations'); log('possible browser memory leak using webgl or conflict with multiple backend registrations');
instance.emit('error'); instance.emit('error');
@ -121,7 +121,7 @@ export async function register(instance: Human): Promise<void> {
} }
const current = tf.backend().getGPGPUContext ? tf.backend().getGPGPUContext().gl : null; const current = tf.backend().getGPGPUContext ? tf.backend().getGPGPUContext().gl : null;
if (current) { if (current) {
log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`); log(`humangl webgl version:${current.getParameter(current.VERSION) as string} renderer:${current.getParameter(current.RENDERER) as string}`);
} else { } else {
log('error: no current gl context:', current, config.gl); log('error: no current gl context:', current, config.gl);
return; return;

View File

@ -23,7 +23,7 @@ export interface ModelInfo {
export const modelStats: Record<string, ModelInfo> = {}; export const modelStats: Record<string, ModelInfo> = {};
async function httpHandler(url, init?): Promise<Response | null> { async function httpHandler(url: string, init?: RequestInit): Promise<Response | null> {
if (options.debug) log('load model fetch:', url, init); if (options.debug) log('load model fetch:', url, init);
return fetch(url, init); return fetch(url, init);
} }
@ -55,7 +55,7 @@ export async function loadModel(modelPath: string | undefined): Promise<GraphMod
options.cacheSupported = false; options.cacheSupported = false;
} }
modelStats[shortModelName].inCache = (options.cacheSupported && options.cacheModels) && Object.keys(cachedModels).includes(cachedModelName); // is model found in cache modelStats[shortModelName].inCache = (options.cacheSupported && options.cacheModels) && Object.keys(cachedModels).includes(cachedModelName); // is model found in cache
const tfLoadOptions = typeof fetch === 'undefined' ? {} : { fetchFunc: (url, init?) => httpHandler(url, init) }; const tfLoadOptions = typeof fetch === 'undefined' ? {} : { fetchFunc: (url: string, init?: RequestInit) => httpHandler(url, init) };
const model: GraphModel = new tf.GraphModel(modelStats[shortModelName].inCache ? cachedModelName : modelUrl, tfLoadOptions) as unknown as GraphModel; // create model prototype and decide if load from cache or from original modelurl const model: GraphModel = new tf.GraphModel(modelStats[shortModelName].inCache ? cachedModelName : modelUrl, tfLoadOptions) as unknown as GraphModel; // create model prototype and decide if load from cache or from original modelurl
let loaded = false; let loaded = false;
try { try {
@ -81,6 +81,6 @@ export async function loadModel(modelPath: string | undefined): Promise<GraphMod
log('error saving model:', modelUrl, err); log('error saving model:', modelUrl, err);
} }
} }
validateModel(null, model, `${modelPath}`); validateModel(null, model, `${modelPath || ''}`);
return model; return model;
} }

View File

@ -97,9 +97,9 @@ export class Env {
this.worker = this.browser && this.offscreen ? (typeof WorkerGlobalScope !== 'undefined') : undefined; this.worker = this.browser && this.offscreen ? (typeof WorkerGlobalScope !== 'undefined') : undefined;
if (typeof navigator !== 'undefined') { if (typeof navigator !== 'undefined') {
const raw = navigator.userAgent.match(/\(([^()]+)\)/g); const raw = navigator.userAgent.match(/\(([^()]+)\)/g);
if (raw && raw[0]) { if (raw?.[0]) {
const platformMatch = raw[0].match(/\(([^()]+)\)/g); const platformMatch = raw[0].match(/\(([^()]+)\)/g);
this.platform = (platformMatch && platformMatch[0]) ? platformMatch[0].replace(/\(|\)/g, '') : ''; this.platform = (platformMatch?.[0]) ? platformMatch[0].replace(/\(|\)/g, '') : '';
this.agent = navigator.userAgent.replace(raw[0], ''); this.agent = navigator.userAgent.replace(raw[0], '');
if (this.platform[1]) this.agent = this.agent.replace(raw[1], ''); if (this.platform[1]) this.agent = this.agent.replace(raw[1], '');
this.agent = this.agent.replace(/ /g, ' '); this.agent = this.agent.replace(/ /g, ' ');
@ -156,7 +156,7 @@ export class Env {
this.webgpu.supported = false; this.webgpu.supported = false;
} }
try { try {
this.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => kernel.kernelName.toLowerCase()); this.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => (kernel.kernelName as string).toLowerCase());
} catch { /**/ } } catch { /**/ }
} }

View File

@ -2,7 +2,7 @@
* Results interpolation for smoothening of video detection results inbetween detected frames * Results interpolation for smoothening of video detection results inbetween detected frames
*/ */
import type { Result, FaceResult, BodyResult, HandResult, ObjectResult, GestureResult, PersonResult, Box, Point, BodyLandmark, BodyAnnotation } from '../result'; import type { Result, FaceResult, BodyResult, HandResult, ObjectResult, PersonResult, Box, Point, BodyLandmark, BodyAnnotation } from '../result';
import type { Config } from '../config'; import type { Config } from '../config';
import * as moveNetCoords from '../body/movenetcoords'; import * as moveNetCoords from '../body/movenetcoords';
@ -103,7 +103,7 @@ export function calc(newResult: Result, config: Config): Result {
annotations = bufferedResult.hand[i].annotations; annotations = bufferedResult.hand[i].annotations;
} else if (newResult.hand[i].annotations) { } else if (newResult.hand[i].annotations) {
for (const key of Object.keys(newResult.hand[i].annotations)) { // update annotations for (const key of Object.keys(newResult.hand[i].annotations)) { // update annotations
annotations[key] = newResult.hand[i].annotations[key] && newResult.hand[i].annotations[key][0] annotations[key] = newResult.hand[i]?.annotations?.[key]?.[0]
? newResult.hand[i].annotations[key] ? newResult.hand[i].annotations[key]
.map((val, j: number) => val .map((val, j: number) => val
.map((coord: number, k: number) => ((bufferedFactor - 1) * bufferedResult.hand[i].annotations[key][j][k] + coord) / bufferedFactor)) .map((coord: number, k: number) => ((bufferedFactor - 1) * bufferedResult.hand[i].annotations[key][j][k] + coord) / bufferedFactor))
@ -173,7 +173,7 @@ export function calc(newResult: Result, config: Config): Result {
} }
// just copy latest gestures without interpolation // just copy latest gestures without interpolation
if (newResult.gesture) bufferedResult.gesture = newResult.gesture as GestureResult[]; if (newResult.gesture) bufferedResult.gesture = newResult.gesture;
// append interpolation performance data // append interpolation performance data
const t1 = now(); const t1 = now();

View File

@ -59,7 +59,7 @@ export function join(faces: FaceResult[], bodies: BodyResult[], hands: HandResul
person.box = [minX, minY, Math.max(...x) - minX, Math.max(...y) - minY]; // create new overarching box person.box = [minX, minY, Math.max(...x) - minX, Math.max(...y) - minY]; // create new overarching box
// shape is known so we calculate boxRaw as well // shape is known so we calculate boxRaw as well
if (shape && shape[1] && shape[2]) person.boxRaw = [person.box[0] / shape[2], person.box[1] / shape[1], person.box[2] / shape[2], person.box[3] / shape[1]]; if (shape?.[1] && shape?.[2]) person.boxRaw = [person.box[0] / shape[2], person.box[1] / shape[1], person.box[2] / shape[2], person.box[3] / shape[1]];
persons.push(person); persons.push(person);
} }

View File

@ -7,15 +7,15 @@ import { log } from './util';
export const data = {}; export const data = {};
export type ProfileData = { export interface ProfileData {
newBytes: number, newBytes: number,
peakBytes: number, peakBytes: number,
newTensors: number, newTensors: number,
kernels: Array<{ kernels: {
id: number, id: number,
kernelTimeMs: number, kernelTimeMs: number,
totalBytesSnapshot: number, totalBytesSnapshot: number,
}>, }[],
} }
export function run(modelName: string, profileData: ProfileData): void { // profileData is tfjs internal type export function run(modelName: string, profileData: ProfileData): void { // profileData is tfjs internal type

View File

@ -10,6 +10,7 @@ import { env } from './util/env';
import type { Config } from './config'; import type { Config } from './config';
import type { Result } from './result'; import type { Result } from './result';
import type { Human, Models } from './human'; import type { Human, Models } from './human';
import type { Tensor } from './exports';
async function warmupBitmap(instance: Human): Promise<Result | undefined> { async function warmupBitmap(instance: Human): Promise<Result | undefined> {
const b64toBlob = (base64: string, type = 'application/octet-stream') => fetch(`data:${type};base64,${base64}`).then((res) => res.blob()); const b64toBlob = (base64: string, type = 'application/octet-stream') => fetch(`data:${type};base64,${base64}`).then((res) => res.blob());
@ -76,10 +77,10 @@ async function warmupNode(instance: Human): Promise<Result | undefined> {
let img; let img;
if (instance.config.warmup === 'face') img = atob(sample.face); if (instance.config.warmup === 'face') img = atob(sample.face);
else img = atob(sample.body); else img = atob(sample.body);
let res; let res: Result;
if (('node' in tf) && (tf.getBackend() === 'tensorflow')) { if (('node' in tf) && (tf.getBackend() === 'tensorflow')) {
const data = tf['node'].decodeJpeg(img); // eslint-disable-line import/namespace const data: Tensor = tf['node'].decodeJpeg(img); // eslint-disable-line import/namespace
const expanded = data.expandDims(0); const expanded: Tensor = tf.expandDims(data, 0);
instance.tf.dispose(data); instance.tf.dispose(data);
// log('Input:', expanded); // log('Input:', expanded);
res = await instance.detect(expanded, instance.config); res = await instance.detect(expanded, instance.config);
@ -94,6 +95,7 @@ async function warmupNode(instance: Human): Promise<Result | undefined> {
res = await instance.detect(input, instance.config); res = await instance.detect(input, instance.config);
*/ */
} }
// @ts-ignore
return res; return res;
} }
@ -118,8 +120,8 @@ export async function runCompile(allModels: Models) {
const numTensorsStart = tf.engine().state.numTensors; const numTensorsStart = tf.engine().state.numTensors;
const compiledModels: string[] = []; const compiledModels: string[] = [];
for (const [modelName, model] of Object.entries(allModels).filter(([key, val]) => (key !== null && val !== null))) { for (const [modelName, model] of Object.entries(allModels).filter(([key, val]) => (key !== null && val !== null))) {
const shape = (model.inputs && model.inputs[0] && model.inputs[0].shape) ? [...model.inputs[0].shape] : [1, 64, 64, 3]; const shape = (model.inputs?.[0]?.shape) ? [...model.inputs[0].shape] : [1, 64, 64, 3];
const dtype = (model.inputs && model.inputs[0] && model.inputs[0].dtype) ? model.inputs[0].dtype : 'float32'; const dtype: string = (model.inputs?.[0]?.dtype) ? model.inputs[0].dtype : 'float32';
for (let dim = 0; dim < shape.length; dim++) { for (let dim = 0; dim < shape.length; dim++) {
if (shape[dim] === -1) shape[dim] = dim === 0 ? 1 : 64; // override batch number and any dynamic dimensions if (shape[dim] === -1) shape[dim] = dim === 0 ? 1 : 64; // override batch number and any dynamic dimensions
} }

View File

@ -1,39 +1,39 @@
2022-08-21 13:32:23 DATA:  Build {"name":"@vladmandic/human","version":"2.9.4"} 2022-08-21 15:21:09 DATA:  Build {"name":"@vladmandic/human","version":"2.9.4"}
2022-08-21 13:32:23 INFO:  Application: {"name":"@vladmandic/human","version":"2.9.4"} 2022-08-21 15:21:09 INFO:  Application: {"name":"@vladmandic/human","version":"2.9.4"}
2022-08-21 13:32:23 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true} 2022-08-21 15:21:09 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
2022-08-21 13:32:23 INFO:  Toolchain: {"build":"0.7.10","esbuild":"0.15.5","typescript":"4.7.4","typedoc":"0.23.10","eslint":"8.22.0"} 2022-08-21 15:21:09 INFO:  Toolchain: {"build":"0.7.10","esbuild":"0.15.5","typescript":"4.7.4","typedoc":"0.23.10","eslint":"8.22.0"}
2022-08-21 13:32:23 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]} 2022-08-21 15:21:09 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
2022-08-21 13:32:23 STATE: Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]} 2022-08-21 15:21:09 STATE: Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
2022-08-21 13:32:23 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":159,"outputBytes":608} 2022-08-21 15:21:09 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":159,"outputBytes":608}
2022-08-21 13:32:23 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":75,"inputBytes":652939,"outputBytes":306172} 2022-08-21 15:21:09 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":75,"inputBytes":653284,"outputBytes":306632}
2022-08-21 13:32:23 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":167,"outputBytes":612} 2022-08-21 15:21:09 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":167,"outputBytes":612}
2022-08-21 13:32:23 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":75,"inputBytes":652943,"outputBytes":306176} 2022-08-21 15:21:09 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":75,"inputBytes":653288,"outputBytes":306636}
2022-08-21 13:32:23 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":206,"outputBytes":664} 2022-08-21 15:21:09 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":206,"outputBytes":664}
2022-08-21 13:32:23 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":75,"inputBytes":652995,"outputBytes":306226} 2022-08-21 15:21:09 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":75,"inputBytes":653340,"outputBytes":306686}
2022-08-21 13:32:23 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1125,"outputBytes":358} 2022-08-21 15:21:09 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1125,"outputBytes":358}
2022-08-21 13:32:23 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1088,"outputBytes":583} 2022-08-21 15:21:09 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1088,"outputBytes":583}
2022-08-21 13:32:23 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":75,"inputBytes":652914,"outputBytes":305046} 2022-08-21 15:21:09 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":75,"inputBytes":653259,"outputBytes":305505}
2022-08-21 13:32:23 STATE: Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":11,"inputBytes":1344,"outputBytes":2787569} 2022-08-21 15:21:09 STATE: Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":11,"inputBytes":1344,"outputBytes":2787569}
2022-08-21 13:32:23 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":75,"inputBytes":3439900,"outputBytes":1667925} 2022-08-21 15:21:09 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":75,"inputBytes":3440245,"outputBytes":1668404}
2022-08-21 13:32:23 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":75,"inputBytes":3439900,"outputBytes":3070714} 2022-08-21 15:21:09 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":75,"inputBytes":3440245,"outputBytes":3071598}
2022-08-21 13:32:28 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":30} 2022-08-21 15:21:14 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":30}
2022-08-21 13:32:29 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true} 2022-08-21 15:21:16 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true}
2022-08-21 13:32:29 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6699,"outputBytes":3141} 2022-08-21 15:21:16 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6714,"outputBytes":3134}
2022-08-21 13:32:29 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15549,"outputBytes":7741} 2022-08-21 15:21:16 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15501,"outputBytes":7733}
2022-08-21 13:32:39 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":111,"errors":0,"warnings":0} 2022-08-21 15:21:27 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":111,"errors":0,"warnings":0}
2022-08-21 13:32:39 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"} 2022-08-21 15:21:27 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
2022-08-21 13:32:39 STATE: Copy: {"input":"tfjs/tfjs.esm.d.ts"} 2022-08-21 15:21:27 STATE: Copy: {"input":"tfjs/tfjs.esm.d.ts"}
2022-08-21 13:32:39 INFO:  Done... 2022-08-21 15:21:27 INFO:  Done...
2022-08-21 13:32:40 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":198} 2022-08-21 15:21:27 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":198}
2022-08-21 13:32:40 STATE: Copy: {"input":"types/human.d.ts"} 2022-08-21 15:21:27 STATE: Copy: {"input":"types/human.d.ts"}
2022-08-21 13:32:40 INFO:  Analyze models: {"folders":8,"result":"models/models.json"} 2022-08-21 15:21:27 INFO:  Analyze models: {"folders":8,"result":"models/models.json"}
2022-08-21 13:32:40 STATE: Models {"folder":"./models","models":13} 2022-08-21 15:21:27 STATE: Models {"folder":"./models","models":13}
2022-08-21 13:32:40 STATE: Models {"folder":"../human-models/models","models":42} 2022-08-21 15:21:27 STATE: Models {"folder":"../human-models/models","models":42}
2022-08-21 13:32:40 STATE: Models {"folder":"../blazepose/model/","models":4} 2022-08-21 15:21:27 STATE: Models {"folder":"../blazepose/model/","models":4}
2022-08-21 13:32:40 STATE: Models {"folder":"../anti-spoofing/model","models":1} 2022-08-21 15:21:27 STATE: Models {"folder":"../anti-spoofing/model","models":1}
2022-08-21 13:32:40 STATE: Models {"folder":"../efficientpose/models","models":3} 2022-08-21 15:21:27 STATE: Models {"folder":"../efficientpose/models","models":3}
2022-08-21 13:32:40 STATE: Models {"folder":"../insightface/models","models":5} 2022-08-21 15:21:27 STATE: Models {"folder":"../insightface/models","models":5}
2022-08-21 13:32:40 STATE: Models {"folder":"../movenet/models","models":3} 2022-08-21 15:21:27 STATE: Models {"folder":"../movenet/models","models":3}
2022-08-21 13:32:40 STATE: Models {"folder":"../nanodet/models","models":4} 2022-08-21 15:21:27 STATE: Models {"folder":"../nanodet/models","models":4}
2022-08-21 13:32:40 STATE: Models: {"count":57,"totalSize":383017442} 2022-08-21 15:21:28 STATE: Models: {"count":57,"totalSize":383017442}
2022-08-21 13:32:40 INFO:  Human Build complete... {"logFile":"test/build.log"} 2022-08-21 15:21:28 INFO:  Human Build complete... {"logFile":"test/build.log"}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@
<h1>Function canvas</h1></div> <h1>Function canvas</h1></div>
<section class="tsd-panel"> <section class="tsd-panel">
<ul class="tsd-signatures tsd-kind-function tsd-parent-kind-namespace"> <ul class="tsd-signatures tsd-kind-function tsd-parent-kind-namespace">
<li class="tsd-signature tsd-anchor-link" id="canvas">canvas<span class="tsd-signature-symbol">(</span>input<span class="tsd-signature-symbol">: </span><a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLImageElement</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLVideoElement</span>, output<span class="tsd-signature-symbol">: </span><a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span><a href="#canvas" aria-label="Permalink" class="tsd-anchor-icon"><svg class="icon icon-tabler icon-tabler-link" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none" id="icon-anchor-a"></path><path d="M10 14a3.5 3.5 0 0 0 5 0l4 -4a3.5 3.5 0 0 0 -5 -5l-.5 .5" id="icon-anchor-b"></path><path d="M14 10a3.5 3.5 0 0 0 -5 0l-4 4a3.5 3.5 0 0 0 5 5l.5 -.5" id="icon-anchor-c"></path></svg></a></li> <li class="tsd-signature tsd-anchor-link" id="canvas">canvas<span class="tsd-signature-symbol">(</span>input<span class="tsd-signature-symbol">: </span><a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLImageElement</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLVideoElement</span>, output<span class="tsd-signature-symbol">: </span><a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span><a href="#canvas" aria-label="Permalink" class="tsd-anchor-icon"><svg class="icon icon-tabler icon-tabler-link" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none" id="icon-anchor-a"></path><path d="M10 14a3.5 3.5 0 0 0 5 0l4 -4a3.5 3.5 0 0 0 -5 -5l-.5 .5" id="icon-anchor-b"></path><path d="M14 10a3.5 3.5 0 0 0 -5 0l-4 4a3.5 3.5 0 0 0 5 5l.5 -.5" id="icon-anchor-c"></path></svg></a></li>
<li class="tsd-description"> <li class="tsd-description">
<div class="tsd-comment tsd-typography"><p>draw processed canvas</p> <div class="tsd-comment tsd-typography"><p>draw processed canvas</p>
</div> </div>
@ -27,7 +27,7 @@
<h5>input: <a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLImageElement</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLVideoElement</span></h5></li> <h5>input: <a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLImageElement</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HTMLVideoElement</span></h5></li>
<li> <li>
<h5>output: <a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a></h5></li></ul></div> <h5>output: <a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a></h5></li></ul></div>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h4><aside class="tsd-sources"> <h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4><aside class="tsd-sources">
<ul> <ul>
<li>Defined in <a href="https://github.com/vladmandic/human/blob/main/src/draw/draw.ts#L55">src/draw/draw.ts:55</a></li></ul></aside></li></ul></section></div> <li>Defined in <a href="https://github.com/vladmandic/human/blob/main/src/draw/draw.ts#L55">src/draw/draw.ts:55</a></li></ul></aside></li></ul></section></div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight"> <div class="col-4 col-menu menu-sticky-wrap menu-highlight">

View File

@ -16,7 +16,7 @@
<h1>Function person</h1></div> <h1>Function person</h1></div>
<section class="tsd-panel"> <section class="tsd-panel">
<ul class="tsd-signatures tsd-kind-function tsd-parent-kind-namespace"> <ul class="tsd-signatures tsd-kind-function tsd-parent-kind-namespace">
<li class="tsd-signature tsd-anchor-link" id="person">person<span class="tsd-signature-symbol">(</span>inCanvas<span class="tsd-signature-symbol">: </span><a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a>, result<span class="tsd-signature-symbol">: </span><a href="../interfaces/PersonResult.html" class="tsd-signature-type" data-tsd-kind="Interface">PersonResult</a><span class="tsd-signature-symbol">[]</span>, drawOptions<span class="tsd-signature-symbol">?: </span><span class="tsd-signature-type">Partial</span><span class="tsd-signature-symbol">&lt;</span><a href="../interfaces/DrawOptions.html" class="tsd-signature-type" data-tsd-kind="Interface">DrawOptions</a><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span><a href="#person" aria-label="Permalink" class="tsd-anchor-icon"><svg class="icon icon-tabler icon-tabler-link" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none" id="icon-anchor-a"></path><path d="M10 14a3.5 3.5 0 0 0 5 0l4 -4a3.5 3.5 0 0 0 -5 -5l-.5 .5" id="icon-anchor-b"></path><path d="M14 10a3.5 3.5 0 0 0 -5 0l-4 4a3.5 3.5 0 0 0 5 5l.5 -.5" id="icon-anchor-c"></path></svg></a></li> <li class="tsd-signature tsd-anchor-link" id="person">person<span class="tsd-signature-symbol">(</span>inCanvas<span class="tsd-signature-symbol">: </span><a href="../types/AnyCanvas.html" class="tsd-signature-type" data-tsd-kind="Type alias">AnyCanvas</a>, result<span class="tsd-signature-symbol">: </span><a href="../interfaces/PersonResult.html" class="tsd-signature-type" data-tsd-kind="Interface">PersonResult</a><span class="tsd-signature-symbol">[]</span>, drawOptions<span class="tsd-signature-symbol">?: </span><span class="tsd-signature-type">Partial</span><span class="tsd-signature-symbol">&lt;</span><a href="../interfaces/DrawOptions.html" class="tsd-signature-type" data-tsd-kind="Interface">DrawOptions</a><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span><a href="#person" aria-label="Permalink" class="tsd-anchor-icon"><svg class="icon icon-tabler icon-tabler-link" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none" id="icon-anchor-a"></path><path d="M10 14a3.5 3.5 0 0 0 5 0l4 -4a3.5 3.5 0 0 0 -5 -5l-.5 .5" id="icon-anchor-b"></path><path d="M14 10a3.5 3.5 0 0 0 -5 0l-4 4a3.5 3.5 0 0 0 5 5l.5 -.5" id="icon-anchor-c"></path></svg></a></li>
<li class="tsd-description"> <li class="tsd-description">
<div class="tsd-comment tsd-typography"><p>draw combined person results instead of individual detection result objects</p> <div class="tsd-comment tsd-typography"><p>draw combined person results instead of individual detection result objects</p>
</div> </div>
@ -29,7 +29,7 @@
<h5>result: <a href="../interfaces/PersonResult.html" class="tsd-signature-type" data-tsd-kind="Interface">PersonResult</a><span class="tsd-signature-symbol">[]</span></h5></li> <h5>result: <a href="../interfaces/PersonResult.html" class="tsd-signature-type" data-tsd-kind="Interface">PersonResult</a><span class="tsd-signature-symbol">[]</span></h5></li>
<li> <li>
<h5><code class="tsd-tag ts-flagOptional">Optional</code> drawOptions: <span class="tsd-signature-type">Partial</span><span class="tsd-signature-symbol">&lt;</span><a href="../interfaces/DrawOptions.html" class="tsd-signature-type" data-tsd-kind="Interface">DrawOptions</a><span class="tsd-signature-symbol">&gt;</span></h5></li></ul></div> <h5><code class="tsd-tag ts-flagOptional">Optional</code> drawOptions: <span class="tsd-signature-type">Partial</span><span class="tsd-signature-symbol">&lt;</span><a href="../interfaces/DrawOptions.html" class="tsd-signature-type" data-tsd-kind="Interface">DrawOptions</a><span class="tsd-signature-symbol">&gt;</span></h5></li></ul></div>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h4><aside class="tsd-sources"> <h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4><aside class="tsd-sources">
<ul> <ul>
<li>Defined in <a href="https://github.com/vladmandic/human/blob/main/src/draw/draw.ts#L27">src/draw/draw.ts:27</a></li></ul></aside></li></ul></section></div> <li>Defined in <a href="https://github.com/vladmandic/human/blob/main/src/draw/draw.ts#L27">src/draw/draw.ts:27</a></li></ul></aside></li></ul></section></div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight"> <div class="col-4 col-menu menu-sticky-wrap menu-highlight">

14
types/human.d.ts vendored
View File

@ -28,7 +28,7 @@ declare interface ArrayMap {
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu']; export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */ /** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function body(inCanvas: AnyCanvas, result: BodyResult[], drawOptions?: Partial<DrawOptions>): void;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose; export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
@ -140,7 +140,7 @@ declare function browserFiles(files: File[]): IOHandler;
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler; declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */ /** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>; declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): void;
/** /**
* Concatenate a number of ArrayBuffers into one. * Concatenate a number of ArrayBuffers into one.
@ -509,7 +509,7 @@ export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' |
export declare type ExternalCanvas = typeof env.Canvas; export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */ /** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function face(inCanvas: AnyCanvas, result: FaceResult[], drawOptions?: Partial<DrawOptions>): void;
/** Anti-spoofing part of face configuration */ /** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig { export declare interface FaceAntiSpoofConfig extends GenericConfig {
@ -780,7 +780,7 @@ export declare interface GenericConfig {
} }
/** draw detected gestures */ /** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function gesture(inCanvas: AnyCanvas, result: GestureResult[], drawOptions?: Partial<DrawOptions>): void;
/** Controlls gesture detection */ /** Controlls gesture detection */
export declare interface GestureConfig { export declare interface GestureConfig {
@ -1038,7 +1038,7 @@ export declare class GraphModel<ModelURL extends Url = string | io.IOHandler> im
} }
/** draw detected hands */ /** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function hand(inCanvas: AnyCanvas, result: HandResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all hand detection specific options */ /** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig { export declare interface HandConfig extends GenericConfig {
@ -2022,7 +2022,7 @@ declare type NamedTensorsMap = {
declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64'; declare type NumericDataType = 'float32' | 'int32' | 'bool' | 'complex64';
/** draw detected objects */ /** draw detected objects */
declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function object(inCanvas: AnyCanvas, result: ObjectResult[], drawOptions?: Partial<DrawOptions>): void;
/** Configures all object detection specific options */ /** Configures all object detection specific options */
export declare interface ObjectConfig extends GenericConfig { export declare interface ObjectConfig extends GenericConfig {
@ -2065,7 +2065,7 @@ declare type OnProgressCallback = (fraction: number) => void;
declare const options: DrawOptions; declare const options: DrawOptions;
/** draw combined person results instead of individual detection result objects */ /** draw combined person results instead of individual detection result objects */
declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): Promise<void>; declare function person(inCanvas: AnyCanvas, result: PersonResult[], drawOptions?: Partial<DrawOptions>): void;
/** Person getter /** Person getter
* - Triggers combining all individual results into a virtual person object * - Triggers combining all individual results into a virtual person object