new serve module and demo structure

pull/293/head
Vladimir Mandic 2021-03-29 14:40:34 -04:00
parent f9306abac5
commit 77476652d2
14 changed files with 62 additions and 51 deletions

View File

@ -11,6 +11,7 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
### **HEAD -> main** 2021/03/28 mandic00@live.com
- minor rotation calculation fix
- remove debug output
- new face rotation calculations
- cleanup

View File

@ -43,7 +43,7 @@ function log(...msg) {
async function getFaceDB() {
// download db with known faces
try {
const res = await fetch('/demo/faces.json');
const res = await fetch('/demo/facematch-faces.json');
db = (res && res.ok) ? await res.json() : [];
for (const rec of db) {
rec.embedding = rec.embedding.map((a) => parseFloat(a.toFixed(4)));

BIN
demo/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,3 +1,5 @@
// @ts-nocheck
let instance = 0;
let CSScreated = false;
@ -80,7 +82,7 @@ class Menu {
this.instance = instance;
instance++;
this._maxFPS = 0;
this.hidden = 0;
this.hidden = false;
}
createMenu(parent, title = '', position = { top: null, left: null, bottom: null, right: null }) {
@ -109,9 +111,11 @@ class Menu {
if (title) elTitle.innerHTML = `${title}${svg}`;
this.menu.appendChild(elTitle);
elTitle.addEventListener('click', () => {
this.container.classList.toggle('menu-container-fadeout');
this.container.classList.toggle('menu-container-fadein');
this.menu.style.borderStyle = this.container.classList.contains('menu-container-fadeout') ? 'none' : 'solid';
if (this.container && this.menu) {
this.container.classList.toggle('menu-container-fadeout');
this.container.classList.toggle('menu-container-fadein');
this.menu.style.borderStyle = this.container.classList.contains('menu-container-fadeout') ? 'none' : 'solid';
}
});
this.menu.appendChild(this.container);
@ -129,40 +133,42 @@ class Menu {
}
get width() {
return this.menu.offsetWidth;
return this.menu?.offsetWidth || 0;
}
get height() {
return this.menu.offsetHeight;
return this.menu?.offsetHeight || 0;
}
hide() {
if (this.container.classList.contains('menu-container-fadein')) {
if (this.container && this.container.classList.contains('menu-container-fadein')) {
this.container.classList.toggle('menu-container-fadeout');
this.container.classList.toggle('menu-container-fadein');
}
}
visible() {
return (this.container.classList.contains('menu-container-fadein'));
return (this.container ? this.container.classList.contains('menu-container-fadein') : false);
}
toggle(evt) {
this.container.classList.toggle('menu-container-fadeout');
this.container.classList.toggle('menu-container-fadein');
if (this.container.classList.contains('menu-container-fadein') && evt) {
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);
if (x) this.menu.style.left = `${x - (this.menu.offsetWidth / 2)}px`;
// if (y) this.menu.style.top = '5.5rem'; // `${evt.y + 55}px`;
if (this.menu.offsetLeft < 0) this.menu.style.left = 0;
if ((this.menu.offsetLeft + this.menu.offsetWidth) > window.innerWidth) {
this.menu.style.left = null;
this.menu.style.right = 0;
if (this.container && this.menu) {
this.container.classList.toggle('menu-container-fadeout');
this.container.classList.toggle('menu-container-fadein');
if (this.container.classList.contains('menu-container-fadein') && evt) {
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);
if (x) this.menu.style.left = `${x - (this.menu.offsetWidth / 2)}px`;
// if (y) this.menu.style.top = '5.5rem'; // `${evt.y + 55}px`;
if (this.menu.offsetLeft < 0) this.menu.style.left = '0';
if ((this.menu.offsetLeft + this.menu.offsetWidth) > window.innerWidth) {
this.menu.style.left = '';
this.menu.style.right = '0';
}
this.menu.style.borderStyle = 'solid';
} else {
this.menu.style.borderStyle = 'none';
}
this.menu.style.borderStyle = 'solid';
} else {
this.menu.style.borderStyle = 'none';
}
}
@ -171,7 +177,7 @@ class Menu {
el.className = 'menu-title';
el.id = this.newID;
el.innerHTML = title;
this.menu.appendChild(el);
if (this.menu) this.menu.appendChild(el);
el.addEventListener('click', () => {
this.hidden = !this.hidden;
const all = document.getElementsByClassName('menu');
@ -187,7 +193,7 @@ class Menu {
el.className = 'menu-item menu-label';
el.id = this.newID;
el.innerHTML = title;
this.container.appendChild(el);
if (this.container) this.container.appendChild(el);
return el;
}
@ -195,10 +201,10 @@ class Menu {
const el = document.createElement('div');
el.className = 'menu-item';
el.innerHTML = `<div class="menu-checkbox"><input class="menu-checkbox" type="checkbox" id="${this.newID}" ${object[variable] ? 'checked' : ''}/><label class="menu-checkbox-label" for="${this.ID}"></label></div>${title}`;
this.container.appendChild(el);
if (this.container) this.container.appendChild(el);
el.addEventListener('change', (evt) => {
object[variable] = evt.target.checked;
if (callback) callback(evt.target.checked);
object[variable] = evt.target?.checked;
if (callback) callback(evt.target?.checked);
});
return el;
}
@ -215,9 +221,9 @@ class Menu {
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);
if (this.container) this.container.appendChild(el);
el.addEventListener('change', (evt) => {
if (callback) callback(items[evt.target.selectedIndex]);
if (callback) callback(items[evt.target?.selectedIndex]);
});
return el;
}
@ -226,11 +232,13 @@ class Menu {
const el = document.createElement('div');
el.className = 'menu-item';
el.innerHTML = `<input class="menu-range" type="range" id="${this.newID}" min="${min}" max="${max}" step="${step}" value="${object[variable]}">${title}`;
this.container.appendChild(el);
if (this.container) this.container.appendChild(el);
el.addEventListener('change', (evt) => {
object[variable] = parseInt(evt.target.value) === parseFloat(evt.target.value) ? parseInt(evt.target.value) : parseFloat(evt.target.value);
evt.target.setAttribute('value', evt.target.value);
if (callback) callback(evt.target.value);
if (evt.target) {
object[variable] = parseInt(evt.target?.value) === parseFloat(evt.target?.value) ? parseInt(evt.target?.value) : parseFloat(evt.target?.value);
evt.target.setAttribute('value', evt.target.value);
if (callback) callback(evt.target?.value);
}
});
el.input = el.children[0];
return el;
@ -241,7 +249,7 @@ class Menu {
el.className = 'menu-item';
el.id = this.newID;
if (html) el.innerHTML = html;
this.container.appendChild(el);
if (this.container) this.container.appendChild(el);
return el;
}
@ -254,7 +262,7 @@ class Menu {
el.type = 'button';
el.id = this.newID;
el.innerText = titleOn;
this.container.appendChild(el);
if (this.container) this.container.appendChild(el);
el.addEventListener('click', () => {
if (el.innerText === titleOn) el.innerText = titleOff;
else el.innerText = titleOn;
@ -268,7 +276,7 @@ class Menu {
el.className = 'menu-item';
el.id = `menu-val-${title}`;
el.innerText = `${title}: ${val}${suffix}`;
this.container.appendChild(el);
if (this.container) this.container.appendChild(el);
return el;
}
@ -285,7 +293,7 @@ class Menu {
el.className = 'menu-item menu-chart-title';
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);
if (this.container) this.container.appendChild(el);
return el;
}

View File

@ -14,9 +14,9 @@
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="../assets/icon.png">
<!-- load compiled demo js -->
<script src="../dist/demo-browser-index.js"></script>
<!-- <script src="../dist/demo-browser-index.js"></script> -->
<!-- alternatively load demo sources directly -->
<!-- <script src="./browser.js" type="module"></script> -->
<script src="./index.js" type="module"></script>
<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: 'FA'; font-display: swap; font-style: normal; font-weight: 900; src: local('FA'), url('../assets/fa-solid-900.woff2'); }

View File

@ -1,7 +1,7 @@
// import Human from '../dist/human.esm.js'; // equivalent of @vladmandic/human
import Human from '../src/human';
import Menu from './menu.js';
import GLBench from './gl-bench.js';
import Human from '../dist/human.esm.js'; // equivalent of @vladmandic/human
// import Human from '../src/human'; // import sources directly
import Menu from './helpers/menu.js';
import GLBench from './helpers/gl-bench.js';
const userConfig = { backend: 'webgl' }; // add any user configuration overrides
@ -37,7 +37,7 @@ const ui = {
columns: 2, // when processing sample images create this many columns
facing: true, // camera facing front or back
useWorker: false, // use web workers for processing
worker: 'worker.js',
worker: 'index-worker.js',
samples: ['../assets/sample6.jpg', '../assets/sample1.jpg', '../assets/sample4.jpg', '../assets/sample5.jpg', '../assets/sample3.jpg', '../assets/sample2.jpg'],
compare: '../assets/sample-me.jpg',
console: true, // log messages to browser console

View File

@ -57,12 +57,12 @@
"@tensorflow/tfjs-node": "^3.3.0",
"@tensorflow/tfjs-node-gpu": "^3.3.0",
"@types/node": "^14.14.37",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"@typescript-eslint/eslint-plugin": "^4.20.0",
"@typescript-eslint/parser": "^4.20.0",
"@vladmandic/pilogger": "^0.2.15",
"chokidar": "^3.5.1",
"dayjs": "^1.10.4",
"esbuild": "^0.10.2",
"esbuild": "^0.11.0",
"eslint": "^7.23.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.22.1",

View File

@ -255,7 +255,8 @@ const config: Config = {
body: {
enabled: true,
modelPath: '../models/posenet.json', // can be 'posenet' or 'blazepose'
modelPath: '../models/posenet.json', // can be 'posenet', 'blazepose' or 'efficientpose'
// 'blazepose' and 'efficientpose' are experimental
maxDetections: 10, // maximum number of people detected in the input
// should be set to the minimum number for performance
// only valid for posenet as blazepose only detects single pose
@ -296,6 +297,7 @@ const config: Config = {
object: {
enabled: false,
modelPath: '../models/nanodet.json',
// 'nanodet' is experimental
minConfidence: 0.20, // threshold for discarding a prediction
iouThreshold: 0.40, // threshold for deciding whether boxes overlap too much
// in non-maximum suppression

View File

@ -21,7 +21,7 @@
"allowJs": true
},
"formatCodeOptions": { "indentSize": 2, "tabSize": 2 },
"include": ["src/*", "src/***/*", "demo/*"],
"include": ["src/*", "src/***/*", "demo/*", "demo/helpers/gl-bench.js", "demo/helpers/menu.js"],
"typedocOptions": {
"excludePrivate": true,
"excludeExternals": true,

2
wiki

@ -1 +1 @@
Subproject commit aae30ba3904eb7d76847895e11c55926e35ad00b
Subproject commit df23c6e6fdd3aedd5da6ee08d90d61983a761e91