mirror of https://github.com/vladmandic/human
new serve module and demo structure
parent
f9306abac5
commit
77476652d2
|
@ -11,6 +11,7 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
|
||||||
|
|
||||||
### **HEAD -> main** 2021/03/28 mandic00@live.com
|
### **HEAD -> main** 2021/03/28 mandic00@live.com
|
||||||
|
|
||||||
|
- minor rotation calculation fix
|
||||||
- remove debug output
|
- remove debug output
|
||||||
- new face rotation calculations
|
- new face rotation calculations
|
||||||
- cleanup
|
- cleanup
|
||||||
|
|
|
@ -43,7 +43,7 @@ function log(...msg) {
|
||||||
async function getFaceDB() {
|
async function getFaceDB() {
|
||||||
// download db with known faces
|
// download db with known faces
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/demo/faces.json');
|
const res = await fetch('/demo/facematch-faces.json');
|
||||||
db = (res && res.ok) ? await res.json() : [];
|
db = (res && res.ok) ? await res.json() : [];
|
||||||
for (const rec of db) {
|
for (const rec of db) {
|
||||||
rec.embedding = rec.embedding.map((a) => parseFloat(a.toFixed(4)));
|
rec.embedding = rec.embedding.map((a) => parseFloat(a.toFixed(4)));
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
|
@ -1,3 +1,5 @@
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
let instance = 0;
|
let instance = 0;
|
||||||
let CSScreated = false;
|
let CSScreated = false;
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@ class Menu {
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
instance++;
|
instance++;
|
||||||
this._maxFPS = 0;
|
this._maxFPS = 0;
|
||||||
this.hidden = 0;
|
this.hidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
createMenu(parent, title = '', position = { top: null, left: null, bottom: null, right: null }) {
|
createMenu(parent, title = '', position = { top: null, left: null, bottom: null, right: null }) {
|
||||||
|
@ -109,9 +111,11 @@ class Menu {
|
||||||
if (title) elTitle.innerHTML = `${title}${svg}`;
|
if (title) elTitle.innerHTML = `${title}${svg}`;
|
||||||
this.menu.appendChild(elTitle);
|
this.menu.appendChild(elTitle);
|
||||||
elTitle.addEventListener('click', () => {
|
elTitle.addEventListener('click', () => {
|
||||||
this.container.classList.toggle('menu-container-fadeout');
|
if (this.container && this.menu) {
|
||||||
this.container.classList.toggle('menu-container-fadein');
|
this.container.classList.toggle('menu-container-fadeout');
|
||||||
this.menu.style.borderStyle = this.container.classList.contains('menu-container-fadeout') ? 'none' : 'solid';
|
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);
|
this.menu.appendChild(this.container);
|
||||||
|
@ -129,40 +133,42 @@ class Menu {
|
||||||
}
|
}
|
||||||
|
|
||||||
get width() {
|
get width() {
|
||||||
return this.menu.offsetWidth;
|
return this.menu?.offsetWidth || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get height() {
|
get height() {
|
||||||
return this.menu.offsetHeight;
|
return this.menu?.offsetHeight || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
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-fadeout');
|
||||||
this.container.classList.toggle('menu-container-fadein');
|
this.container.classList.toggle('menu-container-fadein');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visible() {
|
visible() {
|
||||||
return (this.container.classList.contains('menu-container-fadein'));
|
return (this.container ? this.container.classList.contains('menu-container-fadein') : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle(evt) {
|
toggle(evt) {
|
||||||
this.container.classList.toggle('menu-container-fadeout');
|
if (this.container && this.menu) {
|
||||||
this.container.classList.toggle('menu-container-fadein');
|
this.container.classList.toggle('menu-container-fadeout');
|
||||||
if (this.container.classList.contains('menu-container-fadein') && evt) {
|
this.container.classList.toggle('menu-container-fadein');
|
||||||
const x = evt.x || (evt.touches && evt.touches[0] ? evt.touches[0].pageX : null);
|
if (this.container.classList.contains('menu-container-fadein') && evt) {
|
||||||
// const y = evt.y || (evt.touches && evt.touches[0] ? evt.touches[0].pageY : null);
|
const x = evt.x || (evt.touches && evt.touches[0] ? evt.touches[0].pageX : null);
|
||||||
if (x) this.menu.style.left = `${x - (this.menu.offsetWidth / 2)}px`;
|
// const y = evt.y || (evt.touches && evt.touches[0] ? evt.touches[0].pageY : null);
|
||||||
// if (y) this.menu.style.top = '5.5rem'; // `${evt.y + 55}px`;
|
if (x) this.menu.style.left = `${x - (this.menu.offsetWidth / 2)}px`;
|
||||||
if (this.menu.offsetLeft < 0) this.menu.style.left = 0;
|
// if (y) this.menu.style.top = '5.5rem'; // `${evt.y + 55}px`;
|
||||||
if ((this.menu.offsetLeft + this.menu.offsetWidth) > window.innerWidth) {
|
if (this.menu.offsetLeft < 0) this.menu.style.left = '0';
|
||||||
this.menu.style.left = null;
|
if ((this.menu.offsetLeft + this.menu.offsetWidth) > window.innerWidth) {
|
||||||
this.menu.style.right = 0;
|
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.className = 'menu-title';
|
||||||
el.id = this.newID;
|
el.id = this.newID;
|
||||||
el.innerHTML = title;
|
el.innerHTML = title;
|
||||||
this.menu.appendChild(el);
|
if (this.menu) this.menu.appendChild(el);
|
||||||
el.addEventListener('click', () => {
|
el.addEventListener('click', () => {
|
||||||
this.hidden = !this.hidden;
|
this.hidden = !this.hidden;
|
||||||
const all = document.getElementsByClassName('menu');
|
const all = document.getElementsByClassName('menu');
|
||||||
|
@ -187,7 +193,7 @@ class Menu {
|
||||||
el.className = 'menu-item menu-label';
|
el.className = 'menu-item menu-label';
|
||||||
el.id = this.newID;
|
el.id = this.newID;
|
||||||
el.innerHTML = title;
|
el.innerHTML = title;
|
||||||
this.container.appendChild(el);
|
if (this.container) this.container.appendChild(el);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,10 +201,10 @@ class Menu {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'menu-item';
|
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}`;
|
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) => {
|
el.addEventListener('change', (evt) => {
|
||||||
object[variable] = evt.target.checked;
|
object[variable] = evt.target?.checked;
|
||||||
if (callback) callback(evt.target.checked);
|
if (callback) callback(evt.target?.checked);
|
||||||
});
|
});
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
@ -215,9 +221,9 @@ class Menu {
|
||||||
el.style.fontFamily = document.body.style.fontFamily;
|
el.style.fontFamily = document.body.style.fontFamily;
|
||||||
el.style.fontSize = document.body.style.fontSize;
|
el.style.fontSize = document.body.style.fontSize;
|
||||||
el.style.fontVariant = document.body.style.fontVariant;
|
el.style.fontVariant = document.body.style.fontVariant;
|
||||||
this.container.appendChild(el);
|
if (this.container) this.container.appendChild(el);
|
||||||
el.addEventListener('change', (evt) => {
|
el.addEventListener('change', (evt) => {
|
||||||
if (callback) callback(items[evt.target.selectedIndex]);
|
if (callback) callback(items[evt.target?.selectedIndex]);
|
||||||
});
|
});
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
@ -226,11 +232,13 @@ class Menu {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'menu-item';
|
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}`;
|
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) => {
|
el.addEventListener('change', (evt) => {
|
||||||
object[variable] = parseInt(evt.target.value) === parseFloat(evt.target.value) ? parseInt(evt.target.value) : parseFloat(evt.target.value);
|
if (evt.target) {
|
||||||
evt.target.setAttribute('value', evt.target.value);
|
object[variable] = parseInt(evt.target?.value) === parseFloat(evt.target?.value) ? parseInt(evt.target?.value) : parseFloat(evt.target?.value);
|
||||||
if (callback) callback(evt.target.value);
|
evt.target.setAttribute('value', evt.target.value);
|
||||||
|
if (callback) callback(evt.target?.value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
el.input = el.children[0];
|
el.input = el.children[0];
|
||||||
return el;
|
return el;
|
||||||
|
@ -241,7 +249,7 @@ class Menu {
|
||||||
el.className = 'menu-item';
|
el.className = 'menu-item';
|
||||||
el.id = this.newID;
|
el.id = this.newID;
|
||||||
if (html) el.innerHTML = html;
|
if (html) el.innerHTML = html;
|
||||||
this.container.appendChild(el);
|
if (this.container) this.container.appendChild(el);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +262,7 @@ class Menu {
|
||||||
el.type = 'button';
|
el.type = 'button';
|
||||||
el.id = this.newID;
|
el.id = this.newID;
|
||||||
el.innerText = titleOn;
|
el.innerText = titleOn;
|
||||||
this.container.appendChild(el);
|
if (this.container) this.container.appendChild(el);
|
||||||
el.addEventListener('click', () => {
|
el.addEventListener('click', () => {
|
||||||
if (el.innerText === titleOn) el.innerText = titleOff;
|
if (el.innerText === titleOn) el.innerText = titleOff;
|
||||||
else el.innerText = titleOn;
|
else el.innerText = titleOn;
|
||||||
|
@ -268,7 +276,7 @@ class Menu {
|
||||||
el.className = 'menu-item';
|
el.className = 'menu-item';
|
||||||
el.id = `menu-val-${title}`;
|
el.id = `menu-val-${title}`;
|
||||||
el.innerText = `${title}: ${val}${suffix}`;
|
el.innerText = `${title}: ${val}${suffix}`;
|
||||||
this.container.appendChild(el);
|
if (this.container) this.container.appendChild(el);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +293,7 @@ class Menu {
|
||||||
el.className = 'menu-item menu-chart-title';
|
el.className = 'menu-item menu-chart-title';
|
||||||
el.id = this.newID;
|
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>`;
|
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;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
<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">
|
||||||
<!-- load compiled demo js -->
|
<!-- 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 -->
|
<!-- alternatively load demo sources directly -->
|
||||||
<!-- <script src="./browser.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'); }
|
@font-face { font-family: 'FA'; font-display: swap; font-style: normal; font-weight: 900; src: local('FA'), url('../assets/fa-solid-900.woff2'); }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// import Human from '../dist/human.esm.js'; // equivalent of @vladmandic/human
|
import Human from '../dist/human.esm.js'; // equivalent of @vladmandic/human
|
||||||
import Human from '../src/human';
|
// import Human from '../src/human'; // import sources directly
|
||||||
import Menu from './menu.js';
|
import Menu from './helpers/menu.js';
|
||||||
import GLBench from './gl-bench.js';
|
import GLBench from './helpers/gl-bench.js';
|
||||||
|
|
||||||
const userConfig = { backend: 'webgl' }; // add any user configuration overrides
|
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
|
columns: 2, // when processing sample images create this many columns
|
||||||
facing: true, // camera facing front or back
|
facing: true, // camera facing front or back
|
||||||
useWorker: false, // use web workers for processing
|
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'],
|
samples: ['../assets/sample6.jpg', '../assets/sample1.jpg', '../assets/sample4.jpg', '../assets/sample5.jpg', '../assets/sample3.jpg', '../assets/sample2.jpg'],
|
||||||
compare: '../assets/sample-me.jpg',
|
compare: '../assets/sample-me.jpg',
|
||||||
console: true, // log messages to browser console
|
console: true, // log messages to browser console
|
|
@ -57,12 +57,12 @@
|
||||||
"@tensorflow/tfjs-node": "^3.3.0",
|
"@tensorflow/tfjs-node": "^3.3.0",
|
||||||
"@tensorflow/tfjs-node-gpu": "^3.3.0",
|
"@tensorflow/tfjs-node-gpu": "^3.3.0",
|
||||||
"@types/node": "^14.14.37",
|
"@types/node": "^14.14.37",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.19.0",
|
"@typescript-eslint/eslint-plugin": "^4.20.0",
|
||||||
"@typescript-eslint/parser": "^4.19.0",
|
"@typescript-eslint/parser": "^4.20.0",
|
||||||
"@vladmandic/pilogger": "^0.2.15",
|
"@vladmandic/pilogger": "^0.2.15",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"esbuild": "^0.10.2",
|
"esbuild": "^0.11.0",
|
||||||
"eslint": "^7.23.0",
|
"eslint": "^7.23.0",
|
||||||
"eslint-config-airbnb-base": "^14.2.1",
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.22.1",
|
||||||
|
|
|
@ -255,7 +255,8 @@ const config: Config = {
|
||||||
|
|
||||||
body: {
|
body: {
|
||||||
enabled: true,
|
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
|
maxDetections: 10, // maximum number of people detected in the input
|
||||||
// should be set to the minimum number for performance
|
// should be set to the minimum number for performance
|
||||||
// only valid for posenet as blazepose only detects single pose
|
// only valid for posenet as blazepose only detects single pose
|
||||||
|
@ -296,6 +297,7 @@ const config: Config = {
|
||||||
object: {
|
object: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
modelPath: '../models/nanodet.json',
|
modelPath: '../models/nanodet.json',
|
||||||
|
// 'nanodet' is experimental
|
||||||
minConfidence: 0.20, // threshold for discarding a prediction
|
minConfidence: 0.20, // threshold for discarding a prediction
|
||||||
iouThreshold: 0.40, // threshold for deciding whether boxes overlap too much
|
iouThreshold: 0.40, // threshold for deciding whether boxes overlap too much
|
||||||
// in non-maximum suppression
|
// in non-maximum suppression
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
"allowJs": true
|
"allowJs": true
|
||||||
},
|
},
|
||||||
"formatCodeOptions": { "indentSize": 2, "tabSize": 2 },
|
"formatCodeOptions": { "indentSize": 2, "tabSize": 2 },
|
||||||
"include": ["src/*", "src/***/*", "demo/*"],
|
"include": ["src/*", "src/***/*", "demo/*", "demo/helpers/gl-bench.js", "demo/helpers/menu.js"],
|
||||||
"typedocOptions": {
|
"typedocOptions": {
|
||||||
"excludePrivate": true,
|
"excludePrivate": true,
|
||||||
"excludeExternals": true,
|
"excludeExternals": true,
|
||||||
|
|
2
wiki
2
wiki
|
@ -1 +1 @@
|
||||||
Subproject commit aae30ba3904eb7d76847895e11c55926e35ad00b
|
Subproject commit df23c6e6fdd3aedd5da6ee08d90d61983a761e91
|
Loading…
Reference in New Issue