pull/134/head
Vladimir Mandic 2021-04-16 18:00:24 -04:00
parent 981b2b9b08
commit 4b88212f22
8 changed files with 60 additions and 43 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -14,7 +14,6 @@
<script src="./face3d.js" type="module"></script> <script src="./face3d.js" type="module"></script>
<style> <style>
@font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 100; src: local('Lato'), url('../assets/lato-light.woff2') } @font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 100; src: local('Lato'), url('../assets/lato-light.woff2') }
@font-face { font-family: 'FA'; font-display: swap; font-style: normal; font-weight: 900; src: local('FA'), url('../assets/fa-solid-900.woff2'); }
html { font-family: 'Lato', 'Segoe UI'; font-size: 16px; font-variant: small-caps; } html { font-family: 'Lato', 'Segoe UI'; font-size: 16px; font-variant: small-caps; }
body { margin: 0; background: black; color: white; overflow-x: hidden; } body { margin: 0; background: black; color: white; overflow-x: hidden; }
body::-webkit-scrollbar { display: none; } body::-webkit-scrollbar { display: none; }

View File

@ -22,11 +22,11 @@ function createCSS() {
.menu { position: absolute; top: 0rem; right: 0; min-width: 180px; width: max-content; padding: 0.2rem 0.2rem 0 0.2rem; line-height: 1.8rem; z-index: 10; background: ${theme.background}; border: none } .menu { position: absolute; top: 0rem; right: 0; min-width: 180px; width: max-content; padding: 0.2rem 0.2rem 0 0.2rem; line-height: 1.8rem; z-index: 10; background: ${theme.background}; border: none }
.button { text-shadow: none; } .button { text-shadow: none; }
.menu:hover { background: ${theme.hover}; }
.menu-container { display: block; max-height: 100vh; } .menu-container { display: block; max-height: 100vh; }
.menu-container-fadeout { max-height: 0; overflow: hidden; transition: max-height, 0.5s ease; } .menu-container-fadeout { max-height: 0; overflow: hidden; transition: max-height, 0.5s ease; }
.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; padding: 0.2rem; cursor: default; width: 100%; } .menu-item { display: flex; white-space: nowrap; padding: 0.2rem; cursor: default; width: 100%; }
.menu-item:hover { background: ${theme.hover} }
.menu-title { cursor: pointer; } .menu-title { 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; font-weight: 800; } .menu-label { padding: 0; font-weight: 800; }
@ -112,7 +112,7 @@ class Menu {
if (this.container && this.menu) { if (this.container && this.menu) {
this.container.classList.toggle('menu-container-fadeout'); this.container.classList.toggle('menu-container-fadeout');
this.container.classList.toggle('menu-container-fadein'); this.container.classList.toggle('menu-container-fadein');
this.menu.style.borderStyle = this.container.classList.contains('menu-container-fadeout') ? 'none' : 'solid'; // this.menu.style.borderStyle = this.container.classList.contains('menu-container-fadeout') ? 'none' : 'solid';
} }
}); });
@ -153,6 +153,7 @@ class Menu {
if (this.container && this.menu) { if (this.container && this.menu) {
this.container.classList.toggle('menu-container-fadeout'); this.container.classList.toggle('menu-container-fadeout');
this.container.classList.toggle('menu-container-fadein'); this.container.classList.toggle('menu-container-fadein');
/*
if (this.container.classList.contains('menu-container-fadein') && evt) { if (this.container.classList.contains('menu-container-fadein') && evt) {
const x = evt.x || (evt.touches && evt.touches[0] ? evt.touches[0].pageX : null); const x = evt.x || (evt.touches && evt.touches[0] ? evt.touches[0].pageX : null);
// const y = evt.y || (evt.touches && evt.touches[0] ? evt.touches[0].pageY : null); // const y = evt.y || (evt.touches && evt.touches[0] ? evt.touches[0].pageY : null);
@ -163,10 +164,11 @@ class Menu {
this.menu.style.left = ''; this.menu.style.left = '';
this.menu.style.right = '0'; this.menu.style.right = '0';
} }
this.menu.style.borderStyle = 'solid'; // this.menu.style.borderStyle = 'solid';
} else { } else {
this.menu.style.borderStyle = 'none'; // this.menu.style.borderStyle = 'none';
} }
*/
} }
} }

13
demo/icons.css Normal file

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@
<head> <head>
<title>Human</title> <title>Human</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width" id="viewport">
<meta name="keywords" content="Human"> <meta name="keywords" content="Human">
<meta name="application-name" content="Human"> <meta name="application-name" content="Human">
<meta name="description" content="Human: 3D Face Detection, Body Pose, Hand & Finger Tracking, Iris Tracking, Age & Gender Prediction, Emotion Prediction & Gesture Recognition; Author: Vladimir Mandic <https://github.com/vladmandic>"> <meta name="description" content="Human: 3D Face Detection, Body Pose, Hand & Finger Tracking, Iris Tracking, Age & Gender Prediction, Emotion Prediction & Gesture Recognition; Author: Vladimir Mandic <https://github.com/vladmandic>">
@ -11,16 +11,16 @@
<link rel="manifest" href="./manifest.webmanifest"> <link rel="manifest" href="./manifest.webmanifest">
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon"> <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="../assets/icon.png"> <link rel="apple-touch-icon" href="../assets/icon.png">
<!-- <script src="../node_modules/@tensorflow/tfjs/dist/tf.es2017.js"></script> --> <link rel="stylesheet" type="text/css" href="./icons.css">
<script src="./index.js" type="module"></script> <script src="./index.js" type="module"></script>
<style> <style>
@font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 100; src: local('Lato'), url('../assets/lato-light.woff2') } @font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 100; src: local('Lato'), url('../assets/lato-light.woff2') }
@font-face { font-family: 'FA'; font-display: swap; font-style: normal; font-weight: 900; src: local('FA'), url('../assets/fa-solid-900.woff2'); }
html { font-family: 'Lato', 'Segoe UI'; font-size: 16px; font-variant: small-caps; } html { font-family: 'Lato', 'Segoe UI'; font-size: 16px; font-variant: small-caps; }
body { margin: 0; background: black; color: white; overflow-x: hidden } body { margin: 0; background: black; color: white; overflow-x: hidden }
body::-webkit-scrollbar { display: none; } body::-webkit-scrollbar { display: none; }
hr { width: 100%; } hr { width: 100%; }
.play { position: absolute; width: 250px; height: 250px; z-index: 9; bottom: 15%; left: 50%; margin-left: -125px; display: none; } .play { position: absolute; width: 256px; height: 256px; z-index: 9; bottom: 15%; left: 50%; margin-left: -125px; display: none; filter: grayscale(1); }
.play:hover { filter: grayscale(0); }
.btn-background { fill:grey; cursor: pointer; opacity: 0.6; } .btn-background { fill:grey; cursor: pointer; opacity: 0.6; }
.btn-background:hover { opacity: 1; } .btn-background:hover { opacity: 1; }
.btn-foreground { fill:white; cursor: pointer; opacity: 0.8; } .btn-foreground { fill:white; cursor: pointer; opacity: 0.8; }
@ -35,7 +35,7 @@
.canvas { margin: 0 auto; } .canvas { margin: 0 auto; }
.bench { position: absolute; right: 0; bottom: 0; } .bench { position: absolute; right: 0; bottom: 0; }
.compare-image { width: 200px; position: absolute; top: 150px; left: 30px; box-shadow: 0 0 2px 2px black; background: black; } .compare-image { width: 200px; position: absolute; top: 150px; left: 30px; box-shadow: 0 0 2px 2px black; background: black; }
.loader { width: 300px; height: 300px; border: 3px solid transparent; border-radius: 50%; border-top: 4px solid #f15e41; animation: spin 4s linear infinite; position: absolute; bottom: 25%; left: 50%; margin-left: -150px; z-index: 15; } .loader { width: 300px; height: 300px; border: 3px solid transparent; border-radius: 50%; border-top: 4px solid #f15e41; animation: spin 4s linear infinite; position: absolute; bottom: 15%; left: 50%; margin-left: -150px; z-index: 15; }
.loader::before, .loader::after { content: ""; position: absolute; top: 6px; bottom: 6px; left: 6px; right: 6px; border-radius: 50%; border: 4px solid transparent; } .loader::before, .loader::after { content: ""; position: absolute; top: 6px; bottom: 6px; left: 6px; right: 6px; border-radius: 50%; border: 4px solid transparent; }
.loader::before { border-top-color: #bad375; animation: 3s spin linear infinite; } .loader::before { border-top-color: #bad375; animation: 3s spin linear infinite; }
.loader::after { border-top-color: #26a9e0; animation: spin 1.5s linear infinite; } .loader::after { border-top-color: #26a9e0; animation: spin 1.5s linear infinite; }
@ -60,15 +60,13 @@
.button-model::before { content: "\f2c2"; } .button-model::before { content: "\f2c2"; }
.button-start::before { content: "\f144"; } .button-start::before { content: "\f144"; }
.button-stop::before { content: "\f28b"; } .button-stop::before { content: "\f28b"; }
.icon { width: 180px; text-align: -webkit-center; text-align: -moz-center; filter: grayscale(1); }
.icon:hover { background: #505050; filter: grayscale(0); }
</style> </style>
</head> </head>
<body> <body>
<div id="play" class="play"> <div id="play" class="play icon-play"></div>
<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" class="btn-background"/>
<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" class="btn-foreground"/>
</svg>
</div>
<div id="background"> <div id="background">
<div class='wave one'></div> <div class='wave one'></div>
<div class='wave two'></div> <div class='wave two'></div>
@ -77,11 +75,11 @@
<div id="loader" class="loader"></div> <div id="loader" class="loader"></div>
<div id="status" class="status"></div> <div id="status" class="status"></div>
<div id="menubar" class="menubar"> <div id="menubar" class="menubar">
<span class="button button-display" id="btnDisplay">Display<br>Options</span> <div id="btnDisplay" class="icon"><div class="icon-binoculars"> </div>display options</div>
<span class="button button-image" id="btnImage">Image<br>Processing</span> <div id="btnImage" class="icon"><div class="icon-brush"></div>image processing</div>
<span class="button button-process" id="btnProcess">Model<br>Processing</span> <div id="btnProcess" class="icon"><div class="icon-stats"></div>model processing</div>
<span class="button button-model" id="btnModel">Model<br>Selection</span> <div id="btnModel" class="icon"><div class="icon-games"></div>model selection</div>
<span class="button button-start" id="btnStart">Start<br>Video</span> <div id="btnStart" class="icon"><div class="icon-webcam"></div><span id="btnStartText">start video</span></div>
</div> </div>
<div id="media"> <div id="media">
<canvas id="canvas" class="canvas"></canvas> <canvas id="canvas" class="canvas"></canvas>

View File

@ -196,9 +196,6 @@ async function drawResults(input) {
async function setupCamera() { async function setupCamera() {
if (ui.busy) return null; if (ui.busy) return null;
ui.busy = true; 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 video = document.getElementById('video');
const canvas = document.getElementById('canvas'); const canvas = document.getElementById('canvas');
const output = document.getElementById('log'); const output = document.getElementById('log');
@ -411,8 +408,7 @@ async function detectVideo() {
const canvas = document.getElementById('canvas'); const canvas = document.getElementById('canvas');
if ((video.srcObject !== null) && !video.paused) { if ((video.srcObject !== null) && !video.paused) {
document.getElementById('play').style.display = 'block'; document.getElementById('play').style.display = 'block';
document.getElementById('btnStart').className = 'button button-start'; document.getElementById('btnStartText').innerHTML = 'start video';
document.getElementById('btnStart').innerHTML = 'start<br>video';
status('paused'); status('paused');
video.pause(); video.pause();
} else { } else {
@ -421,8 +417,7 @@ async function detectVideo() {
document.getElementById('play').style.display = 'none'; document.getElementById('play').style.display = 'none';
for (const m of Object.values(menu)) m.hide(); for (const m of Object.values(menu)) m.hide();
status(''); status('');
document.getElementById('btnStart').className = 'button button-stop'; document.getElementById('btnStartText').innerHTML = 'pause video';
document.getElementById('btnStart').innerHTML = 'pause<br>video';
await video.play(); await video.play();
if (!ui.detectThread) runHumanDetect(video, canvas); if (!ui.detectThread) runHumanDetect(video, canvas);
} else { } else {
@ -446,16 +441,10 @@ async function detectSampleImages() {
} }
function setupMenu() { function setupMenu() {
let x = []; const x = [`${document.getElementById('btnDisplay').offsetLeft}px`, `${document.getElementById('btnImage').offsetLeft}px`, `${document.getElementById('btnProcess').offsetLeft}px`, `${document.getElementById('btnModel').offsetLeft}px`];
if (window.innerWidth > 800) { const top = `${document.getElementById('menubar').offsetHeight - 3}px`;
// initial position of menu items, later it's calculated based on mouse coordinates
x = [`${document.getElementById('btnDisplay').offsetLeft - 50}px`, `${document.getElementById('btnImage').offsetLeft - 50}px`, `${document.getElementById('btnProcess').offsetLeft - 50}px`, `${document.getElementById('btnModel').offsetLeft - 50}px`];
} else {
// absolute minimum spacing for menus
x = ['0rem', '11rem', '21.1rem', '33rem'];
}
menu.display = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[0] }); menu.display = new Menu(document.body, '', { top, left: x[0] });
menu.display.addBool('perf monitor', ui, 'bench', (val) => ui.bench = val); menu.display.addBool('perf monitor', ui, 'bench', (val) => ui.bench = val);
menu.display.addBool('buffered output', ui, 'buffered', (val) => ui.buffered = val); menu.display.addBool('buffered output', ui, 'buffered', (val) => ui.buffered = val);
menu.display.addBool('crop & scale', ui, 'crop', (val) => { menu.display.addBool('crop & scale', ui, 'crop', (val) => {
@ -475,7 +464,7 @@ function setupMenu() {
menu.display.addBool('draw polygons', human.draw.options, 'drawPolygons'); menu.display.addBool('draw polygons', human.draw.options, 'drawPolygons');
menu.display.addBool('fill polygons', human.draw.options, 'fillPolygons'); menu.display.addBool('fill polygons', human.draw.options, 'fillPolygons');
menu.image = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[1] }); menu.image = new Menu(document.body, '', { top, left: x[1] });
menu.image.addBool('enabled', human.config.filter, 'enabled', (val) => human.config.filter.enabled = val); menu.image.addBool('enabled', human.config.filter, 'enabled', (val) => human.config.filter.enabled = val);
ui.menuWidth = menu.image.addRange('image width', human.config.filter, 'width', 0, 3840, 10, (val) => human.config.filter.width = parseInt(val)); ui.menuWidth = menu.image.addRange('image width', human.config.filter, 'width', 0, 3840, 10, (val) => human.config.filter.width = parseInt(val));
ui.menuHeight = menu.image.addRange('image height', human.config.filter, 'height', 0, 2160, 10, (val) => human.config.filter.height = parseInt(val)); ui.menuHeight = menu.image.addRange('image height', human.config.filter, 'height', 0, 2160, 10, (val) => human.config.filter.height = parseInt(val));
@ -495,7 +484,7 @@ function setupMenu() {
menu.image.addBool('technicolor', human.config.filter, 'technicolor', (val) => human.config.filter.technicolor = val); menu.image.addBool('technicolor', human.config.filter, 'technicolor', (val) => human.config.filter.technicolor = val);
menu.image.addBool('polaroid', human.config.filter, 'polaroid', (val) => human.config.filter.polaroid = val); menu.image.addBool('polaroid', human.config.filter, 'polaroid', (val) => human.config.filter.polaroid = val);
menu.process = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[2] }); menu.process = new Menu(document.body, '', { top, left: x[2] });
menu.process.addList('backend', ['cpu', 'webgl', 'wasm', 'humangl'], human.config.backend, (val) => human.config.backend = val); menu.process.addList('backend', ['cpu', 'webgl', 'wasm', 'humangl'], human.config.backend, (val) => human.config.backend = val);
menu.process.addBool('async operations', human.config, 'async', (val) => human.config.async = val); menu.process.addBool('async operations', human.config, 'async', (val) => human.config.async = val);
// menu.process.addBool('enable profiler', human.config, 'profile', (val) => human.config.profile = val); // menu.process.addBool('enable profiler', human.config, 'profile', (val) => human.config.profile = val);
@ -538,7 +527,7 @@ function setupMenu() {
menu.process.addHTML('<hr style="border-style: inset; border-color: dimgray">'); menu.process.addHTML('<hr style="border-style: inset; border-color: dimgray">');
menu.process.addChart('FPS', 'FPS'); menu.process.addChart('FPS', 'FPS');
menu.models = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[3] }); menu.models = new Menu(document.body, '', { top, left: x[3] });
menu.models.addBool('face detect', human.config.face, 'enabled', (val) => human.config.face.enabled = val); menu.models.addBool('face detect', human.config.face, 'enabled', (val) => human.config.face.enabled = val);
menu.models.addBool('face mesh', human.config.face.mesh, 'enabled', (val) => human.config.face.mesh.enabled = val); menu.models.addBool('face mesh', human.config.face.mesh, 'enabled', (val) => human.config.face.mesh.enabled = val);
menu.models.addBool('face iris', human.config.face.iris, 'enabled', (val) => human.config.face.iris.enabled = val); menu.models.addBool('face iris', human.config.face.iris, 'enabled', (val) => human.config.face.iris.enabled = val);
@ -567,6 +556,21 @@ function setupMenu() {
document.getElementById('play').addEventListener('click', () => detectVideo()); document.getElementById('play').addEventListener('click', () => detectVideo());
} }
async function resize() {
const x = [`${document.getElementById('btnDisplay').offsetLeft}px`, `${document.getElementById('btnImage').offsetLeft}px`, `${document.getElementById('btnProcess').offsetLeft}px`, `${document.getElementById('btnModel').offsetLeft}px`];
menu.display.menu.style.left = x[0];
menu.image.menu.style.left = x[1];
menu.process.menu.style.left = x[2];
menu.models.menu.style.left = x[3];
const viewportScale = Math.min(1, Math.round(100 * window.innerWidth / 960) / 100);
const viewport = document.querySelector('meta[name=viewport]');
viewport.setAttribute('content', `width=device-width, shrink-to-fit=yes, minimum-scale=0.2, maximum-scale=2.0, user-scalable=yes, initial-scale=${viewportScale}`);
// console.log('view', viewportScale, window.innerWidth, viewport);
// document.body.style.MozTransform = `scale(${viewportScale})`;
// document.body.style.zoom = `scale(${viewportScale})`;
setupCamera();
}
async function drawWarmup(res) { async function drawWarmup(res) {
const canvas = document.getElementById('canvas'); const canvas = document.getElementById('canvas');
canvas.width = res.canvas.width; canvas.width = res.canvas.width;
@ -607,7 +611,8 @@ async function main() {
} }
// setup main menu // setup main menu
setupMenu(); await setupMenu();
await resize();
document.getElementById('log').innerText = `Human: version ${human.version}`; document.getElementById('log').innerText = `Human: version ${human.version}`;
// preload models // preload models
@ -636,4 +641,4 @@ async function main() {
} }
window.onload = main; window.onload = main;
window.onresize = setupCamera; window.onresize = resize;

2
wiki

@ -1 +1 @@
Subproject commit 458f02833206e3a6ee1c76652d9e8048530f0708 Subproject commit ddf8fb116b159dc3dabea4cb858b608fa5914355