From f278424664aded08958ef8563f0ee65307ee472f Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 17 Nov 2022 14:53:48 -0500 Subject: [PATCH] default empty result --- CHANGELOG.md | 5 +- TODO.md | 12 +++-- src/face/match.ts | 2 +- src/human.ts | 11 ++--- src/result.ts | 2 +- src/util/interpolate.ts | 6 +-- src/warmup.ts | 4 +- test/build.log | 106 +++++++++++++++++++--------------------- 8 files changed, 72 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd107bae..d2283098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,8 @@ ### **HEAD -> main** 2022/11/17 mandic00@live.com - -### **origin/main** 2022/11/16 mandic00@live.com - +- refactor distance +- add basic anthropometry - added webcam id specification - include external typedefs - prepare external typedefs diff --git a/TODO.md b/TODO.md index be48b6a4..d3647035 100644 --- a/TODO.md +++ b/TODO.md @@ -59,6 +59,10 @@ Optimizations: - If `config.backend` is not set, Human will auto-select best backend based on device capabilities - Enhanced support for `webgpu` +- Reduce build dependencies + `Human` is now 30% smaller :) + As usual, `Human` has **zero** runtime dependencies, + all *devDependencies* are only to rebuild `Human` itself Features: - Add [draw label templates](https://github.com/vladmandic/human/wiki/Draw) @@ -73,15 +77,15 @@ Features: See `human.result.face[n].distance` Architecture: -- Reduce build dependencies - `Human` is now 30% smaller :) - As usual, `Human` has **zero** runtime dependencies, - all *devDependencies* are only to rebuild `Human` itself - Upgrade to **TFJS 4.0** with **strong typing** see [notes](https://github.com/vladmandic/human#typedefs) on how to use - `TypeDef` refactoring - Re-architect `human.models` namespace for better dynamic model handling Added additional methods `load`, `list`, `loaded`, `reset` +- Repack external typedefs + Removes all external typedef dependencies +- Refactor namespace exports + Better [TypeDoc specs](https://vladmandic.github.io/human/typedoc/index.html) - Add named export for improved bundler support when using non-default imports - Support for **NodeJS v19** - Upgrade to **TypeScript 4.9** diff --git a/src/face/match.ts b/src/face/match.ts index 1141145e..8df1dd16 100644 --- a/src/face/match.ts +++ b/src/face/match.ts @@ -54,7 +54,7 @@ export function similarity(descriptor1: Descriptor, descriptor2: Descriptor, opt * - `distance` calculated `distance` of given descriptor to the best match * - `similarity` calculated normalized `similarity` of given descriptor to the best match */ -export function match(descriptor: Descriptor, descriptors: Descriptor[], options: MatchOptions = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) { +export function find(descriptor: Descriptor, descriptors: Descriptor[], options: MatchOptions = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) { if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0) { // validate input return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 }; } diff --git a/src/human.ts b/src/human.ts index 2edfba27..ab4e29df 100644 --- a/src/human.ts +++ b/src/human.ts @@ -39,7 +39,7 @@ import * as selfie from './segmentation/selfie'; import * as warmups from './warmup'; // type definitions -import { Input, DrawOptions, Config, Result, FaceResult, HandResult, BodyResult, ObjectResult, GestureResult, AnyCanvas, emptyResult } from './exports'; +import { Input, Config, Result, FaceResult, HandResult, BodyResult, ObjectResult, GestureResult, AnyCanvas, empty } from './exports'; import type { Tensor, Tensor4D } from './tfjs/types'; // type exports export * from './exports'; @@ -85,7 +85,7 @@ export class Human { tf; /** Object containing environment information used for diagnostics */ - env: Env; + env: Env = env; /** Draw helper classes that can draw detected objects on canvas using specified draw * - canvas: draws input to canvas @@ -133,7 +133,6 @@ export class Human { * @param userConfig - user configuration object {@link Config} */ constructor(userConfig?: Partial) { - this.env = env; /* defaults.wasmPath = tf.version['tfjs-core'].includes('-') // custom build or official build ? 'https://vladmandic.github.io/tfjs/dist/' @@ -160,7 +159,7 @@ export class Human { this.models = new models.Models(this); // reexport draw methods draw.init(); - this.result = emptyResult(); + this.result = empty(); // export access to image processing this.process = { tensor: null, canvas: null }; // export raw access to underlying models @@ -394,7 +393,7 @@ export class Human { if (error) { log(error, input); this.emit('error'); - resolve(emptyResult(error)); + resolve(empty(error)); } const timeStart = now(); @@ -412,7 +411,7 @@ export class Human { if (!img.tensor) { if (this.config.debug) log('could not convert input to tensor'); this.emit('error'); - resolve(emptyResult('could not convert input to tensor')); + resolve(empty('could not convert input to tensor')); return; } this.emit('image'); diff --git a/src/result.ts b/src/result.ts index b00c2eaf..e65e56ce 100644 --- a/src/result.ts +++ b/src/result.ts @@ -231,4 +231,4 @@ export interface Result { height: number, } -export const emptyResult = (error: string | null = null): Result => ({ face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0, width: 0, height: 0, error }); +export const empty = (error: string | null = null): Result => ({ face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0, width: 0, height: 0, error }); diff --git a/src/util/interpolate.ts b/src/util/interpolate.ts index 4271736e..bb474b0d 100644 --- a/src/util/interpolate.ts +++ b/src/util/interpolate.ts @@ -2,7 +2,7 @@ * Results interpolation for smoothening of video detection results inbetween detected frames */ -import { Result, FaceResult, BodyResult, HandResult, ObjectResult, PersonResult, Box, Point, BodyLandmark, BodyAnnotation, emptyResult } from '../result'; +import { Result, FaceResult, BodyResult, HandResult, ObjectResult, PersonResult, Box, Point, BodyLandmark, BodyAnnotation, empty } from '../result'; import type { Config } from '../config'; import * as moveNetCoords from '../body/movenetcoords'; @@ -11,12 +11,12 @@ import * as efficientPoseCoords from '../body/efficientposecoords'; import { now } from './util'; import { env } from './env'; -const bufferedResult: Result = emptyResult(); +const bufferedResult: Result = empty(); let interpolateTime = 0; export function calc(newResult: Result, config: Config): Result { const t0 = now(); - if (!newResult) return emptyResult(); + if (!newResult) return empty(); // each record is only updated using deep clone when number of detected record changes, otherwise it will converge by itself // otherwise bufferedResult is a shallow clone of result plus updated local calculated values // thus mixing by-reference and by-value assignments to minimize memory operations diff --git a/src/warmup.ts b/src/warmup.ts index 69f61fd2..5cf8775d 100644 --- a/src/warmup.ts +++ b/src/warmup.ts @@ -8,7 +8,7 @@ import * as sample from './sample'; import * as image from './image/image'; import * as backend from './tfjs/backend'; import { env } from './util/env'; -import { emptyResult, Result } from './result'; +import { empty, Result } from './result'; import type { Config } from './config'; import type { Human } from './human'; import type { Tensor, DataType } from './tfjs/types'; @@ -158,7 +158,7 @@ export async function warmup(instance: Human, userConfig?: Partial): Pro instance.state = 'warmup'; if (userConfig) instance.config = mergeDeep(instance.config, userConfig) as Config; if (!instance.config.warmup || instance.config.warmup.length === 0 || instance.config.warmup === 'none') { - return emptyResult(); + return empty(); } return new Promise(async (resolve) => { await instance.models.load(); diff --git a/test/build.log b/test/build.log index 65ca6407..c6b76abd 100644 --- a/test/build.log +++ b/test/build.log @@ -1,56 +1,50 @@ -2022-11-17 14:37:08 DATA:  Build {"name":"@vladmandic/human","version":"3.0.0"} -2022-11-17 14:37:08 INFO:  Application: {"name":"@vladmandic/human","version":"3.0.0"} -2022-11-17 14:37:08 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true} -2022-11-17 14:37:08 INFO:  Toolchain: {"build":"0.7.14","esbuild":"0.15.14","typescript":"4.9.3","typedoc":"0.23.21","eslint":"8.27.0"} -2022-11-17 14:37:08 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]} -2022-11-17 14:37:08 STATE: Clean: {"locations":["dist/*","types/*","typedoc/*"]} -2022-11-17 14:37:08 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1289,"outputBytes":361} -2022-11-17 14:37:08 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":569,"outputBytes":924} -2022-11-17 14:37:08 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":80,"inputBytes":670179,"outputBytes":317460} -2022-11-17 14:37:08 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":577,"outputBytes":928} -2022-11-17 14:37:08 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":80,"inputBytes":670183,"outputBytes":317464} -2022-11-17 14:37:08 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":665,"outputBytes":1876} -2022-11-17 14:37:08 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":80,"inputBytes":671131,"outputBytes":317575} -2022-11-17 14:37:08 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1375,"outputBytes":670} -2022-11-17 14:37:08 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":80,"inputBytes":669925,"outputBytes":316039} -2022-11-17 14:37:08 STATE: Compile: {"name":"tfjs/browser/esm/bundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":10,"inputBytes":1375,"outputBytes":1144900} -2022-11-17 14:37:08 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":80,"inputBytes":1814155,"outputBytes":1457353} -2022-11-17 14:37:09 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":80,"inputBytes":1814155,"outputBytes":1914737} -2022-11-17 14:37:12 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":15} -2022-11-17 14:37:14 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true} -2022-11-17 14:37:14 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6135,"outputBytes":2913} -2022-11-17 14:37:14 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":17572,"outputBytes":9456} -2022-11-17 14:37:22 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":114,"errors":0,"warnings":1} -2022-11-17 14:37:22 WARN:  -/home/vlado/dev/human/src/human.ts - 42:17 warning 'DrawOptions' is defined but never used @typescript-eslint/no-unused-vars - -✖ 1 problem (0 errors, 1 warning) - -2022-11-17 14:37:22 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"} -2022-11-17 14:37:22 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs-core.d.ts","output":"types/tfjs-core.d.ts"} -2022-11-17 14:37:22 INFO:  Done... -2022-11-17 14:37:22 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs.d.ts","output":"types/tfjs.esm.d.ts"} -2022-11-17 14:37:22 STATE: Copy: {"input":"src/types/tsconfig.json","output":"types/tsconfig.json"} -2022-11-17 14:37:22 STATE: Copy: {"input":"src/types/eslint.json","output":"types/.eslintrc.json"} -2022-11-17 14:37:22 STATE: Copy: {"input":"src/types/tfjs.esm.d.ts","output":"dist/tfjs.esm.d.ts"} -2022-11-17 14:37:22 STATE: Filter: {"input":"types/tfjs-core.d.ts"} -2022-11-17 14:37:23 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":195} -2022-11-17 14:37:23 STATE: Filter: {"input":"types/human.d.ts"} -2022-11-17 14:37:23 STATE: Write: {"output":"dist/human.esm-nobundle.d.ts"} -2022-11-17 14:37:23 STATE: Write: {"output":"dist/human.esm.d.ts"} -2022-11-17 14:37:23 STATE: Write: {"output":"dist/human.d.ts"} -2022-11-17 14:37:23 STATE: Write: {"output":"dist/human.node-gpu.d.ts"} -2022-11-17 14:37:23 STATE: Write: {"output":"dist/human.node.d.ts"} -2022-11-17 14:37:23 STATE: Write: {"output":"dist/human.node-wasm.d.ts"} -2022-11-17 14:37:23 INFO:  Analyze models: {"folders":8,"result":"models/models.json"} -2022-11-17 14:37:23 STATE: Models {"folder":"./models","models":12} -2022-11-17 14:37:23 STATE: Models {"folder":"../human-models/models","models":43} -2022-11-17 14:37:23 STATE: Models {"folder":"../blazepose/model/","models":4} -2022-11-17 14:37:23 STATE: Models {"folder":"../anti-spoofing/model","models":1} -2022-11-17 14:37:23 STATE: Models {"folder":"../efficientpose/models","models":3} -2022-11-17 14:37:23 STATE: Models {"folder":"../insightface/models","models":5} -2022-11-17 14:37:23 STATE: Models {"folder":"../movenet/models","models":3} -2022-11-17 14:37:23 STATE: Models {"folder":"../nanodet/models","models":4} -2022-11-17 14:37:24 STATE: Models: {"count":58,"totalSize":386543911} -2022-11-17 14:37:24 INFO:  Human Build complete... {"logFile":"test/build.log"} +2022-11-17 14:50:24 DATA:  Build {"name":"@vladmandic/human","version":"3.0.0"} +2022-11-17 14:50:24 INFO:  Application: {"name":"@vladmandic/human","version":"3.0.0"} +2022-11-17 14:50:24 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true} +2022-11-17 14:50:24 INFO:  Toolchain: {"build":"0.7.14","esbuild":"0.15.14","typescript":"4.9.3","typedoc":"0.23.21","eslint":"8.27.0"} +2022-11-17 14:50:24 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]} +2022-11-17 14:50:24 STATE: Clean: {"locations":["dist/*","types/*","typedoc/*"]} +2022-11-17 14:50:24 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1289,"outputBytes":361} +2022-11-17 14:50:24 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":569,"outputBytes":924} +2022-11-17 14:50:24 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":80,"inputBytes":670091,"outputBytes":317438} +2022-11-17 14:50:24 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":577,"outputBytes":928} +2022-11-17 14:50:24 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":80,"inputBytes":670095,"outputBytes":317442} +2022-11-17 14:50:24 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":665,"outputBytes":1876} +2022-11-17 14:50:24 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":80,"inputBytes":671043,"outputBytes":317553} +2022-11-17 14:50:24 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1375,"outputBytes":670} +2022-11-17 14:50:24 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":80,"inputBytes":669837,"outputBytes":316023} +2022-11-17 14:50:24 STATE: Compile: {"name":"tfjs/browser/esm/bundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":10,"inputBytes":1375,"outputBytes":1144900} +2022-11-17 14:50:25 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":80,"inputBytes":1814067,"outputBytes":1457337} +2022-11-17 14:50:25 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":80,"inputBytes":1814067,"outputBytes":1914669} +2022-11-17 14:50:28 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":15} +2022-11-17 14:50:30 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true} +2022-11-17 14:50:30 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6135,"outputBytes":2913} +2022-11-17 14:50:30 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":17572,"outputBytes":9456} +2022-11-17 14:50:38 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":114,"errors":0,"warnings":0} +2022-11-17 14:50:38 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"} +2022-11-17 14:50:38 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs-core.d.ts","output":"types/tfjs-core.d.ts"} +2022-11-17 14:50:38 INFO:  Done... +2022-11-17 14:50:38 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs.d.ts","output":"types/tfjs.esm.d.ts"} +2022-11-17 14:50:38 STATE: Copy: {"input":"src/types/tsconfig.json","output":"types/tsconfig.json"} +2022-11-17 14:50:38 STATE: Copy: {"input":"src/types/eslint.json","output":"types/.eslintrc.json"} +2022-11-17 14:50:38 STATE: Copy: {"input":"src/types/tfjs.esm.d.ts","output":"dist/tfjs.esm.d.ts"} +2022-11-17 14:50:38 STATE: Filter: {"input":"types/tfjs-core.d.ts"} +2022-11-17 14:50:39 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":195} +2022-11-17 14:50:39 STATE: Filter: {"input":"types/human.d.ts"} +2022-11-17 14:50:39 STATE: Write: {"output":"dist/human.esm-nobundle.d.ts"} +2022-11-17 14:50:39 STATE: Write: {"output":"dist/human.esm.d.ts"} +2022-11-17 14:50:39 STATE: Write: {"output":"dist/human.d.ts"} +2022-11-17 14:50:39 STATE: Write: {"output":"dist/human.node-gpu.d.ts"} +2022-11-17 14:50:39 STATE: Write: {"output":"dist/human.node.d.ts"} +2022-11-17 14:50:39 STATE: Write: {"output":"dist/human.node-wasm.d.ts"} +2022-11-17 14:50:39 INFO:  Analyze models: {"folders":8,"result":"models/models.json"} +2022-11-17 14:50:39 STATE: Models {"folder":"./models","models":12} +2022-11-17 14:50:39 STATE: Models {"folder":"../human-models/models","models":43} +2022-11-17 14:50:39 STATE: Models {"folder":"../blazepose/model/","models":4} +2022-11-17 14:50:39 STATE: Models {"folder":"../anti-spoofing/model","models":1} +2022-11-17 14:50:39 STATE: Models {"folder":"../efficientpose/models","models":3} +2022-11-17 14:50:39 STATE: Models {"folder":"../insightface/models","models":5} +2022-11-17 14:50:39 STATE: Models {"folder":"../movenet/models","models":3} +2022-11-17 14:50:39 STATE: Models {"folder":"../nanodet/models","models":4} +2022-11-17 14:50:40 STATE: Models: {"count":58,"totalSize":386543911} +2022-11-17 14:50:40 INFO:  Human Build complete... {"logFile":"test/build.log"}