mirror of https://github.com/vladmandic/human
added wasm and webgpu backends
parent
5ae0cce05a
commit
254deb9c59
|
@ -9,7 +9,8 @@
|
||||||
- [**Change Log**](./CHANGELOG.md)
|
- [**Change Log**](./CHANGELOG.md)
|
||||||
- [**Live Demo**](https://vladmandic.github.io/human/demo/index.html)
|
- [**Live Demo**](https://vladmandic.github.io/human/demo/index.html)
|
||||||
|
|
||||||
Compatible with Browser, WebWorker and NodeJS execution!
|
Compatible with *Browser*, *WebWorker* and *NodeJS* execution
|
||||||
|
Compatible with *CPU*, *WebGL*, *WASM* and *WebGPU* backends
|
||||||
(and maybe with React-Native as it doesn't use any DOM objects)
|
(and maybe with React-Native as it doesn't use any DOM objects)
|
||||||
|
|
||||||
*This is a pre-release project, see [issues](https://github.com/vladmandic/human/issues) for list of known limitations and planned enhancements*
|
*This is a pre-release project, see [issues](https://github.com/vladmandic/human/issues) for list of known limitations and planned enhancements*
|
||||||
|
@ -159,10 +160,12 @@ If your application resides in a different folder, modify `modelPath` property i
|
||||||
|
|
||||||
Demos are included in `/demo`:
|
Demos are included in `/demo`:
|
||||||
|
|
||||||
Browser:
|
**Browser**:
|
||||||
- `index.html`, `browser.js`, `worker.js`: Full demo using Browser with ESM module, includes selectable backends and webworkers
|
- `index.html`, `browser.js`, `worker.js`: Full demo using Browser with ESM module, includes selectable backends and webworkers
|
||||||
|
|
||||||
NodeJS:
|
*If you want to test `wasm` or `webgpu` backends, enable loading in `index.html`*
|
||||||
|
|
||||||
|
**NodeJS**:
|
||||||
- `node.js`: Demo using NodeJS with CommonJS module
|
- `node.js`: Demo using NodeJS with CommonJS module
|
||||||
This is a very simple demo as althought `Human` library is compatible with NodeJS execution
|
This is a very simple demo as althought `Human` library is compatible with NodeJS execution
|
||||||
and is able to load images and models from local filesystem,
|
and is able to load images and models from local filesystem,
|
||||||
|
|
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
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.
|
@ -29,7 +29,8 @@ const ui = {
|
||||||
|
|
||||||
// configuration overrides
|
// configuration overrides
|
||||||
const config = {
|
const config = {
|
||||||
backend: 'webgl', // if you want to use 'wasm' backend, enable script load of tf and tf-backend-wasm in index.html
|
backend: 'webgl',
|
||||||
|
wasm: { path: '../assets' },
|
||||||
filter: {
|
filter: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
width: 0,
|
width: 0,
|
||||||
|
@ -108,7 +109,7 @@ function drawResults(input, result, canvas) {
|
||||||
// update log
|
// update log
|
||||||
const engine = human.tf.engine();
|
const engine = human.tf.engine();
|
||||||
const 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 ? `GPU: ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes` : '';
|
const gpu = engine.backendInstance ? `GPU: ${(engine.backendInstance.numBytesInGPU ? engine.backendInstance.numBytesInGPU : 0).toLocaleString()} bytes` : '';
|
||||||
document.getElementById('log').innerText = `
|
document.getElementById('log').innerText = `
|
||||||
TFJS Version: ${human.tf.version_core} | Backend: ${human.tf.getBackend()} | Memory: ${memory} ${gpu}
|
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
|
||||||
|
@ -267,6 +268,7 @@ function setupMenu() {
|
||||||
menu.addButton('Process Images', 'Process Images', () => detectSampleImages());
|
menu.addButton('Process Images', 'Process Images', () => detectSampleImages());
|
||||||
|
|
||||||
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
||||||
|
menu.addList('Backend', ['cpu', 'webgl', 'wasm', 'webgpu'], config.backend, (val) => config.backend = val);
|
||||||
menu.addBool('Use Web Worker', ui, 'useWorker');
|
menu.addBool('Use Web Worker', ui, 'useWorker');
|
||||||
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
||||||
menu.addLabel('Enabled Models');
|
menu.addLabel('Enabled Models');
|
||||||
|
|
|
@ -12,8 +12,9 @@
|
||||||
<meta name="msapplication-tooltip" content="Human: AI-powered 3D Human Detection">
|
<meta name="msapplication-tooltip" content="Human: AI-powered 3D Human Detection">
|
||||||
<link rel="manifest" href="../dist/human.esm.json">
|
<link rel="manifest" href="../dist/human.esm.json">
|
||||||
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
|
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
|
||||||
<!-- <script src="../assets/tf.min.js"></script> -->
|
<!-- <script src="../assets/tf.es2017.js"></script> -->
|
||||||
<!-- <script src="../assets/tf-backend-wasm.min.js"></script> -->
|
<!-- <script src="../assets/tf-backend-wasm.es2017.js"></script> -->
|
||||||
|
<!-- <script src="../assets/tf-backend-webgpu.js"></script> -->
|
||||||
<script src="./browser.js" type="module"></script>
|
<script src="./browser.js" type="module"></script>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin: 0; background: black; color: white; font-family: 'Segoe UI'; font-size: 16px; font-variant: small-caps; overflow-x: hidden">
|
<body style="margin: 0; background: black; color: white; font-family: 'Segoe UI'; font-size: 16px; font-variant: small-caps; overflow-x: hidden">
|
||||||
|
|
24
demo/menu.js
24
demo/menu.js
|
@ -8,9 +8,13 @@ const css = `
|
||||||
.menu-container-fadein { max-height: 100vh; overflow: hidden; transition: max-height, 0.5s ease; }
|
.menu-container-fadein { max-height: 100vh; overflow: hidden; transition: max-height, 0.5s ease; }
|
||||||
.menu-item { display: flex; white-space: nowrap; background: darkslategray; padding: 0.2rem; width: max-content; }
|
.menu-item { display: flex; white-space: nowrap; background: darkslategray; padding: 0.2rem; width: max-content; }
|
||||||
.menu-title { text-align: right; cursor: pointer; }
|
.menu-title { text-align: right; cursor: pointer; }
|
||||||
.menu-hr { margin: 0.2rem; border: 1px solid rgba(0, 0, 0, 0.5) }
|
.menu-hr { margin: 0.2rem; border: 1px solid rgba(0, 0, 0, 0.5); }
|
||||||
.menu-label { padding: 0; }
|
.menu-label { padding: 0; }
|
||||||
|
|
||||||
|
.menu-list { margin-right: 0.8rem; }
|
||||||
|
select:focus { outline: none; }
|
||||||
|
.menu-list-item { background: black; color: white; border: none; padding: 0.2rem; font-family: inherit; font-variant: inherit; border-radius: 1rem; }
|
||||||
|
|
||||||
.menu-chart-title { align-items: center; }
|
.menu-chart-title { align-items: center; }
|
||||||
.menu-chart-canvas { background: transparent; height: 40px; width: 180px; margin: 0.2rem 0.2rem 0.2rem 1rem; }
|
.menu-chart-canvas { background: transparent; height: 40px; width: 180px; margin: 0.2rem 0.2rem 0.2rem 1rem; }
|
||||||
|
|
||||||
|
@ -130,6 +134,24 @@ class Menu {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async addList(title, items, selected, callback) {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.className = 'menu-item';
|
||||||
|
let options = '';
|
||||||
|
for (const item of items) {
|
||||||
|
const def = item === selected ? 'selected' : '';
|
||||||
|
options += `<option value="${item}" ${def}>${item}</option>`;
|
||||||
|
}
|
||||||
|
el.innerHTML = `<div class="menu-list"><select name="${this.ID}" class="menu-list-item">${options}</select><label for="${this.ID}"></label></div>${title}`;
|
||||||
|
el.style.fontFamily = document.body.style.fontFamily;
|
||||||
|
el.style.fontSize = document.body.style.fontSize;
|
||||||
|
el.style.fontVariant = document.body.style.fontVariant;
|
||||||
|
this.container.appendChild(el);
|
||||||
|
el.addEventListener('change', (evt) => {
|
||||||
|
if (callback) callback(items[evt.target.selectedIndex]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async addRange(title, object, variable, min, max, step, callback) {
|
async addRange(title, object, variable, min, max, step, callback) {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'menu-item';
|
el.className = 'menu-item';
|
||||||
|
|
|
@ -5777,7 +5777,7 @@ var require_config = __commonJS((exports) => {
|
||||||
var require_package = __commonJS((exports, module) => {
|
var require_package = __commonJS((exports, module) => {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "@vladmandic/human",
|
name: "@vladmandic/human",
|
||||||
version: "0.4.10",
|
version: "0.5.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.node.js",
|
||||||
|
@ -5799,10 +5799,9 @@ var require_package = __commonJS((exports, module) => {
|
||||||
dependencies: {},
|
dependencies: {},
|
||||||
peerDependencies: {},
|
peerDependencies: {},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
seedrandom: "^3.0.5",
|
|
||||||
"@tensorflow/tfjs": "^2.7.0",
|
"@tensorflow/tfjs": "^2.7.0",
|
||||||
"@tensorflow/tfjs-node": "^2.7.0",
|
"@tensorflow/tfjs-node": "^2.7.0",
|
||||||
"@vladmandic/pilogger": "^0.2.6",
|
"@vladmandic/pilogger": "^0.2.7",
|
||||||
dayjs: "^1.9.4",
|
dayjs: "^1.9.4",
|
||||||
esbuild: "^0.7.22",
|
esbuild: "^0.7.22",
|
||||||
eslint: "^7.12.1",
|
eslint: "^7.12.1",
|
||||||
|
@ -5812,6 +5811,7 @@ var require_package = __commonJS((exports, module) => {
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
rimraf: "^3.0.2",
|
rimraf: "^3.0.2",
|
||||||
|
seedrandom: "^3.0.5",
|
||||||
"simple-git": "^2.21.0"
|
"simple-git": "^2.21.0"
|
||||||
},
|
},
|
||||||
scripts: {
|
scripts: {
|
||||||
|
@ -5958,17 +5958,33 @@ class Human {
|
||||||
this.models.emotion = await emotion.load(this.config);
|
this.models.emotion = await emotion.load(this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async resetBackend(backendName) {
|
||||||
|
if (tf.getBackend() !== this.config.backend) {
|
||||||
|
this.state = "backend";
|
||||||
|
if (backendName in tf.engine().registry) {
|
||||||
|
this.log("Human library setting backend:", this.config.backend);
|
||||||
|
this.config.backend = backendName;
|
||||||
|
const backendFactory = tf.findBackendFactory(backendName);
|
||||||
|
tf.removeBackend(backendName);
|
||||||
|
tf.registerBackend(backendName, backendFactory);
|
||||||
|
await tf.setBackend(backendName);
|
||||||
|
await tf.ready();
|
||||||
|
} else {
|
||||||
|
this.log("Human library backend not registred:", backendName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
tfImage(input) {
|
tfImage(input) {
|
||||||
let filtered;
|
let filtered;
|
||||||
|
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
||||||
|
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
||||||
|
let targetWidth = originalWidth;
|
||||||
|
let targetHeight = originalHeight;
|
||||||
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
||||||
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
|
||||||
let targetWidth = originalWidth;
|
|
||||||
if (this.config.filter.width > 0)
|
if (this.config.filter.width > 0)
|
||||||
targetWidth = this.config.filter.width;
|
targetWidth = this.config.filter.width;
|
||||||
else if (this.config.filter.height > 0)
|
else if (this.config.filter.height > 0)
|
||||||
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
||||||
let targetHeight = originalHeight;
|
|
||||||
if (this.config.filter.height > 0)
|
if (this.config.filter.height > 0)
|
||||||
targetHeight = this.config.filter.height;
|
targetHeight = this.config.filter.height;
|
||||||
else if (this.config.filter.width > 0)
|
else if (this.config.filter.width > 0)
|
||||||
|
@ -6015,7 +6031,19 @@ class Human {
|
||||||
if (input instanceof tf.Tensor) {
|
if (input instanceof tf.Tensor) {
|
||||||
tensor = tf.clone(input);
|
tensor = tf.clone(input);
|
||||||
} else {
|
} else {
|
||||||
const pixels = tf.browser.fromPixels(filtered || input);
|
const canvas = filtered || input;
|
||||||
|
let pixels;
|
||||||
|
if (this.config.backend === "webgl" || canvas instanceof ImageData)
|
||||||
|
pixels = tf.browser.fromPixels(canvas);
|
||||||
|
else {
|
||||||
|
const tempCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement("canvas");
|
||||||
|
tempCanvas.width = targetWidth;
|
||||||
|
tempCanvas.height = targetHeight;
|
||||||
|
const tempCtx = tempCanvas.getContext("2d");
|
||||||
|
tempCtx.drawImage(canvas, 0, 0);
|
||||||
|
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||||
|
pixels = tf.browser.fromPixels(data);
|
||||||
|
}
|
||||||
const casted = pixels.toFloat();
|
const casted = pixels.toFloat();
|
||||||
tensor = casted.expandDims(0);
|
tensor = casted.expandDims(0);
|
||||||
pixels.dispose();
|
pixels.dispose();
|
||||||
|
@ -6039,12 +6067,7 @@ class Human {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const timeStart = now();
|
const timeStart = now();
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
if (tf.getBackend() !== this.config.backend) {
|
await this.resetBackend(this.config.backend);
|
||||||
this.state = "backend";
|
|
||||||
this.log("Human library setting backend:", this.config.backend);
|
|
||||||
await tf.setBackend(this.config.backend);
|
|
||||||
await tf.ready();
|
|
||||||
}
|
|
||||||
perf.backend = Math.trunc(now() - timeStamp);
|
perf.backend = Math.trunc(now() - timeStamp);
|
||||||
if (first) {
|
if (first) {
|
||||||
this.log("Human library starting");
|
this.log("Human library starting");
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,7 +5,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytes": 2871,
|
"bytes": 2870,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/emotion/emotion.js": {
|
"src/emotion/emotion.js": {
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 11908,
|
"bytes": 13144,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/facemesh/facemesh.js"
|
"path": "src/facemesh/facemesh.js"
|
||||||
|
@ -260,7 +260,7 @@
|
||||||
"dist/human.esm-nobundle.js.map": {
|
"dist/human.esm-nobundle.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 248630
|
"bytes": 250346
|
||||||
},
|
},
|
||||||
"dist/human.esm-nobundle.js": {
|
"dist/human.esm-nobundle.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -353,16 +353,16 @@
|
||||||
"bytesInOutput": 2230
|
"bytesInOutput": 2230
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytesInOutput": 3013
|
"bytesInOutput": 3012
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 10775
|
"bytesInOutput": 11781
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 0
|
"bytesInOutput": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 155239
|
"bytes": 156244
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72826,7 +72826,7 @@ var require_config = __commonJS((exports) => {
|
||||||
var require_package = __commonJS((exports, module) => {
|
var require_package = __commonJS((exports, module) => {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "@vladmandic/human",
|
name: "@vladmandic/human",
|
||||||
version: "0.4.10",
|
version: "0.5.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.node.js",
|
||||||
|
@ -72848,10 +72848,9 @@ var require_package = __commonJS((exports, module) => {
|
||||||
dependencies: {},
|
dependencies: {},
|
||||||
peerDependencies: {},
|
peerDependencies: {},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
seedrandom: "^3.0.5",
|
|
||||||
"@tensorflow/tfjs": "^2.7.0",
|
"@tensorflow/tfjs": "^2.7.0",
|
||||||
"@tensorflow/tfjs-node": "^2.7.0",
|
"@tensorflow/tfjs-node": "^2.7.0",
|
||||||
"@vladmandic/pilogger": "^0.2.6",
|
"@vladmandic/pilogger": "^0.2.7",
|
||||||
dayjs: "^1.9.4",
|
dayjs: "^1.9.4",
|
||||||
esbuild: "^0.7.22",
|
esbuild: "^0.7.22",
|
||||||
eslint: "^7.12.1",
|
eslint: "^7.12.1",
|
||||||
|
@ -72861,6 +72860,7 @@ var require_package = __commonJS((exports, module) => {
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
rimraf: "^3.0.2",
|
rimraf: "^3.0.2",
|
||||||
|
seedrandom: "^3.0.5",
|
||||||
"simple-git": "^2.21.0"
|
"simple-git": "^2.21.0"
|
||||||
},
|
},
|
||||||
scripts: {
|
scripts: {
|
||||||
|
@ -73007,17 +73007,33 @@ class Human {
|
||||||
this.models.emotion = await emotion.load(this.config);
|
this.models.emotion = await emotion.load(this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async resetBackend(backendName) {
|
||||||
|
if (tf.getBackend() !== this.config.backend) {
|
||||||
|
this.state = "backend";
|
||||||
|
if (backendName in tf.engine().registry) {
|
||||||
|
this.log("Human library setting backend:", this.config.backend);
|
||||||
|
this.config.backend = backendName;
|
||||||
|
const backendFactory = tf.findBackendFactory(backendName);
|
||||||
|
tf.removeBackend(backendName);
|
||||||
|
tf.registerBackend(backendName, backendFactory);
|
||||||
|
await tf.setBackend(backendName);
|
||||||
|
await tf.ready();
|
||||||
|
} else {
|
||||||
|
this.log("Human library backend not registred:", backendName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
tfImage(input) {
|
tfImage(input) {
|
||||||
let filtered;
|
let filtered;
|
||||||
|
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
||||||
|
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
||||||
|
let targetWidth = originalWidth;
|
||||||
|
let targetHeight = originalHeight;
|
||||||
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
||||||
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
|
||||||
let targetWidth = originalWidth;
|
|
||||||
if (this.config.filter.width > 0)
|
if (this.config.filter.width > 0)
|
||||||
targetWidth = this.config.filter.width;
|
targetWidth = this.config.filter.width;
|
||||||
else if (this.config.filter.height > 0)
|
else if (this.config.filter.height > 0)
|
||||||
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
||||||
let targetHeight = originalHeight;
|
|
||||||
if (this.config.filter.height > 0)
|
if (this.config.filter.height > 0)
|
||||||
targetHeight = this.config.filter.height;
|
targetHeight = this.config.filter.height;
|
||||||
else if (this.config.filter.width > 0)
|
else if (this.config.filter.width > 0)
|
||||||
|
@ -73064,7 +73080,19 @@ class Human {
|
||||||
if (input instanceof tf.Tensor) {
|
if (input instanceof tf.Tensor) {
|
||||||
tensor = tf.clone(input);
|
tensor = tf.clone(input);
|
||||||
} else {
|
} else {
|
||||||
const pixels = tf.browser.fromPixels(filtered || input);
|
const canvas = filtered || input;
|
||||||
|
let pixels;
|
||||||
|
if (this.config.backend === "webgl" || canvas instanceof ImageData)
|
||||||
|
pixels = tf.browser.fromPixels(canvas);
|
||||||
|
else {
|
||||||
|
const tempCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement("canvas");
|
||||||
|
tempCanvas.width = targetWidth;
|
||||||
|
tempCanvas.height = targetHeight;
|
||||||
|
const tempCtx = tempCanvas.getContext("2d");
|
||||||
|
tempCtx.drawImage(canvas, 0, 0);
|
||||||
|
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||||
|
pixels = tf.browser.fromPixels(data);
|
||||||
|
}
|
||||||
const casted = pixels.toFloat();
|
const casted = pixels.toFloat();
|
||||||
tensor = casted.expandDims(0);
|
tensor = casted.expandDims(0);
|
||||||
pixels.dispose();
|
pixels.dispose();
|
||||||
|
@ -73088,12 +73116,7 @@ class Human {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const timeStart = now();
|
const timeStart = now();
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
if (tf.getBackend() !== this.config.backend) {
|
await this.resetBackend(this.config.backend);
|
||||||
this.state = "backend";
|
|
||||||
this.log("Human library setting backend:", this.config.backend);
|
|
||||||
await tf.setBackend(this.config.backend);
|
|
||||||
await tf.ready();
|
|
||||||
}
|
|
||||||
perf.backend = Math.trunc(now() - timeStamp);
|
perf.backend = Math.trunc(now() - timeStamp);
|
||||||
if (first) {
|
if (first) {
|
||||||
this.log("Human library starting");
|
this.log("Human library starting");
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -149,7 +149,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytes": 2871,
|
"bytes": 2870,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/emotion/emotion.js": {
|
"src/emotion/emotion.js": {
|
||||||
|
@ -291,7 +291,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 11908,
|
"bytes": 13144,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "node_modules/@tensorflow/tfjs/dist/tf.node.js"
|
"path": "node_modules/@tensorflow/tfjs/dist/tf.node.js"
|
||||||
|
@ -468,7 +468,7 @@
|
||||||
"dist/human.esm.js.map": {
|
"dist/human.esm.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 5121936
|
"bytes": 5123652
|
||||||
},
|
},
|
||||||
"dist/human.esm.js": {
|
"dist/human.esm.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -618,16 +618,16 @@
|
||||||
"bytesInOutput": 2230
|
"bytesInOutput": 2230
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytesInOutput": 3013
|
"bytesInOutput": 3012
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 10765
|
"bytesInOutput": 11771
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 0
|
"bytesInOutput": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 2924203
|
"bytes": 2925208
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72827,7 +72827,7 @@ var Human = (() => {
|
||||||
var require_package = __commonJS((exports, module) => {
|
var require_package = __commonJS((exports, module) => {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "@vladmandic/human",
|
name: "@vladmandic/human",
|
||||||
version: "0.4.10",
|
version: "0.5.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.node.js",
|
||||||
|
@ -72849,10 +72849,9 @@ var Human = (() => {
|
||||||
dependencies: {},
|
dependencies: {},
|
||||||
peerDependencies: {},
|
peerDependencies: {},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
seedrandom: "^3.0.5",
|
|
||||||
"@tensorflow/tfjs": "^2.7.0",
|
"@tensorflow/tfjs": "^2.7.0",
|
||||||
"@tensorflow/tfjs-node": "^2.7.0",
|
"@tensorflow/tfjs-node": "^2.7.0",
|
||||||
"@vladmandic/pilogger": "^0.2.6",
|
"@vladmandic/pilogger": "^0.2.7",
|
||||||
dayjs: "^1.9.4",
|
dayjs: "^1.9.4",
|
||||||
esbuild: "^0.7.22",
|
esbuild: "^0.7.22",
|
||||||
eslint: "^7.12.1",
|
eslint: "^7.12.1",
|
||||||
|
@ -72862,6 +72861,7 @@ var Human = (() => {
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
rimraf: "^3.0.2",
|
rimraf: "^3.0.2",
|
||||||
|
seedrandom: "^3.0.5",
|
||||||
"simple-git": "^2.21.0"
|
"simple-git": "^2.21.0"
|
||||||
},
|
},
|
||||||
scripts: {
|
scripts: {
|
||||||
|
@ -73012,17 +73012,33 @@ var Human = (() => {
|
||||||
this.models.emotion = await emotion.load(this.config);
|
this.models.emotion = await emotion.load(this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async resetBackend(backendName) {
|
||||||
|
if (tf.getBackend() !== this.config.backend) {
|
||||||
|
this.state = "backend";
|
||||||
|
if (backendName in tf.engine().registry) {
|
||||||
|
this.log("Human library setting backend:", this.config.backend);
|
||||||
|
this.config.backend = backendName;
|
||||||
|
const backendFactory = tf.findBackendFactory(backendName);
|
||||||
|
tf.removeBackend(backendName);
|
||||||
|
tf.registerBackend(backendName, backendFactory);
|
||||||
|
await tf.setBackend(backendName);
|
||||||
|
await tf.ready();
|
||||||
|
} else {
|
||||||
|
this.log("Human library backend not registred:", backendName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
tfImage(input) {
|
tfImage(input) {
|
||||||
let filtered;
|
let filtered;
|
||||||
|
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
||||||
|
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
||||||
|
let targetWidth = originalWidth;
|
||||||
|
let targetHeight = originalHeight;
|
||||||
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
||||||
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
|
||||||
let targetWidth = originalWidth;
|
|
||||||
if (this.config.filter.width > 0)
|
if (this.config.filter.width > 0)
|
||||||
targetWidth = this.config.filter.width;
|
targetWidth = this.config.filter.width;
|
||||||
else if (this.config.filter.height > 0)
|
else if (this.config.filter.height > 0)
|
||||||
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
||||||
let targetHeight = originalHeight;
|
|
||||||
if (this.config.filter.height > 0)
|
if (this.config.filter.height > 0)
|
||||||
targetHeight = this.config.filter.height;
|
targetHeight = this.config.filter.height;
|
||||||
else if (this.config.filter.width > 0)
|
else if (this.config.filter.width > 0)
|
||||||
|
@ -73069,7 +73085,19 @@ var Human = (() => {
|
||||||
if (input instanceof tf.Tensor) {
|
if (input instanceof tf.Tensor) {
|
||||||
tensor = tf.clone(input);
|
tensor = tf.clone(input);
|
||||||
} else {
|
} else {
|
||||||
const pixels = tf.browser.fromPixels(filtered || input);
|
const canvas = filtered || input;
|
||||||
|
let pixels;
|
||||||
|
if (this.config.backend === "webgl" || canvas instanceof ImageData)
|
||||||
|
pixels = tf.browser.fromPixels(canvas);
|
||||||
|
else {
|
||||||
|
const tempCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement("canvas");
|
||||||
|
tempCanvas.width = targetWidth;
|
||||||
|
tempCanvas.height = targetHeight;
|
||||||
|
const tempCtx = tempCanvas.getContext("2d");
|
||||||
|
tempCtx.drawImage(canvas, 0, 0);
|
||||||
|
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||||
|
pixels = tf.browser.fromPixels(data);
|
||||||
|
}
|
||||||
const casted = pixels.toFloat();
|
const casted = pixels.toFloat();
|
||||||
tensor = casted.expandDims(0);
|
tensor = casted.expandDims(0);
|
||||||
pixels.dispose();
|
pixels.dispose();
|
||||||
|
@ -73093,12 +73121,7 @@ var Human = (() => {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const timeStart = now();
|
const timeStart = now();
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
if (tf.getBackend() !== this.config.backend) {
|
await this.resetBackend(this.config.backend);
|
||||||
this.state = "backend";
|
|
||||||
this.log("Human library setting backend:", this.config.backend);
|
|
||||||
await tf.setBackend(this.config.backend);
|
|
||||||
await tf.ready();
|
|
||||||
}
|
|
||||||
perf.backend = Math.trunc(now() - timeStamp);
|
perf.backend = Math.trunc(now() - timeStamp);
|
||||||
if (first) {
|
if (first) {
|
||||||
this.log("Human library starting");
|
this.log("Human library starting");
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -149,7 +149,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytes": 2871,
|
"bytes": 2870,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/emotion/emotion.js": {
|
"src/emotion/emotion.js": {
|
||||||
|
@ -291,7 +291,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 11908,
|
"bytes": 13144,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "node_modules/@tensorflow/tfjs/dist/tf.node.js"
|
"path": "node_modules/@tensorflow/tfjs/dist/tf.node.js"
|
||||||
|
@ -468,7 +468,7 @@
|
||||||
"dist/human.js.map": {
|
"dist/human.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 5125792
|
"bytes": 5127510
|
||||||
},
|
},
|
||||||
"dist/human.js": {
|
"dist/human.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -618,13 +618,13 @@
|
||||||
"bytesInOutput": 2424
|
"bytesInOutput": 2424
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytesInOutput": 3145
|
"bytesInOutput": 3144
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 11994
|
"bytesInOutput": 13092
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 3070080
|
"bytes": 3071177
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5777,7 +5777,7 @@ var require_config = __commonJS((exports2) => {
|
||||||
var require_package = __commonJS((exports2, module2) => {
|
var require_package = __commonJS((exports2, module2) => {
|
||||||
module2.exports = {
|
module2.exports = {
|
||||||
name: "@vladmandic/human",
|
name: "@vladmandic/human",
|
||||||
version: "0.4.10",
|
version: "0.5.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.node.js",
|
||||||
|
@ -5799,10 +5799,9 @@ var require_package = __commonJS((exports2, module2) => {
|
||||||
dependencies: {},
|
dependencies: {},
|
||||||
peerDependencies: {},
|
peerDependencies: {},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
seedrandom: "^3.0.5",
|
|
||||||
"@tensorflow/tfjs": "^2.7.0",
|
"@tensorflow/tfjs": "^2.7.0",
|
||||||
"@tensorflow/tfjs-node": "^2.7.0",
|
"@tensorflow/tfjs-node": "^2.7.0",
|
||||||
"@vladmandic/pilogger": "^0.2.6",
|
"@vladmandic/pilogger": "^0.2.7",
|
||||||
dayjs: "^1.9.4",
|
dayjs: "^1.9.4",
|
||||||
esbuild: "^0.7.22",
|
esbuild: "^0.7.22",
|
||||||
eslint: "^7.12.1",
|
eslint: "^7.12.1",
|
||||||
|
@ -5812,6 +5811,7 @@ var require_package = __commonJS((exports2, module2) => {
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
rimraf: "^3.0.2",
|
rimraf: "^3.0.2",
|
||||||
|
seedrandom: "^3.0.5",
|
||||||
"simple-git": "^2.21.0"
|
"simple-git": "^2.21.0"
|
||||||
},
|
},
|
||||||
scripts: {
|
scripts: {
|
||||||
|
@ -5961,17 +5961,33 @@ class Human {
|
||||||
this.models.emotion = await emotion.load(this.config);
|
this.models.emotion = await emotion.load(this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async resetBackend(backendName) {
|
||||||
|
if (tf.getBackend() !== this.config.backend) {
|
||||||
|
this.state = "backend";
|
||||||
|
if (backendName in tf.engine().registry) {
|
||||||
|
this.log("Human library setting backend:", this.config.backend);
|
||||||
|
this.config.backend = backendName;
|
||||||
|
const backendFactory = tf.findBackendFactory(backendName);
|
||||||
|
tf.removeBackend(backendName);
|
||||||
|
tf.registerBackend(backendName, backendFactory);
|
||||||
|
await tf.setBackend(backendName);
|
||||||
|
await tf.ready();
|
||||||
|
} else {
|
||||||
|
this.log("Human library backend not registred:", backendName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
tfImage(input) {
|
tfImage(input) {
|
||||||
let filtered;
|
let filtered;
|
||||||
|
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
||||||
|
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
||||||
|
let targetWidth = originalWidth;
|
||||||
|
let targetHeight = originalHeight;
|
||||||
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
||||||
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
|
||||||
let targetWidth = originalWidth;
|
|
||||||
if (this.config.filter.width > 0)
|
if (this.config.filter.width > 0)
|
||||||
targetWidth = this.config.filter.width;
|
targetWidth = this.config.filter.width;
|
||||||
else if (this.config.filter.height > 0)
|
else if (this.config.filter.height > 0)
|
||||||
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
||||||
let targetHeight = originalHeight;
|
|
||||||
if (this.config.filter.height > 0)
|
if (this.config.filter.height > 0)
|
||||||
targetHeight = this.config.filter.height;
|
targetHeight = this.config.filter.height;
|
||||||
else if (this.config.filter.width > 0)
|
else if (this.config.filter.width > 0)
|
||||||
|
@ -6018,7 +6034,19 @@ class Human {
|
||||||
if (input instanceof tf.Tensor) {
|
if (input instanceof tf.Tensor) {
|
||||||
tensor = tf.clone(input);
|
tensor = tf.clone(input);
|
||||||
} else {
|
} else {
|
||||||
const pixels = tf.browser.fromPixels(filtered || input);
|
const canvas = filtered || input;
|
||||||
|
let pixels;
|
||||||
|
if (this.config.backend === "webgl" || canvas instanceof ImageData)
|
||||||
|
pixels = tf.browser.fromPixels(canvas);
|
||||||
|
else {
|
||||||
|
const tempCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement("canvas");
|
||||||
|
tempCanvas.width = targetWidth;
|
||||||
|
tempCanvas.height = targetHeight;
|
||||||
|
const tempCtx = tempCanvas.getContext("2d");
|
||||||
|
tempCtx.drawImage(canvas, 0, 0);
|
||||||
|
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||||
|
pixels = tf.browser.fromPixels(data);
|
||||||
|
}
|
||||||
const casted = pixels.toFloat();
|
const casted = pixels.toFloat();
|
||||||
tensor = casted.expandDims(0);
|
tensor = casted.expandDims(0);
|
||||||
pixels.dispose();
|
pixels.dispose();
|
||||||
|
@ -6042,12 +6070,7 @@ class Human {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const timeStart = now();
|
const timeStart = now();
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
if (tf.getBackend() !== this.config.backend) {
|
await this.resetBackend(this.config.backend);
|
||||||
this.state = "backend";
|
|
||||||
this.log("Human library setting backend:", this.config.backend);
|
|
||||||
await tf.setBackend(this.config.backend);
|
|
||||||
await tf.ready();
|
|
||||||
}
|
|
||||||
perf.backend = Math.trunc(now() - timeStamp);
|
perf.backend = Math.trunc(now() - timeStamp);
|
||||||
if (first) {
|
if (first) {
|
||||||
this.log("Human library starting");
|
this.log("Human library starting");
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -73868,7 +73868,7 @@ var require_config = __commonJS((exports2) => {
|
||||||
var require_package = __commonJS((exports2, module2) => {
|
var require_package = __commonJS((exports2, module2) => {
|
||||||
module2.exports = {
|
module2.exports = {
|
||||||
name: "@vladmandic/human",
|
name: "@vladmandic/human",
|
||||||
version: "0.4.10",
|
version: "0.5.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.node.js",
|
||||||
|
@ -73890,10 +73890,9 @@ var require_package = __commonJS((exports2, module2) => {
|
||||||
dependencies: {},
|
dependencies: {},
|
||||||
peerDependencies: {},
|
peerDependencies: {},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
seedrandom: "^3.0.5",
|
|
||||||
"@tensorflow/tfjs": "^2.7.0",
|
"@tensorflow/tfjs": "^2.7.0",
|
||||||
"@tensorflow/tfjs-node": "^2.7.0",
|
"@tensorflow/tfjs-node": "^2.7.0",
|
||||||
"@vladmandic/pilogger": "^0.2.6",
|
"@vladmandic/pilogger": "^0.2.7",
|
||||||
dayjs: "^1.9.4",
|
dayjs: "^1.9.4",
|
||||||
esbuild: "^0.7.22",
|
esbuild: "^0.7.22",
|
||||||
eslint: "^7.12.1",
|
eslint: "^7.12.1",
|
||||||
|
@ -73903,6 +73902,7 @@ var require_package = __commonJS((exports2, module2) => {
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
rimraf: "^3.0.2",
|
rimraf: "^3.0.2",
|
||||||
|
seedrandom: "^3.0.5",
|
||||||
"simple-git": "^2.21.0"
|
"simple-git": "^2.21.0"
|
||||||
},
|
},
|
||||||
scripts: {
|
scripts: {
|
||||||
|
@ -74052,17 +74052,33 @@ class Human {
|
||||||
this.models.emotion = await emotion.load(this.config);
|
this.models.emotion = await emotion.load(this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async resetBackend(backendName) {
|
||||||
|
if (tf.getBackend() !== this.config.backend) {
|
||||||
|
this.state = "backend";
|
||||||
|
if (backendName in tf.engine().registry) {
|
||||||
|
this.log("Human library setting backend:", this.config.backend);
|
||||||
|
this.config.backend = backendName;
|
||||||
|
const backendFactory = tf.findBackendFactory(backendName);
|
||||||
|
tf.removeBackend(backendName);
|
||||||
|
tf.registerBackend(backendName, backendFactory);
|
||||||
|
await tf.setBackend(backendName);
|
||||||
|
await tf.ready();
|
||||||
|
} else {
|
||||||
|
this.log("Human library backend not registred:", backendName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
tfImage(input) {
|
tfImage(input) {
|
||||||
let filtered;
|
let filtered;
|
||||||
|
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
||||||
|
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
||||||
|
let targetWidth = originalWidth;
|
||||||
|
let targetHeight = originalHeight;
|
||||||
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
||||||
const originalWidth = input.naturalWidth || input.videoWidth || input.width || input.shape && input.shape[1] > 0;
|
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || input.shape && input.shape[2] > 0;
|
|
||||||
let targetWidth = originalWidth;
|
|
||||||
if (this.config.filter.width > 0)
|
if (this.config.filter.width > 0)
|
||||||
targetWidth = this.config.filter.width;
|
targetWidth = this.config.filter.width;
|
||||||
else if (this.config.filter.height > 0)
|
else if (this.config.filter.height > 0)
|
||||||
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
||||||
let targetHeight = originalHeight;
|
|
||||||
if (this.config.filter.height > 0)
|
if (this.config.filter.height > 0)
|
||||||
targetHeight = this.config.filter.height;
|
targetHeight = this.config.filter.height;
|
||||||
else if (this.config.filter.width > 0)
|
else if (this.config.filter.width > 0)
|
||||||
|
@ -74109,7 +74125,19 @@ class Human {
|
||||||
if (input instanceof tf.Tensor) {
|
if (input instanceof tf.Tensor) {
|
||||||
tensor = tf.clone(input);
|
tensor = tf.clone(input);
|
||||||
} else {
|
} else {
|
||||||
const pixels = tf.browser.fromPixels(filtered || input);
|
const canvas = filtered || input;
|
||||||
|
let pixels;
|
||||||
|
if (this.config.backend === "webgl" || canvas instanceof ImageData)
|
||||||
|
pixels = tf.browser.fromPixels(canvas);
|
||||||
|
else {
|
||||||
|
const tempCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement("canvas");
|
||||||
|
tempCanvas.width = targetWidth;
|
||||||
|
tempCanvas.height = targetHeight;
|
||||||
|
const tempCtx = tempCanvas.getContext("2d");
|
||||||
|
tempCtx.drawImage(canvas, 0, 0);
|
||||||
|
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||||
|
pixels = tf.browser.fromPixels(data);
|
||||||
|
}
|
||||||
const casted = pixels.toFloat();
|
const casted = pixels.toFloat();
|
||||||
tensor = casted.expandDims(0);
|
tensor = casted.expandDims(0);
|
||||||
pixels.dispose();
|
pixels.dispose();
|
||||||
|
@ -74133,12 +74161,7 @@ class Human {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const timeStart = now();
|
const timeStart = now();
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
if (tf.getBackend() !== this.config.backend) {
|
await this.resetBackend(this.config.backend);
|
||||||
this.state = "backend";
|
|
||||||
this.log("Human library setting backend:", this.config.backend);
|
|
||||||
await tf.setBackend(this.config.backend);
|
|
||||||
await tf.ready();
|
|
||||||
}
|
|
||||||
perf.backend = Math.trunc(now() - timeStamp);
|
perf.backend = Math.trunc(now() - timeStamp);
|
||||||
if (first) {
|
if (first) {
|
||||||
this.log("Human library starting");
|
this.log("Human library starting");
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,7 +5,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytes": 2871,
|
"bytes": 2870,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/emotion/emotion.js": {
|
"src/emotion/emotion.js": {
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 11908,
|
"bytes": 13144,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/facemesh/facemesh.js"
|
"path": "src/facemesh/facemesh.js"
|
||||||
|
@ -260,7 +260,7 @@
|
||||||
"dist/human.node-nobundle.js.map": {
|
"dist/human.node-nobundle.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 260882
|
"bytes": 263858
|
||||||
},
|
},
|
||||||
"dist/human.node-nobundle.js": {
|
"dist/human.node-nobundle.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -353,16 +353,16 @@
|
||||||
"bytesInOutput": 2232
|
"bytesInOutput": 2232
|
||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"bytesInOutput": 3016
|
"bytesInOutput": 3015
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 47
|
"bytesInOutput": 47
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 10775
|
"bytesInOutput": 11781
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 155393
|
"bytes": 156398
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
48
src/human.js
48
src/human.js
|
@ -126,17 +126,33 @@ class Human {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async resetBackend(backendName) {
|
||||||
|
if (tf.getBackend() !== this.config.backend) {
|
||||||
|
this.state = 'backend';
|
||||||
|
if (backendName in tf.engine().registry) {
|
||||||
|
this.log('Human library setting backend:', this.config.backend);
|
||||||
|
this.config.backend = backendName;
|
||||||
|
const backendFactory = tf.findBackendFactory(backendName);
|
||||||
|
tf.removeBackend(backendName);
|
||||||
|
tf.registerBackend(backendName, backendFactory);
|
||||||
|
await tf.setBackend(backendName);
|
||||||
|
await tf.ready();
|
||||||
|
} else {
|
||||||
|
this.log('Human library backend not registred:', backendName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tfImage(input) {
|
tfImage(input) {
|
||||||
// let imageData;
|
// let imageData;
|
||||||
let filtered;
|
let filtered;
|
||||||
|
const originalWidth = input.naturalWidth || input.videoWidth || input.width || (input.shape && (input.shape[1] > 0));
|
||||||
|
const originalHeight = input.naturalHeight || input.videoHeight || input.height || (input.shape && (input.shape[2] > 0));
|
||||||
|
let targetWidth = originalWidth;
|
||||||
|
let targetHeight = originalHeight;
|
||||||
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
if (this.fx && this.config.filter.enabled && !(input instanceof tf.Tensor)) {
|
||||||
const originalWidth = input.naturalWidth || input.videoWidth || input.width || (input.shape && (input.shape[1] > 0));
|
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || (input.shape && (input.shape[2] > 0));
|
|
||||||
|
|
||||||
let targetWidth = originalWidth;
|
|
||||||
if (this.config.filter.width > 0) targetWidth = this.config.filter.width;
|
if (this.config.filter.width > 0) targetWidth = this.config.filter.width;
|
||||||
else if (this.config.filter.height > 0) targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
else if (this.config.filter.height > 0) targetWidth = originalWidth * (this.config.filter.height / originalHeight);
|
||||||
let targetHeight = originalHeight;
|
|
||||||
if (this.config.filter.height > 0) targetHeight = this.config.filter.height;
|
if (this.config.filter.height > 0) targetHeight = this.config.filter.height;
|
||||||
else if (this.config.filter.width > 0) targetHeight = originalHeight * (this.config.filter.width / originalWidth);
|
else if (this.config.filter.width > 0) targetHeight = originalHeight * (this.config.filter.width / originalWidth);
|
||||||
const offscreenCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement('canvas');
|
const offscreenCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement('canvas');
|
||||||
|
@ -166,7 +182,20 @@ class Human {
|
||||||
if (input instanceof tf.Tensor) {
|
if (input instanceof tf.Tensor) {
|
||||||
tensor = tf.clone(input);
|
tensor = tf.clone(input);
|
||||||
} else {
|
} else {
|
||||||
const pixels = tf.browser.fromPixels(filtered || input);
|
const canvas = filtered || input;
|
||||||
|
let pixels;
|
||||||
|
// tf kernel-optimized method to get imagedata, also if input is imagedata, just use it
|
||||||
|
if ((this.config.backend === 'webgl') || (canvas instanceof ImageData)) pixels = tf.browser.fromPixels(canvas);
|
||||||
|
// cpu and wasm kernel does not implement efficient fromPixels method nor we can use canvas as-is, so we do a silly one more canvas
|
||||||
|
else {
|
||||||
|
const tempCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement('canvas');
|
||||||
|
tempCanvas.width = targetWidth;
|
||||||
|
tempCanvas.height = targetHeight;
|
||||||
|
const tempCtx = tempCanvas.getContext('2d');
|
||||||
|
tempCtx.drawImage(canvas, 0, 0);
|
||||||
|
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||||
|
pixels = tf.browser.fromPixels(data);
|
||||||
|
}
|
||||||
const casted = pixels.toFloat();
|
const casted = pixels.toFloat();
|
||||||
tensor = casted.expandDims(0);
|
tensor = casted.expandDims(0);
|
||||||
pixels.dispose();
|
pixels.dispose();
|
||||||
|
@ -197,12 +226,7 @@ class Human {
|
||||||
|
|
||||||
// configure backend
|
// configure backend
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
if (tf.getBackend() !== this.config.backend) {
|
await this.resetBackend(this.config.backend);
|
||||||
this.state = 'backend';
|
|
||||||
this.log('Human library setting backend:', this.config.backend);
|
|
||||||
await tf.setBackend(this.config.backend);
|
|
||||||
await tf.ready();
|
|
||||||
}
|
|
||||||
perf.backend = Math.trunc(now() - timeStamp);
|
perf.backend = Math.trunc(now() - timeStamp);
|
||||||
|
|
||||||
// check number of loaded models
|
// check number of loaded models
|
||||||
|
|
Loading…
Reference in New Issue