Skip to content

Commit

Permalink
add modelBasePath option
Browse files Browse the repository at this point in the history
  • Loading branch information
vladmandic committed Apr 9, 2021
1 parent 4b44d78 commit ea8a96a
Show file tree
Hide file tree
Showing 34 changed files with 820 additions and 774 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @vladmandic/human

Version: **1.3.5**
Version: **1.4.0**
Description: **Human: AI-powered 3D Face Detection, Face Description & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition**

Author: **Vladimir Mandic <[email protected]>**
Expand All @@ -9,6 +9,9 @@ Repository: **<git+https://github.com/vladmandic/human.git>**

## Changelog

### **HEAD -> main** 2021/04/08 [email protected]


### **1.3.5** 2021/04/06 [email protected]

- add dynamic viewport and fix web worker
Expand Down
4 changes: 2 additions & 2 deletions demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const userConfig = {
hand: { enabled: false },
gesture: { enabled: false },
body: { enabled: false },
// body: { enabled: true, modelPath: '../models/blazepose.json' },
// body: { enabled: true, modelPath: '../models/efficientpose.json' },
// body: { enabled: true, modelPath: 'blazepose.json' },
// body: { enabled: true, modelPath: 'efficientpose.json' },
object: { enabled: true },
};
*/
Expand Down
21 changes: 10 additions & 11 deletions demo/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,25 @@ let human = null;

const myConfig = {
backend: 'tensorflow',
modelBasePath: 'file://models/',
debug: true,
videoOptimized: false,
async: false,
face: {
enabled: true,
detector: { modelPath: 'file://models/blazeface-back.json', enabled: true, rotation: false },
mesh: { modelPath: 'file://models/facemesh.json', enabled: true },
iris: { modelPath: 'file://models/iris.json', enabled: true },
description: { modelPath: 'file://models/faceres.json', enabled: true },
emotion: { modelPath: 'file://models/emotion.json', enabled: true },
detector: { enabled: true, rotation: false },
mesh: { enabled: true },
iris: { enabled: true },
description: { enabled: true },
emotion: { enabled: true },
},
hand: {
enabled: true,
detector: { modelPath: 'file://models/handdetect.json' },
skeleton: { modelPath: 'file://models/handskeleton.json' },
},
// body: { modelPath: 'file://models/efficientpose.json', enabled: true },
// body: { modelPath: 'file://models/blazepose.json', enabled: true },
body: { modelPath: 'file://models/posenet.json', enabled: true },
object: { modelPath: 'file://models/nanodet.json', enabled: true },
// body: { modelPath: 'efficientpose.json', enabled: true },
// body: { modelPath: 'blazepose.json', enabled: true },
body: { enabled: true },
object: { enabled: true },
};

async function init() {
Expand Down
16 changes: 8 additions & 8 deletions dist/human.esm-nobundle.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/human.esm-nobundle.js.map

Large diffs are not rendered by default.

650 changes: 325 additions & 325 deletions dist/human.esm.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/human.esm.js.map

Large diffs are not rendered by default.

650 changes: 325 additions & 325 deletions dist/human.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/human.js.map

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions dist/human.node-gpu.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/human.node-gpu.js.map

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions dist/human.node.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/human.node.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vladmandic/human",
"version": "1.3.5",
"version": "1.4.0",
"description": "Human: AI-powered 3D Face Detection, Face Description & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",
"sideEffects": false,
"main": "dist/human.node.js",
Expand Down
2 changes: 1 addition & 1 deletion server/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ async function typedoc(entryPoint) {
async function build(f, msg, dev = false) {
if (busy) {
log.state('Build: busy...');
setTimeout(() => build(f, msg), 500);
setTimeout(() => build(f, msg, dev), 500);
return;
}
busy = true;
Expand Down
7 changes: 4 additions & 3 deletions src/age/age.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';

Expand All @@ -8,8 +8,9 @@ let skipped = Number.MAX_SAFE_INTEGER;

export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.face.age.modelPath);
if (config.debug) log(`load model: ${config.face.age.modelPath.match(/\/(.*)\./)[1]}`);
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.age.modelPath));
if (!model || !model.modelUrl) log('load model failed:', config.face.age.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
}
return model;
}
Expand Down
11 changes: 6 additions & 5 deletions src/blazeface/blazeface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';

const NUM_LANDMARKS = 6;
Expand Down Expand Up @@ -123,8 +123,9 @@ export class BlazeFaceModel {
}

export async function load(config) {
const blazeface = await tf.loadGraphModel(config.face.detector.modelPath, { fromTFHub: config.face.detector.modelPath.includes('tfhub.dev') });
const model = new BlazeFaceModel(blazeface, config);
if (config.debug) log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`);
return model;
const model = await tf.loadGraphModel(join(config.modelBasePath, config.face.detector.modelPath), { fromTFHub: config.face.detector.modelPath.includes('tfhub.dev') });
const blazeFace = new BlazeFaceModel(model, config);
if (!model || !model.modelUrl) log('load model failed:', config.face.detector.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
return blazeFace;
}
19 changes: 12 additions & 7 deletions src/blazeface/facemesh.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as blazeface from './blazeface';
import * as facepipeline from './facepipeline';
Expand Down Expand Up @@ -58,17 +58,22 @@ export class MediaPipeFaceMesh {
}
}

let faceModels = [null, null, null];
let faceModels:[any, any, any] = [null, null, null];
export async function load(config): Promise<MediaPipeFaceMesh> {
// @ts-ignore
faceModels = await Promise.all([
(!faceModels[0] && config.face.enabled) ? blazeface.load(config) : null,
(!faceModels[1] && config.face.mesh.enabled) ? tf.loadGraphModel(config.face.mesh.modelPath, { fromTFHub: config.face.mesh.modelPath.includes('tfhub.dev') }) : null,
(!faceModels[2] && config.face.iris.enabled) ? tf.loadGraphModel(config.face.iris.modelPath, { fromTFHub: config.face.iris.modelPath.includes('tfhub.dev') }) : null,
(!faceModels[1] && config.face.mesh.enabled) ? tf.loadGraphModel(join(config.modelBasePath, config.face.mesh.modelPath), { fromTFHub: config.face.mesh.modelPath.includes('tfhub.dev') }) : null,
(!faceModels[2] && config.face.iris.enabled) ? tf.loadGraphModel(join(config.modelBasePath, config.face.iris.modelPath), { fromTFHub: config.face.iris.modelPath.includes('tfhub.dev') }) : null,
]);
const faceMesh = new MediaPipeFaceMesh(faceModels[0], faceModels[1], faceModels[2], config);
if (config.face.mesh.enabled && 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.mesh.enabled) {
if (!faceModels[1] || !faceModels[1].modelUrl) log('load model failed:', config.face.age.modelPath);
else if (config.debug) log('load model:', faceModels[1].modelUrl);
}
if (config.face.iris.enabled) {
if (!faceModels[2] || !faceModels[1].modelUrl) log('load model failed:', config.face.age.modelPath);
else if (config.debug) log('load model:', faceModels[2].modelUrl);
}
return faceMesh;
}

Expand Down
7 changes: 4 additions & 3 deletions src/blazepose/blazepose.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';
import * as annotations from './annotations';
Expand All @@ -7,10 +7,11 @@ let model;

export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.body.modelPath);
model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath));
model.width = parseInt(model.signature.inputs['input_1:0'].tensorShape.dim[2].size);
model.height = parseInt(model.signature.inputs['input_1:0'].tensorShape.dim[1].size);
if (config.debug) log(`load model: ${config.body.modelPath.match(/\/(.*)\./)[1]}`);
if (!model || !model.modelUrl) log('load model failed:', config.body.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
}
return model;
}
Expand Down
41 changes: 28 additions & 13 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface Config {
scoped: boolean,
videoOptimized: boolean,
warmup: string,
modelBasePath: string,
filter: {
enabled: boolean,
width: number,
Expand Down Expand Up @@ -125,6 +126,7 @@ const config: Config = {
// can be 'webgl', 'wasm', 'cpu', or 'humangl' which is a custom version of webgl
// leave as empty string to continue using default backend
// when backend is set outside of Human library
modelBasePath: '../models/', // base path for all models
wasmPath: '../assets/', // path for wasm binaries
// only used for backend: wasm
debug: true, // print additional status messages to console
Expand Down Expand Up @@ -185,7 +187,8 @@ const config: Config = {
// detector, mesh, iris, age, gender, emotion
// (note: module is not loaded until it is required)
detector: {
modelPath: '../models/blazeface-back.json',
modelPath: 'blazeface-back.json', // detector model
// can be either absolute path or relative to modelBasePath
rotation: false, // use best-guess rotated face image or just box with rotation as-is
// false means higher performance, but incorrect mesh mapping if face angle is above 20 degrees
// this parameter is not valid in nodejs
Expand All @@ -209,18 +212,21 @@ const config: Config = {

mesh: {
enabled: true,
modelPath: '../models/facemesh.json',
modelPath: 'facemesh.json', // facemesh model
// can be either absolute path or relative to modelBasePath
},

iris: {
enabled: true,
modelPath: '../models/iris.json',
modelPath: 'iris.json', // face iris model
// can be either absolute path or relative to modelBasePath
},

description: {
enabled: true, // to improve accuracy of face description extraction it is
// recommended to enable detector.rotation and mesh.enabled
modelPath: '../models/faceres.json',
modelPath: 'faceres.json', // face description model
// can be either absolute path or relative to modelBasePath
skipFrames: 31, // how many frames to go without re-running the detector
// only used for video inputs
},
Expand All @@ -229,33 +235,39 @@ const config: Config = {
enabled: true,
minConfidence: 0.1, // threshold for discarding a prediction
skipFrames: 32, // how many frames to go without re-running the detector
modelPath: '../models/emotion.json',
modelPath: 'emotion.json', // face emotion model
// can be either absolute path or relative to modelBasePath
},

age: {
enabled: false, // obsolete, replaced by description module
modelPath: '../models/age.json',
modelPath: 'age.json', // age model
// can be either absolute path or relative to modelBasePath
skipFrames: 33, // how many frames to go without re-running the detector
// only used for video inputs
},

gender: {
enabled: false, // obsolete, replaced by description module
minConfidence: 0.1, // threshold for discarding a prediction
modelPath: '../models/gender.json',
modelPath: 'gender.json', // gender model
// can be either absolute path or relative to modelBasePath
skipFrames: 34, // how many frames to go without re-running the detector
// only used for video inputs
},

embedding: {
enabled: false, // obsolete, replaced by description module
modelPath: '../models/mobileface.json',
},
modelPath: 'mobileface.json', // face descriptor model
// can be either absolute path or relative to modelBasePath
},
},

body: {
enabled: true,
modelPath: '../models/posenet.json', // can be 'posenet', 'blazepose' or 'efficientpose'
modelPath: 'posenet.json', // body model
// can be either absolute path or relative to modelBasePath
// can be 'posenet', 'blazepose' or 'efficientpose'
// 'blazepose' and 'efficientpose' are experimental
maxDetections: 10, // maximum number of people detected in the input
// should be set to the minimum number for performance
Expand Down Expand Up @@ -287,16 +299,19 @@ const config: Config = {
// should be set to the minimum number for performance
landmarks: true, // detect hand landmarks or just hand boundary box
detector: {
modelPath: '../models/handdetect.json',
modelPath: 'handdetect.json', // hand detector model
// can be either absolute path or relative to modelBasePath
},
skeleton: {
modelPath: '../models/handskeleton.json',
modelPath: 'handskeleton.json', // hand skeleton model
// can be either absolute path or relative to modelBasePath
},
},

object: {
enabled: false,
modelPath: '../models/nanodet.json',
modelPath: 'nanodet.json', // object detection model
// can be either absolute path or relative to modelBasePath
// 'nanodet' is experimental
minConfidence: 0.20, // threshold for discarding a prediction
iouThreshold: 0.40, // threshold for deciding whether boxes overlap too much
Expand Down
7 changes: 4 additions & 3 deletions src/efficientpose/efficientpose.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';

Expand All @@ -10,8 +10,9 @@ const bodyParts = ['head', 'neck', 'rightShoulder', 'rightElbow', 'rightWrist',

export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.body.modelPath);
if (config.debug) log(`load model: ${config.body.modelPath.match(/\/(.*)\./)[1]}`);
model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath));
if (!model || !model.modelUrl) log('load model failed:', config.body.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
}
return model;
}
Expand Down
7 changes: 4 additions & 3 deletions src/embedding/embedding.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';

Expand All @@ -8,8 +8,9 @@ let model;

export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.face.embedding.modelPath);
if (config.debug) log(`load model: ${config.face.embedding.modelPath.match(/\/(.*)\./)[1]}`);
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.embedding.modelPath));
if (!model || !model.modelUrl) log('load model failed:', config.face.embedding.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
}
return model;
}
Expand Down
7 changes: 4 additions & 3 deletions src/emotion/emotion.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';

Expand All @@ -12,8 +12,9 @@ const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when

export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.face.emotion.modelPath);
if (config.debug) log(`load model: ${config.face.emotion.modelPath.match(/\/(.*)\./)[1]}`);
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.emotion.modelPath));
if (!model || !model.modelUrl) log('load model failed:', config.face.emotion.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
}
return model;
}
Expand Down
7 changes: 4 additions & 3 deletions src/faceres/faceres.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';

Expand All @@ -11,8 +11,9 @@ type DB = Array<{ name: string, source: string, embedding: number[] }>;

export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.face.description.modelPath);
if (config.debug) log(`load model: ${config.face.description.modelPath.match(/\/(.*)\./)[1]}`);
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.description.modelPath));
if (!model || !model.modelUrl) log('load model failed:', config.face.description.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
}
return model;
}
Expand Down
7 changes: 4 additions & 3 deletions src/gender/gender.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '../helpers';
import { log, join } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';

Expand All @@ -12,9 +12,10 @@ const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when

export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.face.gender.modelPath);
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.gender.modelPath));
alternative = model.inputs[0].shape[3] === 1;
if (config.debug) log(`load model: ${config.face.gender.modelPath.match(/\/(.*)\./)[1]}`);
if (!model || !model.modelUrl) log('load model failed:', config.face.gender.modelPath);
else if (config.debug) log('load model:', model.modelUrl);
}
return model;
}
Expand Down
Loading

0 comments on commit ea8a96a

Please sign in to comment.