convert blazeface to module

pull/280/head
Vladimir Mandic 2021-04-25 16:56:10 -04:00
parent 8678b4d57f
commit 88b646b283
9 changed files with 5950 additions and 11845 deletions

View File

@ -11,10 +11,16 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
### **HEAD -> main** 2021/04/25 mandic00@live.com ### **HEAD -> main** 2021/04/25 mandic00@live.com
- build nodejs deliverables in non-minified form
- stop building sourcemaps for nodejs deliverables
- remove deallocate, profile, scoped
- replaced maxfaces, maxdetections, maxhands, maxresults with maxdetected
- replaced nmsradius with built-in default
- unified minconfidence and scorethresdold as minconfidence
- add exception handlers to all demos
- remove blazeface-front and add unhandledrejection handler
- major update for 1.8 release candidate - major update for 1.8 release candidate
- enable webworker detection
### **origin/main** 2021/04/25 mandic00@live.com
### **1.7.1** 2021/04/25 mandic00@live.com ### **1.7.1** 2021/04/25 mandic00@live.com

View File

@ -6,8 +6,7 @@ N/A
## Exploring Features ## Exploring Features
- Implement built-in input handler for `http:`, `https:`, `file:` N/A
- Canvas.js for WASM on NodeJS
## Explore Models ## Explore Models

View File

@ -7,10 +7,9 @@ import Menu from './helpers/menu.js';
import GLBench from './helpers/gl-bench.js'; import GLBench from './helpers/gl-bench.js';
import webRTC from './helpers/webrtc.js'; import webRTC from './helpers/webrtc.js';
const userConfig = {}; // const userConfig = {};
let human; let human;
/*
const userConfig = { const userConfig = {
backend: 'humangl', backend: 'humangl',
async: false, async: false,
@ -21,7 +20,7 @@ const userConfig = {
enabled: false, enabled: false,
flip: false, flip: false,
}, },
face: { enabled: false, face: { enabled: true,
mesh: { enabled: true }, mesh: { enabled: true },
iris: { enabled: true }, iris: { enabled: true },
description: { enabled: false }, description: { enabled: false },
@ -29,11 +28,10 @@ const userConfig = {
}, },
hand: { enabled: false }, hand: { enabled: false },
gesture: { enabled: false }, gesture: { enabled: false },
body: { enabled: true, modelPath: 'posenet.json' }, body: { enabled: false, modelPath: 'posenet.json' },
// body: { enabled: true, modelPath: 'blazepose.json' }, // body: { enabled: true, modelPath: 'blazepose.json' },
// object: { enabled: true }, // object: { enabled: true },
}; };
*/
// ui options // ui options
const ui = { const ui = {

View File

@ -1,5 +1,6 @@
import { log, now } from './helpers'; import { log, now } from './helpers';
import * as tf from '../dist/tfjs.esm.js'; import * as tf from '../dist/tfjs.esm.js';
import * as facemesh from './blazeface/facemesh';
import * as emotion from './emotion/emotion'; import * as emotion from './emotion/emotion';
import * as faceres from './faceres/faceres'; import * as faceres from './faceres/faceres';
@ -130,7 +131,7 @@ export const detectFace = async (parent, input): Promise<any> => {
}> = []; }> = [];
parent.state = 'run:face'; parent.state = 'run:face';
timeStamp = now(); timeStamp = now();
const faces = await parent.models.face?.estimateFaces(input, parent.config); const faces = await facemesh.predict(input, parent.config);
parent.perf.face = Math.trunc(now() - timeStamp); parent.perf.face = Math.trunc(now() - timeStamp);
if (!faces) return []; if (!faces) return [];
for (const face of faces) { for (const face of faces) {

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
import * as tf from '../../dist/tfjs.esm.js'; import * as tf from '../../dist/tfjs.esm.js';
import * as box from './box'; import * as box from './box';
import * as anchors from './anchors';
export class HandDetector { export class HandDetector {
model: any; model: any;
@ -9,13 +10,13 @@ export class HandDetector {
inputSizeTensor: any; inputSizeTensor: any;
doubleInputSizeTensor: any; doubleInputSizeTensor: any;
constructor(model, inputSize, anchorsAnnotated) { constructor(model) {
this.model = model; this.model = model;
this.anchors = anchorsAnnotated.map((anchor) => [anchor.x_center, anchor.y_center]); this.anchors = anchors.anchors.map((anchor) => [anchor.x, anchor.y]);
this.anchorsTensor = tf.tensor2d(this.anchors); this.anchorsTensor = tf.tensor2d(this.anchors);
this.inputSize = inputSize; this.inputSize = this.model?.inputs[0].shape[2];
this.inputSizeTensor = tf.tensor1d([inputSize, inputSize]); this.inputSizeTensor = tf.tensor1d([this.inputSize, this.inputSize]);
this.doubleInputSizeTensor = tf.tensor1d([inputSize * 2, inputSize * 2]); this.doubleInputSizeTensor = tf.tensor1d([this.inputSize * 2, this.inputSize * 2]);
} }
normalizeBoxes(boxes) { normalizeBoxes(boxes) {

View File

@ -18,10 +18,10 @@ export class HandPipeline {
skipped: number; skipped: number;
detectedHands: number; detectedHands: number;
constructor(handDetector, landmarkDetector, inputSize) { constructor(handDetector, landmarkDetector) {
this.handDetector = handDetector; this.handDetector = handDetector;
this.landmarkDetector = landmarkDetector; this.landmarkDetector = landmarkDetector;
this.inputSize = inputSize; this.inputSize = this.landmarkDetector?.inputs[0].shape[2];
this.storedBoxes = []; this.storedBoxes = [];
this.skipped = 0; this.skipped = 0;
this.detectedHands = 0; this.detectedHands = 0;

View File

@ -2,9 +2,8 @@ import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js'; import * as tf from '../../dist/tfjs.esm.js';
import * as handdetector from './handdetector'; import * as handdetector from './handdetector';
import * as handpipeline from './handpipeline'; import * as handpipeline from './handpipeline';
import * as anchors from './anchors';
const MESH_ANNOTATIONS = { const meshAnnotations = {
thumb: [1, 2, 3, 4], thumb: [1, 2, 3, 4],
indexFinger: [5, 6, 7, 8], indexFinger: [5, 6, 7, 8],
middleFinger: [9, 10, 11, 12], middleFinger: [9, 10, 11, 12],
@ -13,26 +12,19 @@ const MESH_ANNOTATIONS = {
palmBase: [0], palmBase: [0],
}; };
export class HandPose { let handDetectorModel;
handPipeline: any; let handPoseModel;
let handPipeline;
constructor(handPipeline) { export async function predict(input, config) {
this.handPipeline = handPipeline; const predictions = await handPipeline.estimateHands(input, config);
}
static getAnnotations() {
return MESH_ANNOTATIONS;
}
async estimateHands(input, config) {
const predictions = await this.handPipeline.estimateHands(input, config);
if (!predictions) return []; if (!predictions) return [];
const hands: Array<{ confidence: number, box: any, boxRaw: any, landmarks: any, annotations: any }> = []; const hands: Array<{ confidence: number, box: any, boxRaw: any, landmarks: any, annotations: any }> = [];
for (const prediction of predictions) { for (const prediction of predictions) {
const annotations = {}; const annotations = {};
if (prediction.landmarks) { if (prediction.landmarks) {
for (const key of Object.keys(MESH_ANNOTATIONS)) { for (const key of Object.keys(meshAnnotations)) {
annotations[key] = MESH_ANNOTATIONS[key].map((index) => prediction.landmarks[index]); annotations[key] = meshAnnotations[key].map((index) => prediction.landmarks[index]);
} }
} }
const box = prediction.box ? [ const box = prediction.box ? [
@ -51,11 +43,8 @@ export class HandPose {
} }
return hands; return hands;
} }
}
let handDetectorModel; export async function load(config): Promise<[Object, Object]> {
let handPoseModel;
export async function load(config): Promise<HandPose> {
if (!handDetectorModel || !handPoseModel) { if (!handDetectorModel || !handPoseModel) {
[handDetectorModel, handPoseModel] = await Promise.all([ [handDetectorModel, handPoseModel] = await Promise.all([
config.hand.enabled ? tf.loadGraphModel(join(config.modelBasePath, config.hand.detector.modelPath), { fromTFHub: config.hand.detector.modelPath.includes('tfhub.dev') }) : null, config.hand.enabled ? tf.loadGraphModel(join(config.modelBasePath, config.hand.detector.modelPath), { fromTFHub: config.hand.detector.modelPath.includes('tfhub.dev') }) : null,
@ -71,8 +60,7 @@ export async function load(config): Promise<HandPose> {
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, handDetectorModel?.inputs[0].shape[2], anchors.anchors); const handDetector = new handdetector.HandDetector(handDetectorModel);
const handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel, handPoseModel?.inputs[0].shape[2]); handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel);
const handPose = new HandPose(handPipeline); return [handDetectorModel, handPoseModel];
return handPose;
} }

View File

@ -82,11 +82,11 @@ export class Human {
}; };
/** Internal: Currently loaded models */ /** Internal: Currently loaded models */
models: { models: {
face: facemesh.MediaPipeFaceMesh | Model | null, face: [Model, Model, Model] | null,
posenet: Model | null, posenet: Model | null,
blazepose: Model | null, blazepose: Model | null,
efficientpose: Model | null, efficientpose: Model | null,
handpose: handpose.HandPose | null, handpose: [Model, Model] | null,
iris: Model | null, iris: Model | null,
age: Model | null, age: Model | null,
gender: Model | null, gender: Model | null,
@ -431,12 +431,12 @@ export class Human {
// run handpose // run handpose
this.analyze('Start Hand:'); this.analyze('Start Hand:');
if (this.config.async) { if (this.config.async) {
handRes = this.config.hand.enabled ? this.models.handpose?.estimateHands(process.tensor, this.config) : []; handRes = this.config.hand.enabled ? handpose.predict(process.tensor, this.config) : [];
if (this.perf.hand) delete this.perf.hand; if (this.perf.hand) delete this.perf.hand;
} else { } else {
this.state = 'run:hand'; this.state = 'run:hand';
timeStamp = now(); timeStamp = now();
handRes = this.config.hand.enabled ? await this.models.handpose?.estimateHands(process.tensor, this.config) : []; handRes = this.config.hand.enabled ? await handpose.predict(process.tensor, this.config) : [];
current = Math.trunc(now() - timeStamp); current = Math.trunc(now() - timeStamp);
if (current > 0) this.perf.hand = current; if (current > 0) this.perf.hand = current;
} }