mirror of https://github.com/vladmandic/human
added multi backend support
parent
9ae61216fb
commit
b4cccc3c76
58
README.md
58
README.md
|
@ -1,8 +1,10 @@
|
||||||
# Human: 3D Face Detection, Body Pose, Hand & Finger Tracking, Iris Tracking, Age & Gender Prediction & Emotion Prediction
|
# Human Library
|
||||||
|
|
||||||
|
## 3D Face Detection, Body Pose, Hand & Finger Tracking, Iris Tracking, Age & Gender Prediction & Emotion Prediction
|
||||||
|
|
||||||
- [**Documentation**](https://github.com/vladmandic/human#readme)
|
- [**Documentation**](https://github.com/vladmandic/human#readme)
|
||||||
- [**Code Repository**](https://github.com/vladmandic/human)
|
- [**Code Repository**](https://github.com/vladmandic/human)
|
||||||
- [**Package**](https://www.npmjs.com/package/@vladmandic/human)
|
- [**NPM Package**](https://www.npmjs.com/package/@vladmandic/human)
|
||||||
- [**Issues Tracker**](https://github.com/vladmandic/human/issues)
|
- [**Issues Tracker**](https://github.com/vladmandic/human/issues)
|
||||||
- [**Live Demo**](https://vladmandic.github.io/human/demo/demo-esm.html)
|
- [**Live Demo**](https://vladmandic.github.io/human/demo/demo-esm.html)
|
||||||
|
|
||||||
|
@ -30,6 +32,25 @@ Compatible with Browser, WebWorker and NodeJS execution!
|
||||||
|
|
||||||
There are multiple ways to use `Human` library, pick one that suits you:
|
There are multiple ways to use `Human` library, pick one that suits you:
|
||||||
|
|
||||||
|
### Included
|
||||||
|
|
||||||
|
- `dist/human.js`: IIFE format minified bundle with TFJS for Browsers
|
||||||
|
- `dist/human.esm.js`: ESM format minified bundle with TFJS for Browsers
|
||||||
|
- `dist/human.esm-nobundle.js`: ESM format non-minified bundle without TFJS for Browsers
|
||||||
|
- `dist/human.cjs`: CommonJS format minified bundle with TFJS for NodeJS
|
||||||
|
- `dist/human-nobundle.cjs`: CommonJS format non-minified bundle without TFJS for NodeJS
|
||||||
|
|
||||||
|
All versions include `sourcemap`
|
||||||
|
|
||||||
|
Defaults:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"main": "dist/human.cjs",
|
||||||
|
"module": "dist/human.esm.js",
|
||||||
|
"browser": "dist/human.esm.js",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### 1. [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) script
|
### 1. [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) script
|
||||||
|
|
||||||
*Simplest way for usage within Browser*
|
*Simplest way for usage within Browser*
|
||||||
|
@ -43,8 +64,6 @@ Simply download `dist/human.js`, include it in your `HTML` file & it's ready to
|
||||||
IIFE script auto-registers global namespace `human` within global `Window` object
|
IIFE script auto-registers global namespace `human` within global `Window` object
|
||||||
This way you can also use `Human` library within embbedded `<script>` tag within your `html` page for all-in-one approach
|
This way you can also use `Human` library within embbedded `<script>` tag within your `html` page for all-in-one approach
|
||||||
|
|
||||||
IIFE script is distributed in minified form with attached sourcemap
|
|
||||||
|
|
||||||
### 2. [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) module
|
### 2. [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) module
|
||||||
|
|
||||||
*Recommended for usage within `Browser`*
|
*Recommended for usage within `Browser`*
|
||||||
|
@ -53,18 +72,25 @@ IIFE script is distributed in minified form with attached sourcemap
|
||||||
|
|
||||||
If you're using bundler *(such as rollup, webpack, esbuild)* to package your client application, you can import ESM version of `Human` library which supports full tree shaking
|
If you're using bundler *(such as rollup, webpack, esbuild)* to package your client application, you can import ESM version of `Human` library which supports full tree shaking
|
||||||
|
|
||||||
|
Install with:
|
||||||
|
```shell
|
||||||
|
npm install @vladmandic/human
|
||||||
|
```
|
||||||
```js
|
```js
|
||||||
import human from '@vladmandic/human'; // points to @vladmandic/human/dist/human.esm.js
|
import human from '@vladmandic/human'; // points to @vladmandic/human/dist/human.esm.js
|
||||||
```
|
```
|
||||||
|
|
||||||
Or if you prefer to package your version of `tfjs`, you can use `nobundle` version
|
Or if you prefer to package your version of `tfjs`, you can use `nobundle` version
|
||||||
|
|
||||||
|
Install with:
|
||||||
|
```shell
|
||||||
|
npm install @vladmandic/human @tensorflow/tfjs-node
|
||||||
|
```
|
||||||
```js
|
```js
|
||||||
import tf from '@tensorflow/tfjs'
|
import tf from '@tensorflow/tfjs'
|
||||||
import human from '@vladmandic/human/dist/human.nobundle.js'; // same functionality as default import, but without tfjs bundled
|
import human from '@vladmandic/human/dist/human.esm-nobundle.js'; // same functionality as default import, but without tfjs bundled
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### 2.2 Using Script Module
|
#### 2.2 Using Script Module
|
||||||
You could use same syntax within your main `JS` file if it's imported with `<script type="module">`
|
You could use same syntax within your main `JS` file if it's imported with `<script type="module">`
|
||||||
|
|
||||||
|
@ -74,11 +100,10 @@ You could use same syntax within your main `JS` file if it's imported with `<scr
|
||||||
and then in your `index.js`
|
and then in your `index.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import human from 'dist/human.esm.js';
|
import * as tf from `https://cdnjs.cloudflare.com/ajax/libs/tensorflow/2.6.0/tf.es2017.min.js`; // load tfjs directly from CDN link
|
||||||
|
import human from 'dist/human.esm.js'; // for direct import must use path to module, not package name
|
||||||
```
|
```
|
||||||
|
|
||||||
ESM script is distributed in minified form with attached sourcemap
|
|
||||||
|
|
||||||
### 3. [NPM](https://www.npmjs.com/) module
|
### 3. [NPM](https://www.npmjs.com/) module
|
||||||
|
|
||||||
*Recommended for `NodeJS` projects that will execute in the backend*
|
*Recommended for `NodeJS` projects that will execute in the backend*
|
||||||
|
@ -88,13 +113,22 @@ You also need to install and include `tfjs-node` or `tfjs-node-gpu` in your proj
|
||||||
|
|
||||||
Install with:
|
Install with:
|
||||||
```shell
|
```shell
|
||||||
npm install @tensorflow/tfjs-node @vladmandic/human
|
npm install @vladmandic/human
|
||||||
```
|
```
|
||||||
And then use with:
|
And then use with:
|
||||||
```js
|
```js
|
||||||
const tf = require('@tensorflow/tfjs-node');
|
const human = require('@vladmandic/human'); // points to @vladmandic/human/dist/human.cjs
|
||||||
const human = require('@vladmandic/human'); // points to @vladmandic/human/dist/human.node.js
|
|
||||||
```
|
```
|
||||||
|
or
|
||||||
|
```shell
|
||||||
|
npm install @vladmandic/human @tensorflow/tfjs-node
|
||||||
|
```
|
||||||
|
And then use with:
|
||||||
|
```js
|
||||||
|
const tf = require('@tensorflow/tfjs-node'); // can also use '@tensorflow/tfjs-node-gpu' if you have environment with CUDA extensions
|
||||||
|
const human = require('@vladmandic/human/dist/human-nobundle.cjs');
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Since NodeJS projects load `weights` from local filesystem instead of using `http` calls, you must modify default configuration to include correct paths with `file://` prefix
|
Since NodeJS projects load `weights` from local filesystem instead of using `http` calls, you must modify default configuration to include correct paths with `file://` prefix
|
||||||
For example:
|
For example:
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,7 @@
|
||||||
<head>
|
<head>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/quicksettings"></script>
|
<script src="../assets/quicksettings.js"></script>
|
||||||
|
<script src="../assets/tf.min.js"></script>
|
||||||
|
<script src="../assets/tf-backend-wasm.min.js"></script>
|
||||||
<script src="./demo-esm.js" type="module"></script>
|
<script src="./demo-esm.js" type="module"></script>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin: 0; background: black; color: white; font-family: 'Segoe UI'; font-variant: small-caps">
|
<body style="margin: 0; background: black; color: white; font-family: 'Segoe UI'; font-variant: small-caps">
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
/* global QuickSettings */
|
/* global tf, QuickSettings */
|
||||||
|
|
||||||
import human from '../dist/human.esm.js';
|
import human from '../dist/human.esm.js';
|
||||||
|
|
||||||
const ui = {
|
const ui = {
|
||||||
|
backend: 'wasm',
|
||||||
baseColor: 'rgba(255, 200, 255, 0.3)',
|
baseColor: 'rgba(255, 200, 255, 0.3)',
|
||||||
baseLabel: 'rgba(255, 200, 255, 0.8)',
|
baseLabel: 'rgba(255, 200, 255, 0.8)',
|
||||||
baseFont: 'small-caps 1.2rem "Segoe UI"',
|
baseFont: 'small-caps 1.2rem "Segoe UI"',
|
||||||
|
@ -34,6 +35,15 @@ function str(...msg) {
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setupTF() {
|
||||||
|
if (ui.backend === 'wasm') {
|
||||||
|
tf.env().set('WASM_HAS_SIMD_SUPPORT', false);
|
||||||
|
tf.env().set('WASM_HAS_MULTITHREAD_SUPPORT', true);
|
||||||
|
}
|
||||||
|
await human.tf.setBackend(ui.backend);
|
||||||
|
await human.tf.ready();
|
||||||
|
}
|
||||||
|
|
||||||
async function drawFace(result, canvas) {
|
async function drawFace(result, canvas) {
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.strokeStyle = ui.baseColor;
|
ctx.strokeStyle = ui.baseColor;
|
||||||
|
@ -217,9 +227,10 @@ async function runHumanDetect(input, canvas) {
|
||||||
drawHand(result.hand, canvas);
|
drawHand(result.hand, canvas);
|
||||||
// update log
|
// update log
|
||||||
const engine = await human.tf.engine();
|
const engine = await human.tf.engine();
|
||||||
const memory = `Memory: ${engine.state.numBytes.toLocaleString()} bytes ${engine.state.numDataBuffers.toLocaleString()} buffers ${engine.state.numTensors.toLocaleString()} tensors`;
|
const memory = `${engine.state.numBytes.toLocaleString()} bytes ${engine.state.numDataBuffers.toLocaleString()} buffers ${engine.state.numTensors.toLocaleString()} tensors`;
|
||||||
|
const gpu = engine.backendInstance.numBytesInGPU ? `GPU: ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes` : '';
|
||||||
log.innerText = `
|
log.innerText = `
|
||||||
TFJS Version: ${human.tf.version_core} | ${memory} | GPU: ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes
|
TFJS Version: ${human.tf.version_core} | Backend: ${human.tf.getBackend()} | Memory: ${memory} ${gpu}
|
||||||
Performance: ${str(result.performance)} | Object size: ${(str(result)).length.toLocaleString()} bytes
|
Performance: ${str(result.performance)} | Object size: ${(str(result)).length.toLocaleString()} bytes
|
||||||
`;
|
`;
|
||||||
// rinse & repeate
|
// rinse & repeate
|
||||||
|
@ -255,6 +266,11 @@ function setupGUI() {
|
||||||
}
|
}
|
||||||
runHumanDetect(video, canvas);
|
runHumanDetect(video, canvas);
|
||||||
});
|
});
|
||||||
|
settings.addDropDown('Backend', ['webgl', 'wasm', 'cpu'], (val) => {
|
||||||
|
ui.backend = val.value;
|
||||||
|
setupTF();
|
||||||
|
});
|
||||||
|
settings.addHTML('title', 'Enabled Models'); settings.hideTitle('title');
|
||||||
settings.addBoolean('Face Detect', config.face.enabled, (val) => config.face.enabled = val);
|
settings.addBoolean('Face Detect', config.face.enabled, (val) => config.face.enabled = val);
|
||||||
settings.addBoolean('Face Mesh', config.face.mesh.enabled, (val) => config.face.mesh.enabled = val);
|
settings.addBoolean('Face Mesh', config.face.mesh.enabled, (val) => config.face.mesh.enabled = val);
|
||||||
settings.addBoolean('Face Iris', config.face.iris.enabled, (val) => config.face.iris.enabled = val);
|
settings.addBoolean('Face Iris', config.face.iris.enabled, (val) => config.face.iris.enabled = val);
|
||||||
|
@ -263,7 +279,7 @@ function setupGUI() {
|
||||||
settings.addBoolean('Face Emotion', config.face.emotion.enabled, (val) => config.face.emotion.enabled = val);
|
settings.addBoolean('Face Emotion', config.face.emotion.enabled, (val) => config.face.emotion.enabled = val);
|
||||||
settings.addBoolean('Body Pose', config.body.enabled, (val) => config.body.enabled = val);
|
settings.addBoolean('Body Pose', config.body.enabled, (val) => config.body.enabled = val);
|
||||||
settings.addBoolean('Hand Pose', config.hand.enabled, (val) => config.hand.enabled = val);
|
settings.addBoolean('Hand Pose', config.hand.enabled, (val) => config.hand.enabled = val);
|
||||||
settings.addHTML('line3', '<hr>'); settings.hideTitle('line3');
|
settings.addHTML('title', 'Model Parameters'); settings.hideTitle('title');
|
||||||
settings.addRange('Max Objects', 1, 20, 5, 1, (val) => {
|
settings.addRange('Max Objects', 1, 20, 5, 1, (val) => {
|
||||||
config.face.detector.maxFaces = parseInt(val);
|
config.face.detector.maxFaces = parseInt(val);
|
||||||
config.body.maxDetections = parseInt(val);
|
config.body.maxDetections = parseInt(val);
|
||||||
|
@ -288,7 +304,7 @@ function setupGUI() {
|
||||||
config.face.detector.iouThreshold = parseFloat(val);
|
config.face.detector.iouThreshold = parseFloat(val);
|
||||||
config.hand.iouThreshold = parseFloat(val);
|
config.hand.iouThreshold = parseFloat(val);
|
||||||
});
|
});
|
||||||
settings.addHTML('line1', '<hr>'); settings.hideTitle('line1');
|
settings.addHTML('title', 'UI Options'); settings.hideTitle('title');
|
||||||
settings.addBoolean('Draw Boxes', true);
|
settings.addBoolean('Draw Boxes', true);
|
||||||
settings.addBoolean('Draw Points', true);
|
settings.addBoolean('Draw Points', true);
|
||||||
settings.addBoolean('Draw Polygons', true);
|
settings.addBoolean('Draw Polygons', true);
|
||||||
|
@ -342,8 +358,7 @@ async function setupImage() {
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
// initialize tensorflow
|
// initialize tensorflow
|
||||||
await human.tf.setBackend('webgl');
|
await setupTF();
|
||||||
await human.tf.ready();
|
|
||||||
// setup ui control panel
|
// setup ui control panel
|
||||||
await setupGUI();
|
await setupGUI();
|
||||||
// setup webcam
|
// setup webcam
|
||||||
|
|
|
@ -5236,4 +5236,4 @@ exports.ssrnet = ssrnet;
|
||||||
exports.posenet = posenet;
|
exports.posenet = posenet;
|
||||||
exports.handpose = handpose;
|
exports.handpose = handpose;
|
||||||
exports.tf = tf;
|
exports.tf = tf;
|
||||||
//# sourceMappingURL=human.node.js.map
|
//# sourceMappingURL=human-nobundle.cjs.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
13
package.json
13
package.json
|
@ -3,9 +3,9 @@
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"description": "human: 3D Face Detection, Iris Tracking and Age & Gender Prediction",
|
"description": "human: 3D Face Detection, Iris Tracking and Age & Gender Prediction",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"main": "dist/human.node.js",
|
"main": "dist/human.cjs",
|
||||||
"module": "dist/human.esm.js",
|
"module": "dist/human.esm.js",
|
||||||
"browser": "dist/human.esmjs",
|
"browser": "dist/human.esm.js",
|
||||||
"author": "Vladimir Mandic <mandic00@live.com>",
|
"author": "Vladimir Mandic <mandic00@live.com>",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/vladmandic/human/issues"
|
"url": "https://github.com/vladmandic/human/issues"
|
||||||
|
@ -36,11 +36,12 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --trace-warnings --trace-uncaught --no-deprecation demo/demo-node.js",
|
"start": "node --trace-warnings --trace-uncaught --no-deprecation demo/demo-node.js",
|
||||||
"lint": "eslint src/*.js demo/*.js",
|
"lint": "eslint src/*.js demo/*.js",
|
||||||
"build": "rimraf dist/ && npm run build-iife && npm run build-esm && npm run build-nobundle && npm run build-node && ls -l dist/",
|
|
||||||
"build-iife": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=iife --minify --external:fs --global-name=human --outfile=dist/human.js src/index.js",
|
"build-iife": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=iife --minify --external:fs --global-name=human --outfile=dist/human.js src/index.js",
|
||||||
"build-esm": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --external:fs --outfile=dist/human.esm.js src/index.js",
|
"build-esm-bundle": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --external:fs --outfile=dist/human.esm.js src/index.js",
|
||||||
"build-nobundle": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --minify --external:@tensorflow --external:fs --outfile=dist/human.nobundle.js src/index.js",
|
"build-esm-nobundle": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --minify --external:@tensorflow --external:fs --outfile=dist/human.esm-nobundle.js src/index.js",
|
||||||
"build-node": "esbuild --bundle --platform=node --sourcemap --target=esnext --format=cjs --external:@tensorflow --outfile=dist/human.node.js src/index.js",
|
"build-node-bundle": "esbuild --bundle --platform=node --sourcemap --target=esnext --format=cjs --minify --outfile=dist/human.cjs src/index.js",
|
||||||
|
"build-node-nobundle": "esbuild --bundle --platform=node --sourcemap --target=esnext --format=cjs --external:@tensorflow --outfile=dist/human-nobundle.cjs src/index.js",
|
||||||
|
"build": "rimraf dist/* && npm run build-iife && npm run build-esm-bundle && npm run build-esm-nobundle && npm run build-node-bundle && npm run build-node-nobundle && ls -l dist/",
|
||||||
"update": "npm update --depth 20 && npm dedupe && npm prune && npm audit"
|
"update": "npm update --depth 20 && npm dedupe && npm prune && npm audit"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
Loading…
Reference in New Issue