From 9b5ced8f62046d6513ef429f4c7f73998160a2e2 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 5 Apr 2021 11:48:24 -0400 Subject: [PATCH] add dynamic viewport and fix web worker --- CHANGELOG.md | 8 ++++++-- demo/index.html | 6 +++--- demo/index.js | 4 ++++ src/image/image.ts | 31 +++++++++++++++++++------------ 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc7cdcdc..1f6fafa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # @vladmandic/human -Version: **1.3.3** +Version: **1.3.4** Description: **Human: AI-powered 3D Face Detection, Face Description & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition** Author: **Vladimir Mandic ** @@ -9,9 +9,13 @@ Repository: **** ## Changelog -### **HEAD -> main** 2021/04/04 mandic00@live.com +### **HEAD -> main** 2021/04/05 mandic00@live.com +### **1.3.4** 2021/04/04 mandic00@live.com + +- implement webhint + ### **1.3.3** 2021/04/03 mandic00@live.com - fix linting and tests diff --git a/demo/index.html b/demo/index.html index 65e18f98..79db69e7 100644 --- a/demo/index.html +++ b/demo/index.html @@ -3,7 +3,7 @@ Human - + @@ -19,12 +19,12 @@ body { margin: 0; background: black; color: white; overflow-x: hidden } body::-webkit-scrollbar { display: none; } hr { width: 100%; } - .play { position: absolute; width: 250px; height: 250px; z-index: 9; top: 55%; left: 50%; margin-left: -125px; display: none; } + .play { position: absolute; width: 250px; height: 250px; z-index: 9; bottom: 15%; left: 50%; margin-left: -125px; display: none; } .btn-background { fill:grey; cursor: pointer; opacity: 0.6; } .btn-background:hover { opacity: 1; } .btn-foreground { fill:white; cursor: pointer; opacity: 0.8; } .btn-foreground:hover { opacity: 1; } - .status { position: absolute; width: 100vw; bottom: 15%; text-align: center; font-size: 4rem; font-weight: 100; text-shadow: 2px 2px darkslategrey; } + .status { position: absolute; width: 100vw; bottom: 10%; text-align: center; font-size: 4rem; font-weight: 100; text-shadow: 2px 2px darkslategrey; } .thumbnail { margin: 8px; box-shadow: 0 0 4px 4px dimgrey; } .thumbnail:hover { box-shadow: 0 0 8px 8px dimgrey; filter: grayscale(1); } .log { position: absolute; bottom: 0; margin: 0.4rem; font-size: 0.9rem; } diff --git a/demo/index.js b/demo/index.js index bd6b2c0d..3c1665e0 100644 --- a/demo/index.js +++ b/demo/index.js @@ -189,6 +189,9 @@ async function drawResults(input) { async function setupCamera() { if (ui.busy) return null; ui.busy = true; + const viewportScale = Math.min(1, Math.round(100 * window.outerWidth / 700) / 100); + log('demo viewport scale:', viewportScale); + document.querySelector('meta[name=viewport]').setAttribute('content', `width=device-width, shrink-to-fit=no; initial-scale=${viewportScale}`); const video = document.getElementById('video'); const canvas = document.getElementById('canvas'); const output = document.getElementById('log'); @@ -569,6 +572,7 @@ async function main() { const res = await human.warmup(userConfig); // this is not required, just pre-warms all models for faster initial inference if (res && res.canvas && ui.drawWarmup) await drawWarmup(res); } + await setupCamera(); status('human: ready'); document.getElementById('loader').style.display = 'none'; document.getElementById('play').style.display = 'block'; diff --git a/src/image/image.ts b/src/image/image.ts index 13248b14..13eead58 100644 --- a/src/image/image.ts +++ b/src/image/image.ts @@ -18,13 +18,13 @@ export function process(input, config): { tensor: tf.Tensor, canvas: OffscreenCa if (!input) throw new Error('Human: Input is missing'); if ( !(input instanceof tf.Tensor) - && !(input instanceof Image) - && !(input instanceof ImageData) - && !(input instanceof ImageBitmap) - && !(input instanceof HTMLImageElement) - && !(input instanceof HTMLVideoElement) - && !(input instanceof HTMLCanvasElement) - && !(input instanceof OffscreenCanvas) + && !(typeof Image !== 'undefined' && input instanceof Image) + && !(typeof ImageData !== 'undefined' && input instanceof ImageData) + && !(typeof ImageBitmap !== 'undefined' && input instanceof ImageBitmap) + && !(typeof HTMLImageElement !== 'undefined' && input instanceof HTMLImageElement) + && !(typeof HTMLVideoElement !== 'undefined' && input instanceof HTMLVideoElement) + && !(typeof HTMLCanvasElement !== 'undefined' && input instanceof HTMLCanvasElement) + && !(typeof OffscreenCanvas !== 'undefined' && input instanceof OffscreenCanvas) ) { throw new Error('Human: Input type is not recognized'); } @@ -107,14 +107,21 @@ export function process(input, config): { tensor: tf.Tensor, canvas: OffscreenCa if (fx) fx = null; } let pixels; - if (outCanvas.data) { + if (outCanvas.data) { // if we have data, just convert to tensor const shape = [outCanvas.height, outCanvas.width, 3]; pixels = tf.tensor3d(outCanvas.data, shape, 'int32'); - } else if ((config.backend === 'webgl') || (outCanvas instanceof ImageData)) { - // tf kernel-optimized method to get imagedata, also if input is imagedata, just use it + } else if (outCanvas instanceof ImageData) { // if input is imagedata, just use it pixels = tf.browser.fromPixels(outCanvas); - } else { - // 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 if (config.backend === 'webgl' || config.backend === 'humangl') { // tf kernel-optimized method to get imagedata + // we can use canvas as-is as it already has a context, so we do a silly one more canvas + 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(outCanvas, 0, 0); + pixels = tf.browser.fromPixels(tempCanvas); + } else { // cpu and wasm kernel does not implement efficient fromPixels method + // we can use canvas as-is as it already has a context, so we do a silly one more canvas const tempCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement('canvas'); tempCanvas.width = targetWidth; tempCanvas.height = targetHeight;