diff --git a/demo/browser.js b/demo/browser.js index 9c6fa699..d9a01a13 100644 --- a/demo/browser.js +++ b/demo/browser.js @@ -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('
'); 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; diff --git a/demo/index.html b/demo/index.html index 51050796..80c1dff1 100644 --- a/demo/index.html +++ b/demo/index.html @@ -19,10 +19,17 @@ +
+ + + + +
+
- +
-
Human library
+
diff --git a/demo/menu.js b/demo/menu.js index cb7bf41f..981fcfcc 100644 --- a/demo/menu.js +++ b/demo/menu.js @@ -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 = `${title}`; this.container.appendChild(el); + return el; } // eslint-disable-next-line class-methods-use-this diff --git a/src/human.js b/src/human.js index f14d094b..ba2a87c1 100644 --- a/src/human.js +++ b/src/human.js @@ -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);