optimized demo

pull/50/head
Vladimir Mandic 2020-11-02 22:15:37 -05:00
parent 4438583612
commit 170d234e6d
19 changed files with 93 additions and 64 deletions

View File

@ -6,9 +6,9 @@ const human = new Human();
// ui options
const ui = {
baseColor: 'rgba(173, 216, 230, 0.3)', // this is 'lightblue', just with alpha channel
baseBackground: 'rgba(50, 50, 50, 1)', // this is 'lightblue', just with alpha channel
baseLabel: 'rgba(173, 216, 230, 0.9)',
baseColor: 'rgba(173, 216, 230, 0.3)', // 'lightblue' with light alpha channel
baseBackground: 'rgba(50, 50, 50, 1)', // 'grey'
baseLabel: 'rgba(173, 216, 230, 0.9)', // 'lightblue' with dark alpha channel
baseFontProto: 'small-caps {size} "Segoe UI"',
baseLineWidth: 16,
baseLineHeightProto: 2,
@ -88,6 +88,11 @@ const log = (...msg) => {
if (ui.console) console.log(...msg);
};
const status = (msg) => {
// eslint-disable-next-line no-console
document.getElementById('status').innerText = msg;
};
// draws processed results and starts processing of a next frame
function drawResults(input, result, canvas) {
// update fps data
@ -131,13 +136,15 @@ async function setupCamera() {
const output = document.getElementById('log');
const live = video.srcObject ? ((video.srcObject.getVideoTracks()[0].readyState === 'live') && (video.readyState > 2) && (!video.paused)) : false;
let msg = `Setting up camera: live: ${live} facing: ${ui.facing ? 'front' : 'back'}`;
status('starting camera');
output.innerText += `\n${msg}`;
log(msg);
// setup webcam. note that navigator.mediaDevices requires that page is accessed via https
if (!navigator.mediaDevices) {
msg = 'Camera access not supported';
msg = 'camera access not supported';
output.innerText += `\n${msg}`;
log(msg);
status(msg);
return null;
}
let stream;
@ -148,6 +155,7 @@ async function setupCamera() {
});
} catch (err) {
output.innerText += '\nCamera permission denied';
status('camera permission denied');
log(err);
}
if (stream) video.srcObject = stream;
@ -250,11 +258,13 @@ async function detectVideo() {
ui.baseFont = ui.baseFontProto.replace(/{size}/, '1.2rem');
ui.baseLineHeight = ui.baseLineHeightProto;
if ((video.srcObject !== null) && !video.paused) {
document.getElementById('log').innerText += '\nPaused ...';
document.getElementById('play').style.display = 'block';
status('paused');
video.pause();
} else {
await setupCamera();
document.getElementById('log').innerText += '\nStarting Human Library ...';
document.getElementById('play').style.display = 'none';
status('');
video.play();
}
runHumanDetect(video, canvas);
@ -262,6 +272,7 @@ async function detectVideo() {
// just initialize everything and call main function
async function detectSampleImages() {
document.getElementById('play').style.display = 'none';
config.videoOptimized = false;
ui.baseFont = ui.baseFontProto.replace(/{size}/, `${1.2 * ui.columns}rem`);
ui.baseLineHeight = ui.baseLineHeightProto * ui.columns;
@ -273,8 +284,9 @@ async function detectSampleImages() {
function setupMenu() {
menu = new Menu(document.body, '...', { top: '1rem', right: '1rem' });
menu.addButton('Start Video', 'Pause Video', (evt) => detectVideo(evt));
const btn = menu.addButton('Start Video', 'Pause Video', () => detectVideo());
menu.addButton('Process Images', 'Process Images', () => detectSampleImages());
document.getElementById('play').addEventListener('click', () => btn.click());
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);
@ -354,9 +366,15 @@ function setupMenu() {
async function main() {
log('Human demo starting ...');
setupMenu();
const msg = `Human ready: version: ${human.version} TensorFlow/JS version: ${human.tf.version_core}`;
document.getElementById('log').innerText += '\n' + msg;
const msg = `Human Library: version: ${human.version} TensorFlow/JS version: ${human.tf.version_core}`;
document.getElementById('log').innerText = msg;
status('loading');
log(msg);
await human.load();
status('initializing');
const warmup = new ImageData(50, 50);
await human.detect(warmup);
status('human: ready');
}
window.onload = main;

View File

@ -19,10 +19,17 @@
<script src="./browser.js" type="module"></script>
</head>
<body style="margin: 0; background: black; color: white; font-family: 'Segoe UI'; font-size: 16px; font-variant: small-caps; overflow-x: hidden">
<div id="play" style="position: absolute; width: 250px; height: 250px; z-index: 25; top: 30%; left: 50%; margin-left: -125px">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm115.7 272l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z" style="fill:darkslategray; cursor:pointer; opacity: 0.6"/>
<path d="M371.7 280l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z" style="fill:white; cursor:pointer"/>
</svg>
</div>
<div id="status" style="position: absolute; width: 100vw; top: 100px; text-align: center; font-size: 4rem; font-weight: 100; text-shadow: 2px 2px darkslategrey;"></div>
<video id="video" playsinline style="display: none"></video>
<image id="image" src="" style="display: none"></video>
<canvas id="canvas" style="margin: 0 auto"></canvas>
<canvas id="canvas" style="margin: 0 auto; width: 100%"></canvas>
<div id="samples" style="display: flex; flex-wrap: wrap"></div>
<div id="log" style="position: fixed; bottom: 0">Human library</div>
<div id="log" style="position: fixed; bottom: 0"></div>
</body>
</html>

View File

@ -164,6 +164,7 @@ class Menu {
item.style.display = this.hidden ? 'none' : 'block';
}
});
return el;
}
addLabel(title) {
@ -172,6 +173,7 @@ class Menu {
el.id = this.newID;
el.innerHTML = title;
this.container.appendChild(el);
return el;
}
addBool(title, object, variable, callback) {
@ -183,6 +185,7 @@ class Menu {
object[variable] = evt.target.checked;
if (callback) callback(evt.target.checked);
});
return el;
}
async addList(title, items, selected, callback) {
@ -201,6 +204,7 @@ class Menu {
el.addEventListener('change', (evt) => {
if (callback) callback(items[evt.target.selectedIndex]);
});
return el;
}
addRange(title, object, variable, min, max, step, callback) {
@ -213,6 +217,7 @@ class Menu {
evt.target.setAttribute('value', evt.target.value);
if (callback) callback(evt.target.value);
});
return el;
}
addHTML(html) {
@ -221,6 +226,7 @@ class Menu {
el.id = this.newID;
if (html) el.innerHTML = html;
this.container.appendChild(el);
return el;
}
addButton(titleOn, titleOff, callback) {
@ -238,6 +244,7 @@ class Menu {
else el.innerText = titleOn;
if (callback) callback(el.innerText !== titleOn);
});
return el;
}
addValue(title, val, suffix = '') {
@ -246,6 +253,7 @@ class Menu {
el.id = `menu-val-${title}`;
el.innerText = `${title}: ${val}${suffix}`;
this.container.appendChild(el);
return el;
}
// eslint-disable-next-line class-methods-use-this
@ -262,6 +270,7 @@ class Menu {
el.id = this.newID;
el.innerHTML = `<font color=${theme.chartColor}>${title}</font><canvas id="menu-canvas-${id}" class="menu-chart-canvas" width="${width}px" height="${height}px"></canvas>`;
this.container.appendChild(el);
return el;
}
// eslint-disable-next-line class-methods-use-this

View File

@ -3896,7 +3896,7 @@ var require_ssrnet = __commonJS((exports) => {
const profile2 = require_profile();
const models = {};
let last = {age: 0, gender: ""};
let frame = 0;
let frame = Number.MAX_SAFE_INTEGER;
async function loadAge(config) {
if (!models.age)
models.age = await tf2.loadGraphModel(config.face.age.modelPath);
@ -6057,15 +6057,14 @@ class Human {
else
ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, this.inCanvas.width, this.inCanvas.height);
if (this.config.filter.enabled) {
if (!this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
if (!this.fx || !this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
this.outCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(this.inCanvas.width, this.inCanvas.height) : document.createElement("canvas");
if (this.outCanvas.width !== this.inCanvas.width)
this.outCanvas.width = this.inCanvas.width;
if (this.outCanvas.height !== this.inCanvas.height)
this.outCanvas.height = this.inCanvas.height;
}
if (!this.fx)
this.fx = tf.ENV.flags.IS_BROWSER && typeof document !== "undefined" ? new fxImage.Canvas({canvas: this.outCanvas}) : null;
}
this.fx.reset();
this.fx.addFilter("brightness", this.config.filter.brightness);
if (this.config.filter.contrast !== 0)

File diff suppressed because one or more lines are too long

View File

@ -263,7 +263,7 @@
"imports": []
},
"src/ssrnet/ssrnet.js": {
"bytes": 2127,
"bytes": 2149,
"imports": [
{
"path": "src/profile.js"
@ -275,7 +275,7 @@
"dist/human.esm-nobundle.js.map": {
"imports": [],
"inputs": {},
"bytes": 256450
"bytes": 256473
},
"dist/human.esm-nobundle.js": {
"imports": [],
@ -308,7 +308,7 @@
"bytesInOutput": 1092
},
"src/ssrnet/ssrnet.js": {
"bytesInOutput": 2322
"bytesInOutput": 2344
},
"src/emotion/emotion.js": {
"bytesInOutput": 2040
@ -374,13 +374,13 @@
"bytesInOutput": 3012
},
"src/human.js": {
"bytesInOutput": 13241
"bytesInOutput": 13231
},
"src/human.js": {
"bytesInOutput": 0
}
},
"bytes": 159418
"bytes": 159430
}
}
}

7
dist/human.esm.js vendored
View File

@ -70945,7 +70945,7 @@ var require_ssrnet = __commonJS((exports) => {
const profile2 = require_profile();
const models = {};
let last = {age: 0, gender: ""};
let frame = 0;
let frame = Number.MAX_SAFE_INTEGER;
async function loadAge(config) {
if (!models.age)
models.age = await tf2.loadGraphModel(config.face.age.modelPath);
@ -73106,15 +73106,14 @@ class Human {
else
ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, this.inCanvas.width, this.inCanvas.height);
if (this.config.filter.enabled) {
if (!this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
if (!this.fx || !this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
this.outCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(this.inCanvas.width, this.inCanvas.height) : document.createElement("canvas");
if (this.outCanvas.width !== this.inCanvas.width)
this.outCanvas.width = this.inCanvas.width;
if (this.outCanvas.height !== this.inCanvas.height)
this.outCanvas.height = this.inCanvas.height;
}
if (!this.fx)
this.fx = tf.ENV.flags.IS_BROWSER && typeof document !== "undefined" ? new fxImage.Canvas({canvas: this.outCanvas}) : null;
}
this.fx.reset();
this.fx.addFilter("brightness", this.config.filter.brightness);
if (this.config.filter.contrast !== 0)

File diff suppressed because one or more lines are too long

10
dist/human.esm.json vendored
View File

@ -450,7 +450,7 @@
"imports": []
},
"src/ssrnet/ssrnet.js": {
"bytes": 2127,
"bytes": 2149,
"imports": [
{
"path": "node_modules/@tensorflow/tfjs/dist/tf.node.js"
@ -481,7 +481,7 @@
"dist/human.esm.js.map": {
"imports": [],
"inputs": {},
"bytes": 5129756
"bytes": 5129779
},
"dist/human.esm.js": {
"imports": [],
@ -571,7 +571,7 @@
"bytesInOutput": 1092
},
"src/ssrnet/ssrnet.js": {
"bytesInOutput": 2312
"bytesInOutput": 2334
},
"src/emotion/emotion.js": {
"bytesInOutput": 2030
@ -637,13 +637,13 @@
"bytesInOutput": 3012
},
"src/human.js": {
"bytesInOutput": 13231
"bytesInOutput": 13221
},
"src/human.js": {
"bytesInOutput": 0
}
},
"bytes": 2928384
"bytes": 2928396
}
}
}

7
dist/human.js vendored
View File

@ -70946,7 +70946,7 @@ var Human = (() => {
const profile = require_profile();
const models = {};
let last = {age: 0, gender: ""};
let frame = 0;
let frame = Number.MAX_SAFE_INTEGER;
async function loadAge(config) {
if (!models.age)
models.age = await tf.loadGraphModel(config.face.age.modelPath);
@ -73111,15 +73111,14 @@ var Human = (() => {
else
ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, this.inCanvas.width, this.inCanvas.height);
if (this.config.filter.enabled) {
if (!this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
if (!this.fx || !this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
this.outCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(this.inCanvas.width, this.inCanvas.height) : document.createElement("canvas");
if (this.outCanvas.width !== this.inCanvas.width)
this.outCanvas.width = this.inCanvas.width;
if (this.outCanvas.height !== this.inCanvas.height)
this.outCanvas.height = this.inCanvas.height;
}
if (!this.fx)
this.fx = tf.ENV.flags.IS_BROWSER && typeof document !== "undefined" ? new fxImage.Canvas({canvas: this.outCanvas}) : null;
}
this.fx.reset();
this.fx.addFilter("brightness", this.config.filter.brightness);
if (this.config.filter.contrast !== 0)

4
dist/human.js.map vendored

File diff suppressed because one or more lines are too long

10
dist/human.json vendored
View File

@ -450,7 +450,7 @@
"imports": []
},
"src/ssrnet/ssrnet.js": {
"bytes": 2127,
"bytes": 2149,
"imports": [
{
"path": "node_modules/@tensorflow/tfjs/dist/tf.node.js"
@ -481,7 +481,7 @@
"dist/human.js.map": {
"imports": [],
"inputs": {},
"bytes": 5133654
"bytes": 5133676
},
"dist/human.js": {
"imports": [],
@ -571,7 +571,7 @@
"bytesInOutput": 1140
},
"src/ssrnet/ssrnet.js": {
"bytesInOutput": 2432
"bytesInOutput": 2454
},
"src/emotion/emotion.js": {
"bytesInOutput": 2133
@ -637,10 +637,10 @@
"bytesInOutput": 3144
},
"src/human.js": {
"bytesInOutput": 14680
"bytesInOutput": 14666
}
},
"bytes": 3074564
"bytes": 3074572
}
}
}

View File

@ -3896,7 +3896,7 @@ var require_ssrnet = __commonJS((exports2) => {
const profile2 = require_profile();
const models = {};
let last = {age: 0, gender: ""};
let frame = 0;
let frame = Number.MAX_SAFE_INTEGER;
async function loadAge(config) {
if (!models.age)
models.age = await tf2.loadGraphModel(config.face.age.modelPath);
@ -6060,15 +6060,14 @@ class Human {
else
ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, this.inCanvas.width, this.inCanvas.height);
if (this.config.filter.enabled) {
if (!this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
if (!this.fx || !this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
this.outCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(this.inCanvas.width, this.inCanvas.height) : document.createElement("canvas");
if (this.outCanvas.width !== this.inCanvas.width)
this.outCanvas.width = this.inCanvas.width;
if (this.outCanvas.height !== this.inCanvas.height)
this.outCanvas.height = this.inCanvas.height;
}
if (!this.fx)
this.fx = tf.ENV.flags.IS_BROWSER && typeof document !== "undefined" ? new fxImage.Canvas({canvas: this.outCanvas}) : null;
}
this.fx.reset();
this.fx.addFilter("brightness", this.config.filter.brightness);
if (this.config.filter.contrast !== 0)

File diff suppressed because one or more lines are too long

7
dist/human.node.js vendored
View File

@ -71987,7 +71987,7 @@ var require_ssrnet = __commonJS((exports2) => {
const profile2 = require_profile();
const models = {};
let last = {age: 0, gender: ""};
let frame = 0;
let frame = Number.MAX_SAFE_INTEGER;
async function loadAge(config) {
if (!models.age)
models.age = await tf2.loadGraphModel(config.face.age.modelPath);
@ -74151,15 +74151,14 @@ class Human {
else
ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, this.inCanvas.width, this.inCanvas.height);
if (this.config.filter.enabled) {
if (!this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
if (!this.fx || !this.outCanvas || this.inCanvas.width !== this.outCanvas.width || this.inCanvas.height !== this.outCanvas.height) {
this.outCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(this.inCanvas.width, this.inCanvas.height) : document.createElement("canvas");
if (this.outCanvas.width !== this.inCanvas.width)
this.outCanvas.width = this.inCanvas.width;
if (this.outCanvas.height !== this.inCanvas.height)
this.outCanvas.height = this.inCanvas.height;
}
if (!this.fx)
this.fx = tf.ENV.flags.IS_BROWSER && typeof document !== "undefined" ? new fxImage.Canvas({canvas: this.outCanvas}) : null;
}
this.fx.reset();
this.fx.addFilter("brightness", this.config.filter.brightness);
if (this.config.filter.contrast !== 0)

File diff suppressed because one or more lines are too long

10
dist/human.node.json vendored
View File

@ -263,7 +263,7 @@
"imports": []
},
"src/ssrnet/ssrnet.js": {
"bytes": 2127,
"bytes": 2149,
"imports": [
{
"path": "src/profile.js"
@ -275,7 +275,7 @@
"dist/human.node-nobundle.js.map": {
"imports": [],
"inputs": {},
"bytes": 271906
"bytes": 271929
},
"dist/human.node-nobundle.js": {
"imports": [],
@ -308,7 +308,7 @@
"bytesInOutput": 1095
},
"src/ssrnet/ssrnet.js": {
"bytesInOutput": 2326
"bytesInOutput": 2348
},
"src/emotion/emotion.js": {
"bytesInOutput": 2043
@ -377,10 +377,10 @@
"bytesInOutput": 47
},
"src/human.js": {
"bytesInOutput": 13241
"bytesInOutput": 13231
}
},
"bytes": 159575
"bytes": 159587
}
}
}

View File

@ -184,12 +184,12 @@ class Human {
if (input instanceof ImageData) ctx.putImageData(input, 0, 0);
else ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, this.inCanvas.width, this.inCanvas.height);
if (this.config.filter.enabled) {
if (!this.outCanvas || (this.inCanvas.width !== this.outCanvas.width) || (this.inCanvas.height !== this.outCanvas.height)) {
if (!this.fx || !this.outCanvas || (this.inCanvas.width !== this.outCanvas.width) || (this.inCanvas.height !== this.outCanvas.height)) {
this.outCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(this.inCanvas.width, this.inCanvas.height) : document.createElement('canvas');
if (this.outCanvas.width !== this.inCanvas.width) this.outCanvas.width = this.inCanvas.width;
if (this.outCanvas.height !== this.inCanvas.height) this.outCanvas.height = this.inCanvas.height;
this.fx = (tf.ENV.flags.IS_BROWSER && (typeof document !== 'undefined')) ? new fxImage.Canvas({ canvas: this.outCanvas }) : null;
}
if (!this.fx) this.fx = (tf.ENV.flags.IS_BROWSER && (typeof document !== 'undefined')) ? new fxImage.Canvas({ canvas: this.outCanvas }) : null;
this.fx.reset();
this.fx.addFilter('brightness', this.config.filter.brightness); // must have at least one filter enabled
if (this.config.filter.contrast !== 0) this.fx.addFilter('contrast', this.config.filter.contrast);

View File

@ -3,7 +3,7 @@ const profile = require('../profile.js');
const models = {};
let last = { age: 0, gender: '' };
let frame = 0;
let frame = Number.MAX_SAFE_INTEGER;
async function loadAge(config) {
if (!models.age) models.age = await tf.loadGraphModel(config.face.age.modelPath);