From 0e15a5e8462e0b816342a4a93a352f43e6c47826 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sun, 21 Mar 2021 07:49:55 -0400 Subject: [PATCH] refactor face classes --- CHANGELOG.md | 5 +- demo/embedding.js | 10 +- package.json | 2 +- src/age/age.ts | 2 +- src/emotion/emotion.ts | 2 +- src/faceall.ts | 159 ++++++++++++++++++++++++++ src/gender/gender.ts | 2 +- src/handpose/handpose.ts | 2 +- src/helpers.ts | 28 +++++ src/human.ts | 235 ++++++--------------------------------- src/image/image.ts | 2 +- src/nanodet/nanodet.ts | 2 +- src/profile.ts | 2 +- src/tfjs/backend.ts | 2 +- 14 files changed, 236 insertions(+), 219 deletions(-) create mode 100644 src/faceall.ts create mode 100644 src/helpers.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c6160488..df04e029 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # @vladmandic/human -Version: **1.1.9** +Version: **1.1.10** Description: **Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition** Author: **Vladimir Mandic ** @@ -9,8 +9,9 @@ Repository: **** ## Changelog -### **HEAD -> main** 2021/03/18 mandic00@live.com +### **1.1.10** 2021/03/18 mandic00@live.com +- cleanup - redefine tensor - enforce types - regen type declarations diff --git a/demo/embedding.js b/demo/embedding.js index c55e15ec..bfaec7d0 100644 --- a/demo/embedding.js +++ b/demo/embedding.js @@ -12,8 +12,8 @@ const userConfig = { mesh: { enabled: true }, embedding: { enabled: true }, iris: { enabled: false }, - age: { enabled: false }, - gender: { enabled: false }, + age: { enabled: true }, + gender: { enabled: true }, emotion: { enabled: false }, }, hand: { enabled: false }, @@ -87,6 +87,7 @@ function faces(index, res, fileName) { // mouse click on any face canvas triggers analysis canvas.addEventListener('click', (evt) => { log('Select:', 'Image:', evt.target.tag.sample, 'Face:', evt.target.tag.face, all[evt.target.tag.sample][evt.target.tag.face]); + log('Select:', 'Gender:', all[evt.target.tag.sample][evt.target.tag.face].gender); analyze(all[evt.target.tag.sample][evt.target.tag.face]); }); // if we actually got face image tensor, draw canvas with that face @@ -135,9 +136,10 @@ async function main() { let images = dir.filter((img) => (img.endsWith('.jpg') && img.includes('sample'))); // enumerate additional private test images in /private, not includded in git repository - res = await fetch('/private'); + res = await fetch('/private/err'); dir = (res && res.ok) ? await res.json() : []; - images = images.concat(dir.filter((img) => (img.endsWith('.jpg')))); + // images = images.concat(dir.filter((img) => (img.endsWith('.jpg')))); + images = dir.filter((img) => (img.endsWith('.jpg'))); // download and analyze all images log('Enumerated:', images.length, 'images'); diff --git a/package.json b/package.json index 05a58b12..54ff9064 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@vladmandic/pilogger": "^0.2.15", "chokidar": "^3.5.1", "dayjs": "^1.10.4", - "esbuild": "^0.9.3", + "esbuild": "^0.9.6", "eslint": "^7.22.0", "eslint-config-airbnb-base": "^14.2.1", "eslint-plugin-import": "^2.22.1", diff --git a/src/age/age.ts b/src/age/age.ts index 404b4fc4..4af5f39e 100644 --- a/src/age/age.ts +++ b/src/age/age.ts @@ -1,4 +1,4 @@ -import { log } from '../log'; +import { log } from '../helpers'; import * as tf from '../../dist/tfjs.esm.js'; import * as profile from '../profile'; diff --git a/src/emotion/emotion.ts b/src/emotion/emotion.ts index 5c0744da..064c60eb 100644 --- a/src/emotion/emotion.ts +++ b/src/emotion/emotion.ts @@ -1,4 +1,4 @@ -import { log } from '../log'; +import { log } from '../helpers'; import * as tf from '../../dist/tfjs.esm.js'; import * as profile from '../profile'; diff --git a/src/faceall.ts b/src/faceall.ts new file mode 100644 index 00000000..a35eaf79 --- /dev/null +++ b/src/faceall.ts @@ -0,0 +1,159 @@ +import { log, now } from './helpers'; +import * as tf from '../dist/tfjs.esm.js'; +import * as age from './age/age'; +import * as gender from './gender/gender'; +import * as emotion from './emotion/emotion'; +import * as embedding from './embedding/embedding'; + +type Tensor = typeof tf.Tensor; + +const calculateFaceAngle = (mesh): { roll: number | null, yaw: number | null, pitch: number | null } => { + if (!mesh || mesh.length < 300) return { roll: null, yaw: null, pitch: null }; + const radians = (a1, a2, b1, b2) => Math.atan2(b2 - a2, b1 - a1); + // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars + const degrees = (theta) => Math.abs(((theta * 180) / Math.PI) % 360); + const angle = { + // values are in radians in range of -pi/2 to pi/2 which is -90 to +90 degrees + // value of 0 means center + // roll is face lean left/right + roll: radians(mesh[33][0], mesh[33][1], mesh[263][0], mesh[263][1]), // looking at x,y of outside corners of leftEye and rightEye + // yaw is face turn left/right + yaw: radians(mesh[33][0], mesh[33][2], mesh[263][0], mesh[263][2]), // looking at x,z of outside corners of leftEye and rightEye + // pitch is face move up/down + pitch: radians(mesh[10][1], mesh[10][2], mesh[152][1], mesh[152][2]), // looking at y,z of top and bottom points of the face + }; + return angle; +}; + +export const detectFace = async (parent, input): Promise => { + // run facemesh, includes blazeface and iris + // eslint-disable-next-line no-async-promise-executor + let timeStamp; + let ageRes; + let genderRes; + let emotionRes; + let embeddingRes; + const faceRes: Array<{ + confidence: number, + boxConfidence: number, + faceConfidence: number, + box: [number, number, number, number], + mesh: Array<[number, number, number]> + meshRaw: Array<[number, number, number]> + boxRaw: [number, number, number, number], + annotations: Array<{ part: string, points: Array<[number, number, number]>[] }>, + age: number, + gender: string, + genderConfidence: number, + emotion: string, + embedding: number[], + iris: number, + angle: { roll: number | null, yaw: number | null, pitch: number | null }, + tensor: Tensor, + }> = []; + parent.state = 'run:face'; + timeStamp = now(); + const faces = await parent.models.face?.estimateFaces(input, parent.config); + parent.perf.face = Math.trunc(now() - timeStamp); + if (!faces) return []; + for (const face of faces) { + parent.analyze('Get Face'); + + // is something went wrong, skip the face + if (!face.image || face.image.isDisposedInternal) { + log('Face object is disposed:', face.image); + continue; + } + + const angle = calculateFaceAngle(face.mesh); + + // run age, inherits face from blazeface + parent.analyze('Start Age:'); + if (parent.config.async) { + ageRes = parent.config.face.age.enabled ? age.predict(face.image, parent.config) : {}; + } else { + parent.state = 'run:age'; + timeStamp = now(); + ageRes = parent.config.face.age.enabled ? await age.predict(face.image, parent.config) : {}; + parent.perf.age = Math.trunc(now() - timeStamp); + } + + // run gender, inherits face from blazeface + parent.analyze('Start Gender:'); + if (parent.config.async) { + genderRes = parent.config.face.gender.enabled ? gender.predict(face.image, parent.config) : {}; + } else { + parent.state = 'run:gender'; + timeStamp = now(); + genderRes = parent.config.face.gender.enabled ? await gender.predict(face.image, parent.config) : {}; + parent.perf.gender = Math.trunc(now() - timeStamp); + } + + // run emotion, inherits face from blazeface + parent.analyze('Start Emotion:'); + if (parent.config.async) { + emotionRes = parent.config.face.emotion.enabled ? emotion.predict(face.image, parent.config) : {}; + } else { + parent.state = 'run:emotion'; + timeStamp = now(); + emotionRes = parent.config.face.emotion.enabled ? await emotion.predict(face.image, parent.config) : {}; + parent.perf.emotion = Math.trunc(now() - timeStamp); + } + parent.analyze('End Emotion:'); + + // run emotion, inherits face from blazeface + parent.analyze('Start Embedding:'); + if (parent.config.async) { + embeddingRes = parent.config.face.embedding.enabled ? embedding.predict(face, parent.config) : []; + } else { + parent.state = 'run:embedding'; + timeStamp = now(); + embeddingRes = parent.config.face.embedding.enabled ? await embedding.predict(face, parent.config) : []; + parent.perf.embedding = Math.trunc(now() - timeStamp); + } + parent.analyze('End Emotion:'); + + // if async wait for results + if (parent.config.async) { + [ageRes, genderRes, emotionRes, embeddingRes] = await Promise.all([ageRes, genderRes, emotionRes, embeddingRes]); + } + + parent.analyze('Finish Face:'); + + // calculate iris distance + // iris: array[ center, left, top, right, bottom] + if (!parent.config.face.iris.enabled && face?.annotations?.leftEyeIris && face?.annotations?.rightEyeIris) { + delete face.annotations.leftEyeIris; + delete face.annotations.rightEyeIris; + } + const irisSize = (face.annotations?.leftEyeIris && face.annotations?.rightEyeIris) + /* average human iris size is 11.7mm */ + ? 11.7 * Math.max(Math.abs(face.annotations.leftEyeIris[3][0] - face.annotations.leftEyeIris[1][0]), Math.abs(face.annotations.rightEyeIris[4][1] - face.annotations.rightEyeIris[2][1])) + : 0; + + // combine results + faceRes.push({ + ...face, + age: ageRes.age, + gender: genderRes.gender, + genderConfidence: genderRes.confidence, + emotion: emotionRes, + embedding: embeddingRes, + iris: (irisSize !== 0) ? Math.trunc(irisSize) / 100 : 0, + angle, + tensor: parent.config.face.detector.return ? face.image?.squeeze() : null, + }); + // dispose original face tensor + face.image?.dispose(); + + parent.analyze('End Face'); + } + parent.analyze('End FaceMesh:'); + if (parent.config.async) { + if (parent.perf.face) delete parent.perf.face; + if (parent.perf.age) delete parent.perf.age; + if (parent.perf.gender) delete parent.perf.gender; + if (parent.perf.emotion) delete parent.perf.emotion; + } + return faceRes; +}; diff --git a/src/gender/gender.ts b/src/gender/gender.ts index 72733477..3d3caecb 100644 --- a/src/gender/gender.ts +++ b/src/gender/gender.ts @@ -1,4 +1,4 @@ -import { log } from '../log'; +import { log } from '../helpers'; import * as tf from '../../dist/tfjs.esm.js'; import * as profile from '../profile'; diff --git a/src/handpose/handpose.ts b/src/handpose/handpose.ts index 98ca38d0..13644d54 100644 --- a/src/handpose/handpose.ts +++ b/src/handpose/handpose.ts @@ -1,6 +1,6 @@ // https://storage.googleapis.com/tfjs-models/demos/handpose/index.html -import { log } from '../log'; +import { log } from '../helpers'; import * as tf from '../../dist/tfjs.esm.js'; import * as handdetector from './handdetector'; import * as handpipeline from './handpipeline'; diff --git a/src/helpers.ts b/src/helpers.ts new file mode 100644 index 00000000..f8a84902 --- /dev/null +++ b/src/helpers.ts @@ -0,0 +1,28 @@ +// helper function: wrapper around console output +export function log(...msg) { + const dt = new Date(); + const ts = `${dt.getHours().toString().padStart(2, '0')}:${dt.getMinutes().toString().padStart(2, '0')}:${dt.getSeconds().toString().padStart(2, '0')}.${dt.getMilliseconds().toString().padStart(3, '0')}`; + // eslint-disable-next-line no-console + if (msg) console.log(ts, 'Human:', ...msg); +} + +// helper function: gets elapsed time on both browser and nodejs +export const now = () => { + if (typeof performance !== 'undefined') return performance.now(); + return parseInt((Number(process.hrtime.bigint()) / 1000 / 1000).toString()); +}; + +// helper function: perform deep merge of multiple objects so it allows full inheriance with overrides +export function mergeDeep(...objects) { + const isObject = (obj) => obj && typeof obj === 'object'; + return objects.reduce((prev, obj) => { + Object.keys(obj || {}).forEach((key) => { + const pVal = prev[key]; + const oVal = obj[key]; + if (Array.isArray(pVal) && Array.isArray(oVal)) prev[key] = pVal.concat(...oVal); + else if (isObject(pVal) && isObject(oVal)) prev[key] = mergeDeep(pVal, oVal); + else prev[key] = oVal; + }); + return prev; + }, {}); +} diff --git a/src/human.ts b/src/human.ts index 01149742..de7903e7 100644 --- a/src/human.ts +++ b/src/human.ts @@ -1,7 +1,8 @@ -import { log } from './log'; +import { log, now, mergeDeep } from './helpers'; import * as sysinfo from './sysinfo'; import * as tf from '../dist/tfjs.esm.js'; import * as backend from './tfjs/backend'; +import * as faceall from './faceall'; import * as facemesh from './blazeface/facemesh'; import * as age from './age/age'; import * as gender from './gender/gender'; @@ -33,26 +34,6 @@ export type TensorFlow = typeof tf; /** Generic Model object type, holds instance of individual models */ type Model = Object; -// helper function: gets elapsed time on both browser and nodejs -const now = () => { - if (typeof performance !== 'undefined') return performance.now(); - return parseInt((Number(process.hrtime.bigint()) / 1000 / 1000).toString()); -}; - -// helper function: perform deep merge of multiple objects so it allows full inheriance with overrides -function mergeDeep(...objects) { - const isObject = (obj) => obj && typeof obj === 'object'; - return objects.reduce((prev, obj) => { - Object.keys(obj || {}).forEach((key) => { - const pVal = prev[key]; - const oVal = obj[key]; - if (Array.isArray(pVal) && Array.isArray(oVal)) prev[key] = pVal.concat(...oVal); - else if (isObject(pVal) && isObject(oVal)) prev[key] = mergeDeep(pVal, oVal); - else prev[key] = oVal; - }); - return prev; - }, {}); -} /** * **Human** library main class * @@ -101,7 +82,7 @@ export class Human { nanodet: typeof nanodet; }; sysinfo: { platform: string, agent: string }; - #perf: any; + perf: any; #numTensors: number; #analyzeMemoryLeaks: boolean; #checkSanity: boolean; @@ -118,7 +99,7 @@ export class Human { this.#analyzeMemoryLeaks = false; this.#checkSanity = false; this.#firstRun = true; - this.#perf = {}; + this.perf = {}; // object that contains all initialized models this.models = { face: null, @@ -156,7 +137,7 @@ export class Human { // helper function: measure tensor leak /** @hidden */ - #analyze = (...msg) => { + analyze = (...msg) => { if (!this.#analyzeMemoryLeaks) return; const current = this.tf.engine().state.numTensors; const previous = this.#numTensors; @@ -252,7 +233,7 @@ export class Human { } const current = Math.trunc(now() - timeStamp); - if (current > (this.#perf.load || 0)) this.#perf.load = current; + if (current > (this.perf.load || 0)) this.perf.load = current; } // check if backend needs initialization if it changed @@ -305,164 +286,10 @@ export class Human { if (this.config.debug) log(`gl version:${gl.getParameter(gl.VERSION)} renderer:${gl.getParameter(gl.RENDERER)}`); } await this.tf.ready(); - this.#perf.backend = Math.trunc(now() - timeStamp); + this.perf.backend = Math.trunc(now() - timeStamp); } } - /** @hidden */ - #calculateFaceAngle = (mesh): { roll: number | null, yaw: number | null, pitch: number | null } => { - if (!mesh || mesh.length < 300) return { roll: null, yaw: null, pitch: null }; - const radians = (a1, a2, b1, b2) => Math.atan2(b2 - a2, b1 - a1); - // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars - const degrees = (theta) => Math.abs(((theta * 180) / Math.PI) % 360); - const angle = { - // values are in radians in range of -pi/2 to pi/2 which is -90 to +90 degrees - // value of 0 means center - // roll is face lean left/right - roll: radians(mesh[33][0], mesh[33][1], mesh[263][0], mesh[263][1]), // looking at x,y of outside corners of leftEye and rightEye - // yaw is face turn left/right - yaw: radians(mesh[33][0], mesh[33][2], mesh[263][0], mesh[263][2]), // looking at x,z of outside corners of leftEye and rightEye - // pitch is face move up/down - pitch: radians(mesh[10][1], mesh[10][2], mesh[152][1], mesh[152][2]), // looking at y,z of top and bottom points of the face - }; - return angle; - } - - /** @hidden */ - #detectFace = async (input): Promise => { - // run facemesh, includes blazeface and iris - // eslint-disable-next-line no-async-promise-executor - let timeStamp; - let ageRes; - let genderRes; - let emotionRes; - let embeddingRes; - const faceRes: Array<{ - confidence: number, - boxConfidence: number, - faceConfidence: number, - box: [number, number, number, number], - mesh: Array<[number, number, number]> - meshRaw: Array<[number, number, number]> - boxRaw: [number, number, number, number], - annotations: Array<{ part: string, points: Array<[number, number, number]>[] }>, - age: number, - gender: string, - genderConfidence: number, - emotion: string, - embedding: number[], - iris: number, - angle: { roll: number | null, yaw: number | null, pitch: number | null }, - tensor: Tensor, - }> = []; - - this.state = 'run:face'; - timeStamp = now(); - const faces = await this.models.face?.estimateFaces(input, this.config); - this.#perf.face = Math.trunc(now() - timeStamp); - if (!faces) return []; - for (const face of faces) { - this.#analyze('Get Face'); - - // is something went wrong, skip the face - if (!face.image || face.image.isDisposedInternal) { - log('Face object is disposed:', face.image); - continue; - } - - const angle = this.#calculateFaceAngle(face.mesh); - - // run age, inherits face from blazeface - this.#analyze('Start Age:'); - if (this.config.async) { - ageRes = this.config.face.age.enabled ? age.predict(face.image, this.config) : {}; - } else { - this.state = 'run:age'; - timeStamp = now(); - ageRes = this.config.face.age.enabled ? await age.predict(face.image, this.config) : {}; - this.#perf.age = Math.trunc(now() - timeStamp); - } - - // run gender, inherits face from blazeface - this.#analyze('Start Gender:'); - if (this.config.async) { - genderRes = this.config.face.gender.enabled ? gender.predict(face.image, this.config) : {}; - } else { - this.state = 'run:gender'; - timeStamp = now(); - genderRes = this.config.face.gender.enabled ? await gender.predict(face.image, this.config) : {}; - this.#perf.gender = Math.trunc(now() - timeStamp); - } - - // run emotion, inherits face from blazeface - this.#analyze('Start Emotion:'); - if (this.config.async) { - emotionRes = this.config.face.emotion.enabled ? emotion.predict(face.image, this.config) : {}; - } else { - this.state = 'run:emotion'; - timeStamp = now(); - emotionRes = this.config.face.emotion.enabled ? await emotion.predict(face.image, this.config) : {}; - this.#perf.emotion = Math.trunc(now() - timeStamp); - } - this.#analyze('End Emotion:'); - - // run emotion, inherits face from blazeface - this.#analyze('Start Embedding:'); - if (this.config.async) { - embeddingRes = this.config.face.embedding.enabled ? embedding.predict(face, this.config) : []; - } else { - this.state = 'run:embedding'; - timeStamp = now(); - embeddingRes = this.config.face.embedding.enabled ? await embedding.predict(face, this.config) : []; - this.#perf.embedding = Math.trunc(now() - timeStamp); - } - this.#analyze('End Emotion:'); - - // if async wait for results - if (this.config.async) { - [ageRes, genderRes, emotionRes, embeddingRes] = await Promise.all([ageRes, genderRes, emotionRes, embeddingRes]); - } - - this.#analyze('Finish Face:'); - - // calculate iris distance - // iris: array[ center, left, top, right, bottom] - if (!this.config.face.iris.enabled && face?.annotations?.leftEyeIris && face?.annotations?.rightEyeIris) { - delete face.annotations.leftEyeIris; - delete face.annotations.rightEyeIris; - } - const irisSize = (face.annotations?.leftEyeIris && face.annotations?.rightEyeIris) - /* average human iris size is 11.7mm */ - ? 11.7 * Math.max(Math.abs(face.annotations.leftEyeIris[3][0] - face.annotations.leftEyeIris[1][0]), Math.abs(face.annotations.rightEyeIris[4][1] - face.annotations.rightEyeIris[2][1])) - : 0; - - // combine results - faceRes.push({ - ...face, - age: ageRes.age, - gender: genderRes.gender, - genderConfidence: genderRes.confidence, - emotion: emotionRes, - embedding: embeddingRes, - iris: (irisSize !== 0) ? Math.trunc(irisSize) / 100 : 0, - angle, - tensor: this.config.face.detector.return ? face.image?.squeeze() : null, - }); - // dispose original face tensor - face.image?.dispose(); - - this.#analyze('End Face'); - } - this.#analyze('End FaceMesh:'); - if (this.config.async) { - if (this.#perf.face) delete this.#perf.face; - if (this.#perf.age) delete this.#perf.age; - if (this.#perf.gender) delete this.#perf.gender; - if (this.#perf.emotion) delete this.#perf.emotion; - } - return faceRes; - } - // main detect function async detect(input: Input, userConfig: Config | Object = {}): Promise { // detection happens inside a promise @@ -490,7 +317,7 @@ export class Human { await this.load(); if (this.config.scoped) this.tf.engine().startScope(); - this.#analyze('Start Scope:'); + this.analyze('Start Scope:'); timeStamp = now(); const process = image.process(input, this.config); @@ -499,8 +326,8 @@ export class Human { resolve({ error: 'could not convert input to tensor' }); return; } - this.#perf.image = Math.trunc(now() - timeStamp); - this.#analyze('Get Image:'); + this.perf.image = Math.trunc(now() - timeStamp); + this.analyze('Get Image:'); // prepare where to store model results let bodyRes; @@ -510,55 +337,55 @@ export class Human { // run face detection followed by all models that rely on face bounding box: face mesh, age, gender, emotion if (this.config.async) { - faceRes = this.config.face.enabled ? this.#detectFace(process.tensor) : []; - if (this.#perf.face) delete this.#perf.face; + faceRes = this.config.face.enabled ? faceall.detectFace(this, process.tensor) : []; + if (this.perf.face) delete this.perf.face; } else { this.state = 'run:face'; timeStamp = now(); - faceRes = this.config.face.enabled ? await this.#detectFace(process.tensor) : []; - this.#perf.face = Math.trunc(now() - timeStamp); + faceRes = this.config.face.enabled ? await faceall.detectFace(this, process.tensor) : []; + this.perf.face = Math.trunc(now() - timeStamp); } // run body: can be posenet or blazepose - this.#analyze('Start Body:'); + this.analyze('Start Body:'); if (this.config.async) { if (this.config.body.modelPath.includes('posenet')) bodyRes = this.config.body.enabled ? this.models.posenet?.estimatePoses(process.tensor, this.config) : []; else bodyRes = this.config.body.enabled ? blazepose.predict(process.tensor, this.config) : []; - if (this.#perf.body) delete this.#perf.body; + if (this.perf.body) delete this.perf.body; } else { this.state = 'run:body'; timeStamp = now(); if (this.config.body.modelPath.includes('posenet')) bodyRes = this.config.body.enabled ? await this.models.posenet?.estimatePoses(process.tensor, this.config) : []; else bodyRes = this.config.body.enabled ? await blazepose.predict(process.tensor, this.config) : []; - this.#perf.body = Math.trunc(now() - timeStamp); + this.perf.body = Math.trunc(now() - timeStamp); } - this.#analyze('End Body:'); + this.analyze('End Body:'); // run handpose - this.#analyze('Start Hand:'); + this.analyze('Start Hand:'); if (this.config.async) { handRes = this.config.hand.enabled ? this.models.handpose?.estimateHands(process.tensor, this.config) : []; - if (this.#perf.hand) delete this.#perf.hand; + if (this.perf.hand) delete this.perf.hand; } else { this.state = 'run:hand'; timeStamp = now(); handRes = this.config.hand.enabled ? await this.models.handpose?.estimateHands(process.tensor, this.config) : []; - this.#perf.hand = Math.trunc(now() - timeStamp); + this.perf.hand = Math.trunc(now() - timeStamp); } - this.#analyze('End Hand:'); + this.analyze('End Hand:'); // run nanodet - this.#analyze('Start Object:'); + this.analyze('Start Object:'); if (this.config.async) { objectRes = this.config.object.enabled ? nanodet.predict(process.tensor, this.config) : []; - if (this.#perf.object) delete this.#perf.object; + if (this.perf.object) delete this.perf.object; } else { this.state = 'run:object'; timeStamp = now(); objectRes = this.config.object.enabled ? await nanodet.predict(process.tensor, this.config) : []; - this.#perf.object = Math.trunc(now() - timeStamp); + this.perf.object = Math.trunc(now() - timeStamp); } - this.#analyze('End Object:'); + this.analyze('End Object:'); // if async wait for results if (this.config.async) { @@ -567,18 +394,18 @@ export class Human { process.tensor.dispose(); if (this.config.scoped) this.tf.engine().endScope(); - this.#analyze('End Scope:'); + this.analyze('End Scope:'); let gestureRes = []; if (this.config.gesture.enabled) { timeStamp = now(); // @ts-ignore gestureRes = [...gesture.face(faceRes), ...gesture.body(bodyRes), ...gesture.hand(handRes), ...gesture.iris(faceRes)]; - if (!this.config.async) this.#perf.gesture = Math.trunc(now() - timeStamp); - else if (this.#perf.gesture) delete this.#perf.gesture; + if (!this.config.async) this.perf.gesture = Math.trunc(now() - timeStamp); + else if (this.perf.gesture) delete this.perf.gesture; } - this.#perf.total = Math.trunc(now() - timeStart); + this.perf.total = Math.trunc(now() - timeStart); this.state = 'idle'; const result = { face: faceRes, @@ -586,7 +413,7 @@ export class Human { hand: handRes, gesture: gestureRes, object: objectRes, - performance: this.#perf, + performance: this.perf, canvas: process.canvas, }; // log('Result:', result); diff --git a/src/image/image.ts b/src/image/image.ts index 288dae14..8ae7e3fb 100644 --- a/src/image/image.ts +++ b/src/image/image.ts @@ -1,6 +1,6 @@ // @ts-nocheck -import { log } from '../log'; +import { log } from '../helpers'; import * as tf from '../../dist/tfjs.esm.js'; import * as fxImage from './imagefx'; diff --git a/src/nanodet/nanodet.ts b/src/nanodet/nanodet.ts index aeb696b2..e272318b 100644 --- a/src/nanodet/nanodet.ts +++ b/src/nanodet/nanodet.ts @@ -1,4 +1,4 @@ -import { log } from '../log'; +import { log } from '../helpers'; import * as tf from '../../dist/tfjs.esm.js'; import * as profile from '../profile'; diff --git a/src/profile.ts b/src/profile.ts index 2e294e82..43080f30 100644 --- a/src/profile.ts +++ b/src/profile.ts @@ -1,4 +1,4 @@ -import { log } from './log'; +import { log } from './helpers'; export const data = {}; diff --git a/src/tfjs/backend.ts b/src/tfjs/backend.ts index 53b71410..aba6084f 100644 --- a/src/tfjs/backend.ts +++ b/src/tfjs/backend.ts @@ -1,4 +1,4 @@ -import { log } from '../log'; +import { log } from '../helpers'; import * as tf from '../../dist/tfjs.esm.js'; export const config = {