mirror of https://github.com/vladmandic/human
ui redesign
parent
77e73b8dfd
commit
26fbe21ab0
|
@ -21,12 +21,17 @@
|
||||||
],
|
],
|
||||||
"ignorePatterns": [ "dist", "assets", "media", "models", "node_modules" ],
|
"ignorePatterns": [ "dist", "assets", "media", "models", "node_modules" ],
|
||||||
"rules": {
|
"rules": {
|
||||||
"max-len": [1, 275, 3],
|
|
||||||
"camelcase": "off",
|
"camelcase": "off",
|
||||||
"guard-for-in": "off",
|
"dot-notation": "off",
|
||||||
"prefer-template":"off",
|
|
||||||
"import/extensions": "off",
|
|
||||||
"func-names": "off",
|
"func-names": "off",
|
||||||
|
"guard-for-in": "off",
|
||||||
|
"import/extensions": "off",
|
||||||
|
"import/no-absolute-path": "off",
|
||||||
|
"import/no-extraneous-dependencies": "off",
|
||||||
|
"import/prefer-default-export": "off",
|
||||||
|
"max-len": [1, 275, 3],
|
||||||
|
"newline-per-chained-call": "off",
|
||||||
|
"no-async-promise-executor": "off",
|
||||||
"no-await-in-loop": "off",
|
"no-await-in-loop": "off",
|
||||||
"no-bitwise": "off",
|
"no-bitwise": "off",
|
||||||
"no-case-declarations":"off",
|
"no-case-declarations":"off",
|
||||||
|
@ -35,25 +40,21 @@
|
||||||
"no-mixed-operators": "off",
|
"no-mixed-operators": "off",
|
||||||
"no-param-reassign":"off",
|
"no-param-reassign":"off",
|
||||||
"no-plusplus": "off",
|
"no-plusplus": "off",
|
||||||
"dot-notation": "off",
|
"no-regex-spaces": "off",
|
||||||
"no-restricted-globals": "off",
|
"no-restricted-globals": "off",
|
||||||
"no-restricted-syntax": "off",
|
"no-restricted-syntax": "off",
|
||||||
"no-underscore-dangle": "off",
|
|
||||||
"no-return-assign": "off",
|
"no-return-assign": "off",
|
||||||
"newline-per-chained-call": "off",
|
"no-underscore-dangle": "off",
|
||||||
|
"node/no-unpublished-import": "off",
|
||||||
|
"node/no-unpublished-require": "off",
|
||||||
"node/no-unsupported-features/es-syntax": "off",
|
"node/no-unsupported-features/es-syntax": "off",
|
||||||
"node/shebang": "off",
|
"node/shebang": "off",
|
||||||
"object-curly-newline": "off",
|
"object-curly-newline": "off",
|
||||||
"prefer-destructuring": "off",
|
"prefer-destructuring": "off",
|
||||||
|
"prefer-template":"off",
|
||||||
"promise/always-return": "off",
|
"promise/always-return": "off",
|
||||||
"promise/catch-or-return": "off",
|
"promise/catch-or-return": "off",
|
||||||
"promise/no-nesting": "off",
|
"promise/no-nesting": "off",
|
||||||
"no-async-promise-executor": "off",
|
|
||||||
"import/no-absolute-path": "off",
|
|
||||||
"import/no-extraneous-dependencies": "off",
|
|
||||||
"node/no-unpublished-import": "off",
|
|
||||||
"node/no-unpublished-require": "off",
|
|
||||||
"no-regex-spaces": "off",
|
|
||||||
"radix": "off"
|
"radix": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
252
demo/browser.js
252
demo/browser.js
|
@ -1,7 +1,7 @@
|
||||||
import Human from '../dist/human.esm.js';
|
import Human from '../dist/human.esm.js';
|
||||||
import draw from './draw.js';
|
import draw from './draw.js';
|
||||||
import Menu from './menu.js';
|
import Menu from './menu.js';
|
||||||
import GLBench from '../assets/gl-bench.js';
|
import GLBench from './gl-bench.js';
|
||||||
|
|
||||||
const userConfig = {}; // add any user configuration overrides
|
const userConfig = {}; // add any user configuration overrides
|
||||||
|
|
||||||
|
@ -11,10 +11,9 @@ const human = new Human(userConfig);
|
||||||
const ui = {
|
const ui = {
|
||||||
baseColor: 'rgba(173, 216, 230, 0.3)', // 'lightblue' with light alpha channel
|
baseColor: 'rgba(173, 216, 230, 0.3)', // 'lightblue' with light alpha channel
|
||||||
baseBackground: 'rgba(50, 50, 50, 1)', // 'grey'
|
baseBackground: 'rgba(50, 50, 50, 1)', // 'grey'
|
||||||
baseLabel: 'rgba(173, 216, 230, 0.9)', // 'lightblue' with dark alpha channel
|
baseLabel: 'rgba(173, 216, 230, 1)', // 'lightblue' with dark alpha channel
|
||||||
baseFontProto: 'small-caps {size} "Segoe UI"',
|
baseFontProto: 'small-caps {size} "Segoe UI"',
|
||||||
baseLineWidth: 12,
|
baseLineWidth: 12,
|
||||||
baseLineHeightProto: 2,
|
|
||||||
crop: true,
|
crop: true,
|
||||||
columns: 2,
|
columns: 2,
|
||||||
busy: false,
|
busy: false,
|
||||||
|
@ -38,7 +37,6 @@ const ui = {
|
||||||
detectFPS: [],
|
detectFPS: [],
|
||||||
drawFPS: [],
|
drawFPS: [],
|
||||||
buffered: false,
|
buffered: false,
|
||||||
bufferedFPSTarget: 0,
|
|
||||||
drawThread: null,
|
drawThread: null,
|
||||||
detectThread: null,
|
detectThread: null,
|
||||||
framesDraw: 0,
|
framesDraw: 0,
|
||||||
|
@ -47,11 +45,9 @@ const ui = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// global variables
|
// global variables
|
||||||
let menu;
|
const menu = {};
|
||||||
let menuFX;
|
|
||||||
let worker;
|
let worker;
|
||||||
let bench;
|
let bench;
|
||||||
let sample;
|
|
||||||
let lastDetectedResult = {};
|
let lastDetectedResult = {};
|
||||||
|
|
||||||
// helper function: translates json to human readable string
|
// helper function: translates json to human readable string
|
||||||
|
@ -78,14 +74,16 @@ const status = (msg) => {
|
||||||
document.getElementById('status').innerText = msg;
|
document.getElementById('status').innerText = msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function calcSimmilariry(faces) {
|
let original;
|
||||||
if (!faces || !faces[0] || (faces[0].embedding?.length !== 192)) return;
|
async function calcSimmilariry(result) {
|
||||||
const current = faces[0].embedding;
|
document.getElementById('compare-container').style.display = human.config.face.embedding.enabled ? 'block' : 'none';
|
||||||
const original = (sample && sample.face && sample.face[0] && sample.face[0].embedding) ? sample.face[0].embedding : null;
|
if ((result?.face?.length > 0) && (result?.face[0].embedding?.length !== 192)) return;
|
||||||
if (original && original.length === 192) {
|
if (!original) {
|
||||||
const simmilarity = human.simmilarity(current, original);
|
original = result;
|
||||||
document.getElementById('simmilarity').innerText = `simmilarity: ${Math.trunc(1000 * simmilarity) / 10}%`;
|
document.getElementById('compare-canvas').getContext('2d').drawImage(original.canvas, 0, 0, 200, 200);
|
||||||
}
|
}
|
||||||
|
const simmilarity = human.simmilarity(original.face[0].embedding, result.face[0].embedding);
|
||||||
|
document.getElementById('simmilarity').innerText = `simmilarity: ${Math.trunc(1000 * simmilarity) / 10}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// draws processed results and starts processing of a next frame
|
// draws processed results and starts processing of a next frame
|
||||||
|
@ -103,7 +101,7 @@ async function drawResults(input) {
|
||||||
// console.log(result.performance);
|
// console.log(result.performance);
|
||||||
|
|
||||||
// draw fps chart
|
// draw fps chart
|
||||||
await menu.updateChart('FPS', ui.detectFPS);
|
await menu.process.updateChart('FPS', ui.detectFPS);
|
||||||
|
|
||||||
// get updated canvas
|
// get updated canvas
|
||||||
if (ui.buffered || !result.canvas) result.canvas = await human.image(input, userConfig);
|
if (ui.buffered || !result.canvas) result.canvas = await human.image(input, userConfig);
|
||||||
|
@ -125,7 +123,7 @@ async function drawResults(input) {
|
||||||
await draw.body(result.body, canvas, ui);
|
await draw.body(result.body, canvas, ui);
|
||||||
await draw.hand(result.hand, canvas, ui);
|
await draw.hand(result.hand, canvas, ui);
|
||||||
await draw.gesture(result.gesture, canvas, ui);
|
await draw.gesture(result.gesture, canvas, ui);
|
||||||
await calcSimmilariry(result.face);
|
await calcSimmilariry(result);
|
||||||
|
|
||||||
// update log
|
// update log
|
||||||
const engine = human.tf.engine();
|
const engine = human.tf.engine();
|
||||||
|
@ -145,14 +143,11 @@ async function drawResults(input) {
|
||||||
ui.framesDraw++;
|
ui.framesDraw++;
|
||||||
ui.lastFrame = performance.now();
|
ui.lastFrame = performance.now();
|
||||||
// if buffered, immediate loop but limit frame rate although it's going to run slower as JS is singlethreaded
|
// if buffered, immediate loop but limit frame rate although it's going to run slower as JS is singlethreaded
|
||||||
if ((ui.bufferedFPSTarget === 0) && ui.buffered) {
|
if (ui.buffered) {
|
||||||
ui.drawThread = requestAnimationFrame(() => drawResults(input, canvas));
|
ui.drawThread = requestAnimationFrame(() => drawResults(input, canvas));
|
||||||
} else if ((ui.bufferedFPSTarget === 0) && ui.buffered && !ui.drawThread) {
|
|
||||||
log('starting buffered refresh');
|
|
||||||
if (ui.bufferedFPSTarget > 0) ui.drawThread = setInterval(() => drawResults(input, canvas), 1000 / ui.bufferedFPSTarget);
|
|
||||||
} else if (!ui.buffered && ui.drawThread) {
|
} else if (!ui.buffered && ui.drawThread) {
|
||||||
log('stopping buffered refresh');
|
log('stopping buffered refresh');
|
||||||
clearTimeout(ui.drawThread);
|
cancelAnimationFrame(ui.drawThread);
|
||||||
ui.drawThread = null;
|
ui.drawThread = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +176,7 @@ async function setupCamera() {
|
||||||
video: { facingMode: ui.facing ? 'user' : 'environment', resizeMode: ui.crop ? 'crop-and-scale' : 'none' },
|
video: { facingMode: ui.facing ? 'user' : 'environment', resizeMode: ui.crop ? 'crop-and-scale' : 'none' },
|
||||||
};
|
};
|
||||||
if (window.innerWidth > window.innerHeight) constraints.video.width = { ideal: window.innerWidth };
|
if (window.innerWidth > window.innerHeight) constraints.video.width = { ideal: window.innerWidth };
|
||||||
else constraints.video.height = { ideal: window.innerHeight };
|
else constraints.video.height = { ideal: (window.innerHeight - document.getElementById('menubar').offsetHeight) };
|
||||||
try {
|
try {
|
||||||
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -209,8 +204,9 @@ async function setupCamera() {
|
||||||
ui.menuWidth.input.setAttribute('value', video.width);
|
ui.menuWidth.input.setAttribute('value', video.width);
|
||||||
ui.menuHeight.input.setAttribute('value', video.height);
|
ui.menuHeight.input.setAttribute('value', video.height);
|
||||||
// silly font resizing for paint-on-canvas since viewport can be zoomed
|
// silly font resizing for paint-on-canvas since viewport can be zoomed
|
||||||
const size = 14 + (6 * canvas.width / window.innerWidth);
|
const size = Math.trunc(window.devicePixelRatio * (8 + (4 * canvas.width / window.innerWidth)));
|
||||||
ui.baseFont = ui.baseFontProto.replace(/{size}/, `${size}px`);
|
ui.baseFont = ui.baseFontProto.replace(/{size}/, `${size}px`);
|
||||||
|
ui.baseLineHeight = size + 4;
|
||||||
if (live) video.play();
|
if (live) video.play();
|
||||||
// eslint-disable-next-line no-use-before-define
|
// eslint-disable-next-line no-use-before-define
|
||||||
if (live && !ui.detectThread) runHumanDetect(video, canvas);
|
if (live && !ui.detectThread) runHumanDetect(video, canvas);
|
||||||
|
@ -223,6 +219,20 @@ async function setupCamera() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initPerfMonitor() {
|
||||||
|
if (!bench) {
|
||||||
|
const gl = null;
|
||||||
|
// cosnt gl = human.tf.engine().backend.gpgpu.gl;
|
||||||
|
// if (!gl) log('bench cannot get tensorflow webgl context');
|
||||||
|
bench = new GLBench(gl, {
|
||||||
|
trackGPU: false, // this is really slow
|
||||||
|
chartHz: 20,
|
||||||
|
chartLen: 20,
|
||||||
|
});
|
||||||
|
bench.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// wrapper for worker.postmessage that creates worker if one does not exist
|
// wrapper for worker.postmessage that creates worker if one does not exist
|
||||||
function webWorker(input, image, canvas, timestamp) {
|
function webWorker(input, image, canvas, timestamp) {
|
||||||
if (!worker) {
|
if (!worker) {
|
||||||
|
@ -233,8 +243,11 @@ function webWorker(input, image, canvas, timestamp) {
|
||||||
worker.addEventListener('message', (msg) => {
|
worker.addEventListener('message', (msg) => {
|
||||||
if (msg.data.result.performance && msg.data.result.performance.total) ui.detectFPS.push(1000 / msg.data.result.performance.total);
|
if (msg.data.result.performance && msg.data.result.performance.total) ui.detectFPS.push(1000 / msg.data.result.performance.total);
|
||||||
if (ui.detectFPS.length > ui.maxFPSframes) ui.detectFPS.shift();
|
if (ui.detectFPS.length > ui.maxFPSframes) ui.detectFPS.shift();
|
||||||
if (ui.bench) bench.end();
|
if (ui.bench) {
|
||||||
if (ui.bench) bench.nextFrame(timestamp);
|
if (!bench) initPerfMonitor();
|
||||||
|
bench.nextFrame(timestamp);
|
||||||
|
}
|
||||||
|
if (document.getElementById('gl-bench')) document.getElementById('gl-bench').style.display = ui.bench ? 'block' : 'none';
|
||||||
lastDetectedResult = msg.data.result;
|
lastDetectedResult = msg.data.result;
|
||||||
ui.framesDetect++;
|
ui.framesDetect++;
|
||||||
if (!ui.drawThread) drawResults(input);
|
if (!ui.drawThread) drawResults(input);
|
||||||
|
@ -243,7 +256,6 @@ function webWorker(input, image, canvas, timestamp) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// pass image data as arraybuffer to worker by reference to avoid copy
|
// pass image data as arraybuffer to worker by reference to avoid copy
|
||||||
if (ui.bench) bench.begin();
|
|
||||||
worker.postMessage({ image: image.data.buffer, width: canvas.width, height: canvas.height, userConfig }, [image.data.buffer]);
|
worker.postMessage({ image: image.data.buffer, width: canvas.width, height: canvas.height, userConfig }, [image.data.buffer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +265,7 @@ function runHumanDetect(input, canvas, timestamp) {
|
||||||
const live = input.srcObject && (input.srcObject.getVideoTracks()[0].readyState === 'live') && (input.readyState > 2) && (!input.paused);
|
const live = input.srcObject && (input.srcObject.getVideoTracks()[0].readyState === 'live') && (input.readyState > 2) && (!input.paused);
|
||||||
if (!live && input.srcObject) {
|
if (!live && input.srcObject) {
|
||||||
// stop ui refresh
|
// stop ui refresh
|
||||||
if (ui.drawThread) clearTimeout(ui.drawThread);
|
if (ui.drawThread) cancelAnimationFrame(ui.drawThread);
|
||||||
if (ui.detectThread) cancelAnimationFrame(ui.detectThread);
|
if (ui.detectThread) cancelAnimationFrame(ui.detectThread);
|
||||||
ui.drawThread = null;
|
ui.drawThread = null;
|
||||||
ui.detectThread = null;
|
ui.detectThread = null;
|
||||||
|
@ -272,19 +284,20 @@ function runHumanDetect(input, canvas, timestamp) {
|
||||||
const offscreen = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(canvas.width, canvas.height) : document.createElement('canvas');
|
const offscreen = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(canvas.width, canvas.height) : document.createElement('canvas');
|
||||||
offscreen.width = canvas.width;
|
offscreen.width = canvas.width;
|
||||||
offscreen.height = canvas.height;
|
offscreen.height = canvas.height;
|
||||||
|
|
||||||
const ctx = offscreen.getContext('2d');
|
const ctx = offscreen.getContext('2d');
|
||||||
ctx.drawImage(input, 0, 0, input.width, input.height, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(input, 0, 0, input.width, input.height, 0, 0, canvas.width, canvas.height);
|
||||||
const data = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
const data = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
// perform detection in worker
|
// perform detection in worker
|
||||||
webWorker(input, data, canvas, userConfig, timestamp);
|
webWorker(input, data, canvas, userConfig, timestamp);
|
||||||
} else {
|
} else {
|
||||||
if (ui.bench) bench.begin();
|
|
||||||
human.detect(input, userConfig).then((result) => {
|
human.detect(input, userConfig).then((result) => {
|
||||||
if (result.performance && result.performance.total) ui.detectFPS.push(1000 / result.performance.total);
|
if (result.performance && result.performance.total) ui.detectFPS.push(1000 / result.performance.total);
|
||||||
if (ui.detectFPS.length > ui.maxFPSframes) ui.detectFPS.shift();
|
if (ui.detectFPS.length > ui.maxFPSframes) ui.detectFPS.shift();
|
||||||
if (ui.bench) bench.end();
|
if (ui.bench) {
|
||||||
if (ui.bench) bench.nextFrame(timestamp);
|
if (!bench) initPerfMonitor();
|
||||||
|
bench.nextFrame(timestamp);
|
||||||
|
}
|
||||||
|
if (document.getElementById('gl-bench')) document.getElementById('gl-bench').style.display = ui.bench ? 'block' : 'none';
|
||||||
if (result.error) log(result.error);
|
if (result.error) log(result.error);
|
||||||
else {
|
else {
|
||||||
lastDetectedResult = result;
|
lastDetectedResult = result;
|
||||||
|
@ -331,15 +344,19 @@ async function detectVideo() {
|
||||||
document.getElementById('canvas').style.display = 'block';
|
document.getElementById('canvas').style.display = 'block';
|
||||||
const video = document.getElementById('video');
|
const video = document.getElementById('video');
|
||||||
const canvas = document.getElementById('canvas');
|
const canvas = document.getElementById('canvas');
|
||||||
ui.baseLineHeight = ui.baseLineHeightProto;
|
|
||||||
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('btnStart').innerHTML = 'start<br>video';
|
||||||
status('paused');
|
status('paused');
|
||||||
video.pause();
|
video.pause();
|
||||||
} else {
|
} else {
|
||||||
await setupCamera();
|
await setupCamera();
|
||||||
document.getElementById('play').style.display = 'none';
|
document.getElementById('play').style.display = 'none';
|
||||||
|
for (const m of Object.values(menu)) m.hide();
|
||||||
status('');
|
status('');
|
||||||
|
document.getElementById('btnStart').className = 'button button-stop';
|
||||||
|
document.getElementById('btnStart').innerHTML = 'pause<br>video';
|
||||||
video.play();
|
video.play();
|
||||||
}
|
}
|
||||||
if (!ui.detectThread) runHumanDetect(video, canvas);
|
if (!ui.detectThread) runHumanDetect(video, canvas);
|
||||||
|
@ -349,9 +366,9 @@ async function detectVideo() {
|
||||||
async function detectSampleImages() {
|
async function detectSampleImages() {
|
||||||
document.getElementById('play').style.display = 'none';
|
document.getElementById('play').style.display = 'none';
|
||||||
userConfig.videoOptimized = false;
|
userConfig.videoOptimized = false;
|
||||||
const size = 12 + Math.trunc(12 * ui.columns * window.innerWidth / document.body.clientWidth);
|
const size = Math.trunc(window.devicePixelRatio * (8 + (4 * ui.columns)));
|
||||||
ui.baseFont = ui.baseFontProto.replace(/{size}/, `${size}px`);
|
ui.baseFont = ui.baseFontProto.replace(/{size}/, `${size}px`);
|
||||||
ui.baseLineHeight = ui.baseLineHeightProto * ui.columns;
|
ui.baseLineHeight = size + 2;
|
||||||
document.getElementById('canvas').style.display = 'none';
|
document.getElementById('canvas').style.display = 'none';
|
||||||
document.getElementById('samples-container').style.display = 'block';
|
document.getElementById('samples-container').style.display = 'block';
|
||||||
log('Running detection of sample images');
|
log('Running detection of sample images');
|
||||||
|
@ -362,121 +379,116 @@ async function detectSampleImages() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupMenu() {
|
function setupMenu() {
|
||||||
document.getElementById('compare-container').style.display = human.config.face.embedding.enabled ? 'block' : 'none';
|
let x = [];
|
||||||
menu = new Menu(document.body, '', { top: '1rem', right: '1rem' });
|
if (window.innerWidth > 800) {
|
||||||
const btn = menu.addButton('start video', 'pause video', () => detectVideo());
|
// initial position of menu items, later it's calculated based on mouse coordinates
|
||||||
menu.addButton('process images', 'process images', () => detectSampleImages());
|
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`];
|
||||||
document.getElementById('play').addEventListener('click', () => btn.click());
|
} else {
|
||||||
|
// absolute minimum spacing for menus
|
||||||
|
x = ['0rem', '11rem', '21.1rem', '33rem'];
|
||||||
|
}
|
||||||
|
|
||||||
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
menu.display = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[0] });
|
||||||
menu.addList('backend', ['cpu', 'webgl', 'wasm'], human.config.backend, (val) => human.config.backend = val);
|
menu.display.addBool('perf monitor', ui, 'bench', (val) => ui.bench = val);
|
||||||
menu.addBool('async operations', human.config, 'async', (val) => human.config.async = val);
|
menu.display.addBool('buffered output', ui, 'buffered', (val) => ui.buffered = val);
|
||||||
// menu.addBool('enable profiler', human.config, 'profile', (val) => human.config.profile = val);
|
menu.display.addBool('crop & scale', ui, 'crop', () => setupCamera());
|
||||||
// menu.addBool('memory shield', human.config, 'deallocate', (val) => human.config.deallocate = val);
|
menu.display.addBool('camera facing', ui, 'facing', () => setupCamera());
|
||||||
menu.addBool('use web worker', ui, 'useWorker');
|
menu.display.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
menu.display.addBool('use 3D depth', ui, 'useDepth');
|
||||||
menu.addLabel('enabled models');
|
menu.display.addBool('draw boxes', ui, 'drawBoxes');
|
||||||
menu.addBool('face detect', human.config.face, 'enabled');
|
menu.display.addBool('draw polygons', ui, 'drawPolygons');
|
||||||
menu.addBool('face mesh', human.config.face.mesh, 'enabled');
|
menu.display.addBool('Fill Polygons', ui, 'fillPolygons');
|
||||||
menu.addBool('face iris', human.config.face.iris, 'enabled');
|
menu.display.addBool('draw points', ui, 'drawPoints');
|
||||||
menu.addBool('face age', human.config.face.age, 'enabled');
|
|
||||||
menu.addBool('face gender', human.config.face.gender, 'enabled');
|
|
||||||
menu.addBool('face emotion', human.config.face.emotion, 'enabled');
|
|
||||||
// menu.addBool('face compare', human.config.face.embedding, 'enabled', (val) => {
|
|
||||||
// human.config.face.embedding.enabled = val;
|
|
||||||
// document.getElementById('compare-container').style.display = human.config.face.embedding.enabled ? 'block' : 'none';
|
|
||||||
// });
|
|
||||||
menu.addBool('body pose', human.config.body, 'enabled');
|
|
||||||
menu.addBool('hand pose', human.config.hand, 'enabled');
|
|
||||||
menu.addBool('gesture analysis', human.config.gesture, 'enabled');
|
|
||||||
|
|
||||||
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
menu.image = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[1] });
|
||||||
menu.addLabel('model parameters');
|
menu.image.addBool('enabled', human.config.filter, 'enabled');
|
||||||
menu.addRange('max objects', human.config.face.detector, 'maxFaces', 1, 50, 1, (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));
|
||||||
|
menu.image.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
|
menu.image.addRange('brightness', human.config.filter, 'brightness', -1.0, 1.0, 0.05, (val) => human.config.filter.brightness = parseFloat(val));
|
||||||
|
menu.image.addRange('contrast', human.config.filter, 'contrast', -1.0, 1.0, 0.05, (val) => human.config.filter.contrast = parseFloat(val));
|
||||||
|
menu.image.addRange('sharpness', human.config.filter, 'sharpness', 0, 1.0, 0.05, (val) => human.config.filter.sharpness = parseFloat(val));
|
||||||
|
menu.image.addRange('blur', human.config.filter, 'blur', 0, 20, 1, (val) => human.config.filter.blur = parseInt(val));
|
||||||
|
menu.image.addRange('saturation', human.config.filter, 'saturation', -1.0, 1.0, 0.05, (val) => human.config.filter.saturation = parseFloat(val));
|
||||||
|
menu.image.addRange('hue', human.config.filter, 'hue', 0, 360, 5, (val) => human.config.filter.hue = parseInt(val));
|
||||||
|
menu.image.addRange('pixelate', human.config.filter, 'pixelate', 0, 32, 1, (val) => human.config.filter.pixelate = parseInt(val));
|
||||||
|
menu.image.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
|
menu.image.addBool('negative', human.config.filter, 'negative');
|
||||||
|
menu.image.addBool('sepia', human.config.filter, 'sepia');
|
||||||
|
menu.image.addBool('vintage', human.config.filter, 'vintage');
|
||||||
|
menu.image.addBool('kodachrome', human.config.filter, 'kodachrome');
|
||||||
|
menu.image.addBool('technicolor', human.config.filter, 'technicolor');
|
||||||
|
menu.image.addBool('polaroid', human.config.filter, 'polaroid');
|
||||||
|
|
||||||
|
menu.process = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[2] });
|
||||||
|
menu.process.addList('backend', ['cpu', 'webgl', 'wasm'], human.config.backend, (val) => human.config.backend = 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('memory shield', human.config, 'deallocate', (val) => human.config.deallocate = val);
|
||||||
|
menu.process.addBool('use web worker', ui, 'useWorker');
|
||||||
|
menu.process.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
|
menu.process.addLabel('model parameters');
|
||||||
|
menu.process.addRange('max objects', human.config.face.detector, 'maxFaces', 1, 50, 1, (val) => {
|
||||||
human.config.face.detector.maxFaces = parseInt(val);
|
human.config.face.detector.maxFaces = parseInt(val);
|
||||||
human.config.body.maxDetections = parseInt(val);
|
human.config.body.maxDetections = parseInt(val);
|
||||||
human.config.hand.maxHands = parseInt(val);
|
human.config.hand.maxHands = parseInt(val);
|
||||||
});
|
});
|
||||||
menu.addRange('skip frames', human.config.face.detector, 'skipFrames', 0, 50, 1, (val) => {
|
menu.process.addRange('skip frames', human.config.face.detector, 'skipFrames', 0, 50, 1, (val) => {
|
||||||
human.config.face.detector.skipFrames = parseInt(val);
|
human.config.face.detector.skipFrames = parseInt(val);
|
||||||
human.config.face.emotion.skipFrames = parseInt(val);
|
human.config.face.emotion.skipFrames = parseInt(val);
|
||||||
human.config.face.age.skipFrames = parseInt(val);
|
human.config.face.age.skipFrames = parseInt(val);
|
||||||
human.config.hand.skipFrames = parseInt(val);
|
human.config.hand.skipFrames = parseInt(val);
|
||||||
});
|
});
|
||||||
menu.addRange('min confidence', human.config.face.detector, 'minConfidence', 0.0, 1.0, 0.05, (val) => {
|
menu.process.addRange('min confidence', human.config.face.detector, 'minConfidence', 0.0, 1.0, 0.05, (val) => {
|
||||||
human.config.face.detector.minConfidence = parseFloat(val);
|
human.config.face.detector.minConfidence = parseFloat(val);
|
||||||
human.config.face.gender.minConfidence = parseFloat(val);
|
human.config.face.gender.minConfidence = parseFloat(val);
|
||||||
human.config.face.emotion.minConfidence = parseFloat(val);
|
human.config.face.emotion.minConfidence = parseFloat(val);
|
||||||
human.config.hand.minConfidence = parseFloat(val);
|
human.config.hand.minConfidence = parseFloat(val);
|
||||||
});
|
});
|
||||||
menu.addRange('score threshold', human.config.face.detector, 'scoreThreshold', 0.1, 1.0, 0.05, (val) => {
|
menu.process.addRange('score threshold', human.config.face.detector, 'scoreThreshold', 0.1, 1.0, 0.05, (val) => {
|
||||||
human.config.face.detector.scoreThreshold = parseFloat(val);
|
human.config.face.detector.scoreThreshold = parseFloat(val);
|
||||||
human.config.hand.scoreThreshold = parseFloat(val);
|
human.config.hand.scoreThreshold = parseFloat(val);
|
||||||
human.config.body.scoreThreshold = parseFloat(val);
|
human.config.body.scoreThreshold = parseFloat(val);
|
||||||
});
|
});
|
||||||
menu.addRange('overlap', human.config.face.detector, 'iouThreshold', 0.1, 1.0, 0.05, (val) => {
|
menu.process.addRange('overlap', human.config.face.detector, 'iouThreshold', 0.1, 1.0, 0.05, (val) => {
|
||||||
human.config.face.detector.iouThreshold = parseFloat(val);
|
human.config.face.detector.iouThreshold = parseFloat(val);
|
||||||
human.config.hand.iouThreshold = parseFloat(val);
|
human.config.hand.iouThreshold = parseFloat(val);
|
||||||
});
|
});
|
||||||
|
menu.process.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
|
menu.process.addButton('process sample images', 'process images', () => detectSampleImages());
|
||||||
|
menu.process.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
|
menu.process.addChart('FPS', 'FPS');
|
||||||
|
|
||||||
menu.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
menu.models = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[3] });
|
||||||
menu.addChart('FPS', 'FPS');
|
menu.models.addBool('face detect', human.config.face, 'enabled');
|
||||||
|
menu.models.addBool('face mesh', human.config.face.mesh, 'enabled');
|
||||||
menuFX = new Menu(document.body, '', { top: '1rem', right: '18rem' });
|
menu.models.addBool('face iris', human.config.face.iris, 'enabled');
|
||||||
menuFX.addLabel('ui options');
|
menu.models.addBool('face age', human.config.face.age, 'enabled');
|
||||||
menuFX.addBool('buffered output', ui, 'buffered', (val) => ui.buffered = val);
|
menu.models.addBool('face gender', human.config.face.gender, 'enabled');
|
||||||
menuFX.addBool('crop & scale', ui, 'crop', () => setupCamera());
|
menu.models.addBool('face emotion', human.config.face.emotion, 'enabled');
|
||||||
menuFX.addBool('camera front/back', ui, 'facing', () => setupCamera());
|
menu.models.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
menuFX.addBool('use 3D depth', ui, 'useDepth');
|
menu.models.addBool('body pose', human.config.body, 'enabled');
|
||||||
menuFX.addBool('draw boxes', ui, 'drawBoxes');
|
menu.models.addBool('hand pose', human.config.hand, 'enabled');
|
||||||
menuFX.addBool('draw polygons', ui, 'drawPolygons');
|
menu.models.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
menuFX.addBool('Fill Polygons', ui, 'fillPolygons');
|
menu.models.addBool('gestures', human.config.gesture, 'enabled');
|
||||||
menuFX.addBool('draw points', ui, 'drawPoints');
|
menu.models.addHTML('<hr style="border-style: inset; border-color: dimgray">');
|
||||||
menuFX.addHTML('<hr style="min-width: 200px; border-style: inset; border-color: dimgray">');
|
menu.models.addBool('face compare', human.config.face.embedding, 'enabled', (val) => {
|
||||||
menuFX.addLabel('image processing');
|
original = null;
|
||||||
menuFX.addBool('enabled', human.config.filter, 'enabled');
|
human.config.face.embedding.enabled = val;
|
||||||
ui.menuWidth = menuFX.addRange('image width', human.config.filter, 'width', 0, 3840, 10, (val) => human.config.filter.width = parseInt(val));
|
|
||||||
ui.menuHeight = menuFX.addRange('image height', human.config.filter, 'height', 0, 2160, 10, (val) => human.config.filter.height = parseInt(val));
|
|
||||||
menuFX.addRange('brightness', human.config.filter, 'brightness', -1.0, 1.0, 0.05, (val) => human.config.filter.brightness = parseFloat(val));
|
|
||||||
menuFX.addRange('contrast', human.config.filter, 'contrast', -1.0, 1.0, 0.05, (val) => human.config.filter.contrast = parseFloat(val));
|
|
||||||
menuFX.addRange('sharpness', human.config.filter, 'sharpness', 0, 1.0, 0.05, (val) => human.config.filter.sharpness = parseFloat(val));
|
|
||||||
menuFX.addRange('blur', human.config.filter, 'blur', 0, 20, 1, (val) => human.config.filter.blur = parseInt(val));
|
|
||||||
menuFX.addRange('saturation', human.config.filter, 'saturation', -1.0, 1.0, 0.05, (val) => human.config.filter.saturation = parseFloat(val));
|
|
||||||
menuFX.addRange('hue', human.config.filter, 'hue', 0, 360, 5, (val) => human.config.filter.hue = parseInt(val));
|
|
||||||
menuFX.addRange('pixelate', human.config.filter, 'pixelate', 0, 32, 1, (val) => human.config.filter.pixelate = parseInt(val));
|
|
||||||
menuFX.addBool('negative', human.config.filter, 'negative');
|
|
||||||
menuFX.addBool('sepia', human.config.filter, 'sepia');
|
|
||||||
menuFX.addBool('vintage', human.config.filter, 'vintage');
|
|
||||||
menuFX.addBool('kodachrome', human.config.filter, 'kodachrome');
|
|
||||||
menuFX.addBool('technicolor', human.config.filter, 'technicolor');
|
|
||||||
menuFX.addBool('polaroid', human.config.filter, 'polaroid');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setupMonitor() {
|
|
||||||
let gl = human.tf.engine().backend.gpgpu;
|
|
||||||
if (!gl) gl = document.getElementById('bench-canvas').getContext('webgl2');
|
|
||||||
if (!bench) {
|
|
||||||
bench = new GLBench(gl, {
|
|
||||||
trackGPU: true,
|
|
||||||
chartHz: 20,
|
|
||||||
chartLen: 20,
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
/*
|
document.getElementById('btnDisplay').addEventListener('click', (evt) => menu.display.toggle(evt));
|
||||||
function update(now) {
|
document.getElementById('btnImage').addEventListener('click', (evt) => menu.image.toggle(evt));
|
||||||
bench.nextFrame(now);
|
document.getElementById('btnProcess').addEventListener('click', (evt) => menu.process.toggle(evt));
|
||||||
requestAnimationFrame(update);
|
document.getElementById('btnModel').addEventListener('click', (evt) => menu.models.toggle(evt));
|
||||||
}
|
document.getElementById('btnStart').addEventListener('click', () => detectVideo());
|
||||||
requestAnimationFrame(update);
|
document.getElementById('play').addEventListener('click', () => detectVideo());
|
||||||
*/
|
|
||||||
// class MathBackendWebGL extends tf.KernelBackend property gpgpu is gl context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
log('demo starting ...');
|
log('demo starting ...');
|
||||||
setupMenu();
|
setupMenu();
|
||||||
setupMonitor();
|
document.getElementById('log').innerText = `Human: version ${human.version}`;
|
||||||
document.getElementById('log').innerText = `Human: version ${human.version} TensorFlow/JS: version ${human.tf.version_core}`;
|
|
||||||
// human.tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true);
|
// human.tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true);
|
||||||
// this is not required, just pre-loads all models
|
// this is not required, just pre-loads all models
|
||||||
if (ui.modelsPreload && !ui.useWorker) {
|
if (ui.modelsPreload && !ui.useWorker) {
|
||||||
|
@ -486,7 +498,7 @@ async function main() {
|
||||||
// this is not required, just pre-warms all models for faster initial inference
|
// this is not required, just pre-warms all models for faster initial inference
|
||||||
if (ui.modelsWarmup && !ui.useWorker) {
|
if (ui.modelsWarmup && !ui.useWorker) {
|
||||||
status('initializing');
|
status('initializing');
|
||||||
sample = await human.warmup(userConfig, document.getElementById('sample-image'));
|
await human.warmup(userConfig);
|
||||||
}
|
}
|
||||||
status('human: ready');
|
status('human: ready');
|
||||||
document.getElementById('loader').style.display = 'none';
|
document.getElementById('loader').style.display = 'none';
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// modified based on: https://github.com/munrocket/gl-bench
|
/* eslint-disable max-len */
|
||||||
|
|
||||||
|
// based on: https://github.com/munrocket/gl-bench
|
||||||
|
|
||||||
const UICSS = `
|
const UICSS = `
|
||||||
#gl-bench { position: absolute; right: 1rem; bottom: 1rem; z-index:1000; -webkit-user-select: none; -moz-user-select: none; user-select: none; }
|
#gl-bench { position: absolute; right: 1rem; bottom: 1rem; z-index:1000; -webkit-user-select: none; -moz-user-select: none; user-select: none; }
|
||||||
#gl-bench div { position: relative; display: block; margin: 4px; padding: 0 7px 0 10px; background: darkslategray; border-radius: 0.2rem; cursor: pointer; opacity: 0.9; }
|
#gl-bench div { position: relative; display: block; margin: 4px; padding: 0 7px 0 10px; background: darkslategray; border-radius: 0.2rem; cursor: pointer; opacity: 0.9; }
|
||||||
#gl-bench svg { height: 60px; margin: 0 4px 0px 4px; }
|
#gl-bench svg { height: 60px; margin: 0 0px 0px 4px; }
|
||||||
#gl-bench text { font-size: 16px; font-family: 'Lato', 'Segoe UI'; dominant-baseline: middle; text-anchor: middle; }
|
#gl-bench text { font-size: 16px; font-family: 'Lato', 'Segoe UI'; dominant-baseline: middle; text-anchor: middle; }
|
||||||
#gl-bench .gl-mem { font-size: 12px; fill: white; }
|
#gl-bench .gl-mem { font-size: 12px; fill: white; }
|
||||||
#gl-bench .gl-fps { font-size: 13px; fill: white; }
|
#gl-bench .gl-fps { font-size: 13px; fill: white; }
|
||||||
|
@ -17,7 +19,7 @@ const UISVG = `
|
||||||
<div class="gl-box">
|
<div class="gl-box">
|
||||||
<svg viewBox="0 0 55 60">
|
<svg viewBox="0 0 55 60">
|
||||||
<text x="27" y="56" class="gl-fps">00 FPS</text>
|
<text x="27" y="56" class="gl-fps">00 FPS</text>
|
||||||
<text x="28" y="8" class="gl-mem"></text>
|
<text x="30" y="8" class="gl-mem"></text>
|
||||||
<rect x="0" y="14" rx="4" ry="4" width="55" height="32"></rect>
|
<rect x="0" y="14" rx="4" ry="4" width="55" height="32"></rect>
|
||||||
<polyline class="gl-chart"></polyline>
|
<polyline class="gl-chart"></polyline>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -87,21 +89,41 @@ class GLBench {
|
||||||
});
|
});
|
||||||
}, 0));
|
}, 0));
|
||||||
|
|
||||||
const addProfiler = (fn, self, target) => function () {
|
const addProfiler = (fn, self, target) => {
|
||||||
const t = self.now();
|
const t = self.now();
|
||||||
// eslint-disable-next-line prefer-rest-params
|
// eslint-disable-next-line prefer-rest-params
|
||||||
fn.apply(target, arguments);
|
fn.apply(target, arguments);
|
||||||
if (self.trackGPU) self.finished.push(glFinish(t, self.activeAccums.slice(0)));
|
if (self.trackGPU) self.finished.push(glFinish(t, self.activeAccums.slice(0)));
|
||||||
};
|
};
|
||||||
|
|
||||||
['drawArrays', 'drawElements', 'drawArraysInstanced', 'drawBuffers', 'drawElementsInstanced', 'drawRangeElements'].forEach((fn) => { if (gl[fn]) gl[fn] = addProfiler(gl[fn], this, gl); });
|
/* ['drawArrays', 'drawElements', 'drawArraysInstanced', 'drawBuffers', 'drawElementsInstanced', 'drawRangeElements'].forEach((fn) => {
|
||||||
|
if (gl[fn]) {
|
||||||
|
gl[fn] = addProfiler(gl[fn], this, gl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
const fn = 'drawElements';
|
||||||
|
if (gl[fn]) {
|
||||||
|
gl[fn] = addProfiler(gl[fn], this, gl);
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('bench: cannot attach to webgl function');
|
||||||
|
}
|
||||||
|
|
||||||
gl.getExtension = ((fn, self) => function () {
|
/*
|
||||||
|
gl.getExtension = ((fn, self) => {
|
||||||
// eslint-disable-next-line prefer-rest-params
|
// eslint-disable-next-line prefer-rest-params
|
||||||
const ext = fn.apply(gl, arguments);
|
const ext = fn.apply(gl, arguments);
|
||||||
if (ext) ['drawElementsInstancedANGLE', 'drawBuffersWEBGL'].forEach((fn2) => { if (ext[fn2]) ext[fn2] = addProfiler(ext[fn2], self, ext); });
|
if (ext) {
|
||||||
|
['drawElementsInstancedANGLE', 'drawBuffersWEBGL'].forEach((fn2) => {
|
||||||
|
if (ext[fn2]) {
|
||||||
|
ext[fn2] = addProfiler(ext[fn2], self, ext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return ext;
|
return ext;
|
||||||
})(gl.getExtension, this);
|
})(gl.getExtension, this);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// init ui and ui loggers
|
// init ui and ui loggers
|
||||||
|
@ -127,7 +149,7 @@ class GLBench {
|
||||||
nodes['gl-gpu'][i].style.strokeDasharray = (gpu * 0.27).toFixed(0) + ' 100';
|
nodes['gl-gpu'][i].style.strokeDasharray = (gpu * 0.27).toFixed(0) + ' 100';
|
||||||
// eslint-disable-next-line no-nested-ternary
|
// eslint-disable-next-line no-nested-ternary
|
||||||
nodes['gl-mem'][i].innerHTML = names[i] ? names[i] : (mem ? 'mem: ' + mem.toFixed(0) + 'mb' : '');
|
nodes['gl-mem'][i].innerHTML = names[i] ? names[i] : (mem ? 'mem: ' + mem.toFixed(0) + 'mb' : '');
|
||||||
nodes['gl-fps'][i].innerHTML = fps.toFixed(0) + ' FPS';
|
nodes['gl-fps'][i].innerHTML = 'FPS: ' + fps.toFixed(1);
|
||||||
logger(names[i], cpu, gpu, mem, fps, totalTime, frameId);
|
logger(names[i], cpu, gpu, mem, fps, totalTime, frameId);
|
||||||
};
|
};
|
||||||
})(this.paramLogger, this.dom, this.names);
|
})(this.paramLogger, this.dom, this.names);
|
|
@ -19,22 +19,26 @@
|
||||||
<!-- <script src="./browser.js" type="module"></script> -->
|
<!-- <script src="./browser.js" type="module"></script> -->
|
||||||
<style>
|
<style>
|
||||||
@font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 400; src: local('Lato'), url('../assets/lato.ttf') format('truetype'); }
|
@font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 400; src: local('Lato'), url('../assets/lato.ttf') format('truetype'); }
|
||||||
|
@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; scrollbar-width: none; }
|
body { margin: 0; background: black; color: white; overflow-x: hidden; scrollbar-width: none; }
|
||||||
body::-webkit-scrollbar { display: none; }
|
body::-webkit-scrollbar { display: none; }
|
||||||
.play { position: absolute; width: 300px; height: 300px; z-index: 9; top: 30%; left: 50%; margin-left: -150px; display: none; }
|
hr { width: 100%; }
|
||||||
.play-background { fill:darkslategray; cursor:pointer; opacity: 0.6; }
|
.play { position: absolute; width: 250px; height: 250px; z-index: 9; top: 55%; left: 50%; margin-left: -125px; display: none; }
|
||||||
.play-foreground { fill:white; cursor:pointer; opacity: 0.8; }
|
.btn-background { fill:grey; cursor: pointer; opacity: 0.6; }
|
||||||
.play-foreground:hover { opacity: 1; }
|
.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: 15%; 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 { margin: 8px; box-shadow: 0 0 4px 4px dimgrey; }
|
||||||
.thumbnail:hover { box-shadow: 0 0 8px 8px dimgrey; filter: grayscale(1); }
|
.thumbnail:hover { box-shadow: 0 0 8px 8px dimgrey; filter: grayscale(1); }
|
||||||
.log { position: fixed; bottom: 0; margin: 0.4rem; font-size: 0.9rem; }
|
.log { position: absolute; bottom: 0; margin: 0.4rem; font-size: 0.9rem; }
|
||||||
|
.menubar { width: 100vw; background: darkslategray; display: flex; justify-content: space-evenly; text-align: center; padding: 8px; cursor: pointer; }
|
||||||
.samples-container { display: flex; flex-wrap: wrap; }
|
.samples-container { display: flex; flex-wrap: wrap; }
|
||||||
.video { display: none; }
|
.video { display: none; }
|
||||||
.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: 10vw; 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; top: 30%; 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; top: 30%; 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; }
|
||||||
|
@ -51,13 +55,22 @@
|
||||||
from { transform: rotate(0deg); }
|
from { transform: rotate(0deg); }
|
||||||
from { transform: rotate(360deg); }
|
from { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
.button { text-shadow: 2px 2px black; display: flex; }
|
||||||
|
.button:hover { text-shadow: -2px -2px black; color: lightblue; }
|
||||||
|
.button::before { display: inline-block; font-style: normal; font-variant: normal; text-rendering: auto; -webkit-font-smoothing: antialiased; font-family: "FA"; font-weight: 900; font-size: 2.4rem; margin-right: 0.4rem; }
|
||||||
|
.button-display::before { content: "\f8c4"; }
|
||||||
|
.button-image::before { content: "\f3f2"; }
|
||||||
|
.button-process::before { content: "\f3f0"; }
|
||||||
|
.button-model::before { content: "\f2c2"; }
|
||||||
|
.button-start::before { content: "\f144"; }
|
||||||
|
.button-stop::before { content: "\f28b"; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="play" class="play">
|
<div id="play" class="play">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
<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="play-background"/>
|
<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="play-foreground"/>
|
<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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div id="background">
|
<div id="background">
|
||||||
|
@ -67,16 +80,22 @@
|
||||||
</div>
|
</div>
|
||||||
<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">
|
||||||
|
<span class="button button-display" id="btnDisplay">Display<br>Options</span>
|
||||||
|
<span class="button button-image" id="btnImage">Image<br>Processing</span>
|
||||||
|
<span class="button button-process" id="btnProcess">Model<br>Processing</span>
|
||||||
|
<span class="button button-model" id="btnModel">Model<br>Selection</span>
|
||||||
|
<span class="button button-start" id="btnStart">Start<br>Video</span>
|
||||||
|
</div>
|
||||||
<div id="media">
|
<div id="media">
|
||||||
<canvas id="canvas" class="canvas"></canvas>
|
<canvas id="canvas" class="canvas"></canvas>
|
||||||
<video id="video" playsinline class="video"></video>
|
<video id="video" playsinline class="video"></video>
|
||||||
</div>
|
</div>
|
||||||
<div id="compare-container" style="display: none" class="compare-image">
|
<div id="compare-container" style="display: none" class="compare-image">
|
||||||
<img id="sample-image" style="width: 100%" src="../assets/sample-me.jpg"></img>
|
<canvas id="compare-canvas" width="200px" height="200px"></canvas>
|
||||||
<div id="simmilarity"></div>
|
<div id="simmilarity"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="samples-container" class="samples-container"></div>
|
<div id="samples-container" class="samples-container"></div>
|
||||||
<canvas id="bench-canvas" class="bench"></canvas>
|
|
||||||
<div id="log" class="log"></div>
|
<div id="log" class="log"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
26
demo/menu.js
26
demo/menu.js
|
@ -19,15 +19,15 @@ function createCSS() {
|
||||||
if (CSScreated) return;
|
if (CSScreated) return;
|
||||||
const css = `
|
const css = `
|
||||||
:root { --rounded: 0.2rem; }
|
:root { --rounded: 0.2rem; }
|
||||||
.menu { position: absolute; top: 0rem; right: 0; width: fit-content; padding: 0 0.8rem 0 0.8rem; line-height: 1.8rem; z-index: 10;
|
.menu { position: absolute; top: 0rem; right: 0; width: fit-content; padding: 0 0.2rem 0 0.2rem; line-height: 1.8rem; z-index: 10;
|
||||||
box-shadow: 0 0 8px dimgrey; background: ${theme.background}; border-radius: var(--rounded); border-color: black; border-style: solid; border-width: thin; }
|
box-shadow: 0 0 8px dimgrey; background: ${theme.background}; border-radius: var(--rounded); border-color: black; border-style: solid; border-width: thin; }
|
||||||
|
|
||||||
.menu:hover { box-shadow: 0 0 8px ${theme.hover}; }
|
.menu:hover { box-shadow: 0 0 8px ${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; width: max-content; cursor: default; }
|
.menu-item { display: flex; white-space: nowrap; padding: 0.2rem; cursor: default; width: 100%; }
|
||||||
.menu-title { text-align: right; 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; }
|
||||||
|
|
||||||
|
@ -39,12 +39,12 @@ function createCSS() {
|
||||||
.menu-chart-title { padding: 0; font-size: 0.8rem; font-weight: 800; align-items: center}
|
.menu-chart-title { padding: 0; font-size: 0.8rem; font-weight: 800; align-items: center}
|
||||||
.menu-chart-canvas { background: transparent; margin: 0.2rem 0 0.2rem 0.6rem; }
|
.menu-chart-canvas { background: transparent; margin: 0.2rem 0 0.2rem 0.6rem; }
|
||||||
|
|
||||||
.menu-button { border: 0; background: ${theme.buttonBackground}; width: 100%; padding: 8px; margin: 8px 0 8px 0; cursor: pointer; box-shadow: 4px 4px 4px 0 dimgrey;
|
.menu-button { border: 0; background: ${theme.buttonBackground}; width: -webkit-fill-available; padding: 8px; margin: 8px; cursor: pointer; box-shadow: 4px 4px 4px 0 dimgrey;
|
||||||
border-radius: var(--rounded); justify-content: center; font-family: inherit; font-variant: inherit; font-size: 1rem; font-weight: 800; }
|
border-radius: var(--rounded); justify-content: center; font-family: inherit; font-variant: inherit; font-size: 1rem; font-weight: 800; }
|
||||||
.menu-button:hover { background: ${theme.buttonHover}; box-shadow: 4px 4px 4px 0 black; }
|
.menu-button:hover { background: ${theme.buttonHover}; box-shadow: 4px 4px 4px 0 black; }
|
||||||
.menu-button:focus { outline: none; }
|
.menu-button:focus { outline: none; }
|
||||||
|
|
||||||
.menu-checkbox { width: 2.8rem; height: 1rem; background: ${theme.itemBackground}; margin: 0.5rem 0.8rem 0 0; position: relative; border-radius: var(--rounded); }
|
.menu-checkbox { width: 2.8rem; height: 1rem; background: ${theme.itemBackground}; margin: 0.5rem 0.5rem 0 0; position: relative; border-radius: var(--rounded); }
|
||||||
.menu-checkbox:after { content: 'OFF'; color: ${theme.checkboxOff}; position: absolute; right: 0.2rem; top: -0.4rem; font-weight: 800; font-size: 0.5rem; }
|
.menu-checkbox:after { content: 'OFF'; color: ${theme.checkboxOff}; position: absolute; right: 0.2rem; top: -0.4rem; font-weight: 800; font-size: 0.5rem; }
|
||||||
.menu-checkbox:before { content: 'ON'; color: ${theme.checkboxOn}; position: absolute; left: 0.3rem; top: -0.4rem; font-weight: 800; font-size: 0.5rem; }
|
.menu-checkbox:before { content: 'ON'; color: ${theme.checkboxOn}; position: absolute; left: 0.3rem; top: -0.4rem; font-weight: 800; font-size: 0.5rem; }
|
||||||
.menu-checkbox-label { width: 1.3rem; height: 0.8rem; cursor: pointer; position: absolute; top: 0.1rem; left: 0.1rem; z-index: 1; background: ${theme.checkboxOff};
|
.menu-checkbox-label { width: 1.3rem; height: 0.8rem; cursor: pointer; position: absolute; top: 0.1rem; left: 0.1rem; z-index: 1; background: ${theme.checkboxOff};
|
||||||
|
@ -53,14 +53,14 @@ function createCSS() {
|
||||||
input[type=checkbox] { visibility: hidden; }
|
input[type=checkbox] { visibility: hidden; }
|
||||||
input[type=checkbox]:checked + label { left: 1.4rem; background: ${theme.checkboxOn}; }
|
input[type=checkbox]:checked + label { left: 1.4rem; background: ${theme.checkboxOn}; }
|
||||||
|
|
||||||
.menu-range { margin: 0 0.8rem 0 0; width: 5rem; background: transparent; color: ${theme.rangeBackground}; }
|
.menu-range { margin: 0.2rem 0.5rem 0 0; width: 3.5rem; background: transparent; color: ${theme.rangeBackground}; }
|
||||||
.menu-range:before { color: ${theme.rangeLabel}; margin: 0 0.4rem 0 0; font-weight: 800; font-size: 0.6rem; position: relative; top: 0.3rem; content: attr(value); }
|
.menu-range:before { color: ${theme.rangeLabel}; margin: 0 0.4rem 0 0; font-weight: 800; font-size: 0.6rem; position: relative; top: 0.3rem; content: attr(value); }
|
||||||
|
|
||||||
input[type=range] { -webkit-appearance: none; }
|
input[type=range] { -webkit-appearance: none; }
|
||||||
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 1rem; cursor: pointer; background: ${theme.itemBackground}; border-radius: var(--rounded); border: 1px; }
|
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 1rem; cursor: pointer; background: ${theme.itemBackground}; border-radius: var(--rounded); border: 1px; }
|
||||||
input[type=range]::-moz-range-track { width: 100%; height: 1rem; cursor: pointer; background: ${theme.itemBackground}; border-radius: var(--rounded); border: 1px; }
|
input[type=range]::-moz-range-track { width: 100%; height: 1rem; cursor: pointer; background: ${theme.itemBackground}; border-radius: var(--rounded); border: 1px; }
|
||||||
input[type=range]::-webkit-slider-thumb { border: 1px solid #000000; margin-top: 0.05rem; height: 0.9rem; width: 1.5rem; border-radius: var(--rounded); background: ${theme.rangeBackground}; cursor: pointer; -webkit-appearance: none; }
|
input[type=range]::-webkit-slider-thumb { border: 1px solid #000000; margin-top: 0.05rem; height: 0.9rem; width: 1rem; border-radius: var(--rounded); background: ${theme.rangeBackground}; cursor: pointer; -webkit-appearance: none; }
|
||||||
input[type=range]::-moz-range-thumb { border: 1px solid #000000; margin-top: 0.05rem; height: 0.9rem; width: 1.5rem; border-radius: var(--rounded); background: ${theme.rangeBackground}; cursor: pointer; -webkit-appearance: none; }
|
input[type=range]::-moz-range-thumb { border: 1px solid #000000; margin-top: 0.05rem; height: 0.9rem; width: 1rem; border-radius: var(--rounded); background: ${theme.rangeBackground}; cursor: pointer; -webkit-appearance: none; }
|
||||||
|
|
||||||
.svg-background { fill:darkslategrey; cursor:pointer; opacity: 0.6; }
|
.svg-background { fill:darkslategrey; cursor:pointer; opacity: 0.6; }
|
||||||
.svg-foreground { fill:white; cursor:pointer; opacity: 0.8; }
|
.svg-foreground { fill:white; cursor:pointer; opacity: 0.8; }
|
||||||
|
@ -106,7 +106,7 @@ class Menu {
|
||||||
<path d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h352a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48zm-51.37 182.31L232.06 348.16a10.38 10.38 0 0 1-16.12 0L99.37 214.31C92.17 206 97.28 192 107.43 192h233.14c10.15 0 15.26 14 8.06 22.31z" class="svg-background"/>
|
<path d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h352a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48zm-51.37 182.31L232.06 348.16a10.38 10.38 0 0 1-16.12 0L99.37 214.31C92.17 206 97.28 192 107.43 192h233.14c10.15 0 15.26 14 8.06 22.31z" class="svg-background"/>
|
||||||
<path d="M348.63 214.31L232.06 348.16a10.38 10.38 0 0 1-16.12 0L99.37 214.31C92.17 206 97.28 192 107.43 192h233.14c10.15 0 15.26 14 8.06 22.31z" class="svg-foreground"/>
|
<path d="M348.63 214.31L232.06 348.16a10.38 10.38 0 0 1-16.12 0L99.37 214.31C92.17 206 97.28 192 107.43 192h233.14c10.15 0 15.26 14 8.06 22.31z" class="svg-foreground"/>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
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');
|
this.container.classList.toggle('menu-container-fadeout');
|
||||||
|
@ -152,9 +152,9 @@ class Menu {
|
||||||
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);
|
||||||
if (x) this.menu.style.left = `${x - 105}px`;
|
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 (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 < 0) this.menu.style.left = 0;
|
||||||
if ((this.menu.offsetLeft + this.menu.offsetWidth) > window.innerWidth) {
|
if ((this.menu.offsetLeft + this.menu.offsetWidth) > window.innerWidth) {
|
||||||
this.menu.style.left = null;
|
this.menu.style.left = null;
|
||||||
|
@ -279,7 +279,7 @@ class Menu {
|
||||||
else this.addValue(title, val);
|
else this.addValue(title, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
addChart(title, id, width = 200, height = 40, color) {
|
addChart(title, id, width = 150, height = 40, color) {
|
||||||
if (color) theme.chartColor = color;
|
if (color) theme.chartColor = color;
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'menu-item menu-chart-title';
|
el.className = 'menu-item menu-chart-title';
|
||||||
|
|
|
@ -116,8 +116,8 @@ class Human {
|
||||||
if (userConfig) this.config = mergeDeep(this.config, userConfig);
|
if (userConfig) this.config = mergeDeep(this.config, userConfig);
|
||||||
|
|
||||||
if (this.firstRun) {
|
if (this.firstRun) {
|
||||||
this.checkBackend(true);
|
|
||||||
this.log(`version: ${this.version} TensorFlow/JS version: ${tf.version_core}`);
|
this.log(`version: ${this.version} TensorFlow/JS version: ${tf.version_core}`);
|
||||||
|
this.checkBackend(true);
|
||||||
this.log('configuration:', this.config);
|
this.log('configuration:', this.config);
|
||||||
this.log('flags:', tf.ENV.flags);
|
this.log('flags:', tf.ENV.flags);
|
||||||
this.firstRun = false;
|
this.firstRun = false;
|
||||||
|
|
Loading…
Reference in New Issue