mirror of https://github.com/vladmandic/human
105 lines
3.7 KiB
JavaScript
105 lines
3.7 KiB
JavaScript
/**
|
|
* Human demo for browsers
|
|
*
|
|
* Demo for face detection
|
|
*/
|
|
|
|
/** @type {Human} */
|
|
import { Human } from '../../dist/human.esm.js';
|
|
import { showLoader, hideLoader } from './loader.js';
|
|
|
|
const humanConfig = { // user configuration for human, used to fine-tune behavior
|
|
debug: true,
|
|
modelBasePath: 'https://vladmandic.github.io/human-models/models/',
|
|
filter: { enabled: true, equalization: false, flip: false },
|
|
face: {
|
|
enabled: true,
|
|
detector: { rotation: true, maxDetected: 100, minConfidence: 0.2, return: true },
|
|
iris: { enabled: true },
|
|
description: { enabled: true },
|
|
emotion: { enabled: true },
|
|
antispoof: { enabled: true },
|
|
liveness: { enabled: true },
|
|
},
|
|
body: { enabled: false },
|
|
hand: { enabled: false },
|
|
object: { enabled: false },
|
|
gesture: { enabled: false },
|
|
segmentation: { enabled: false },
|
|
};
|
|
|
|
const human = new Human(humanConfig); // new instance of human
|
|
|
|
async function addFaces(imgEl) {
|
|
showLoader('human: busy');
|
|
const faceEl = document.getElementById('faces');
|
|
faceEl.innerHTML = '';
|
|
const res = await human.detect(imgEl);
|
|
for (const face of res.face) {
|
|
const canvas = document.createElement('canvas');
|
|
const emotion = face.emotion?.map((e) => `${Math.round(100 * e.score)}% ${e.emotion}`) || [];
|
|
canvas.title = `
|
|
source: ${imgEl.src.substring(0, 64)}
|
|
score: ${Math.round(100 * face.boxScore)}% detection ${Math.round(100 * face.faceScore)}% analysis
|
|
age: ${face.age} years
|
|
gender: ${face.gender} score ${Math.round(100 * face.genderScore)}%
|
|
emotion: ${emotion.join(' | ')}
|
|
check: ${Math.round(100 * face.real)}% real ${Math.round(100 * face.live)}% live
|
|
`.replace(/ /g, ' ');
|
|
canvas.onclick = (e) => {
|
|
e.preventDefault();
|
|
document.getElementById('description').innerHTML = canvas.title;
|
|
};
|
|
human.tf.browser.toPixels(face.tensor, canvas);
|
|
human.tf.dispose(face.tensor);
|
|
faceEl?.appendChild(canvas);
|
|
}
|
|
hideLoader();
|
|
}
|
|
|
|
function addImage(imageUri) {
|
|
const imgEl = new Image(256, 256);
|
|
imgEl.onload = () => {
|
|
const images = document.getElementById('images');
|
|
images.appendChild(imgEl); // add image if loaded ok
|
|
images.scroll(images?.offsetWidth, 0);
|
|
};
|
|
imgEl.onerror = () => console.error('addImage', { imageUri }); // eslint-disable-line no-console
|
|
imgEl.onclick = () => addFaces(imgEl);
|
|
imgEl.title = imageUri.substring(0, 64);
|
|
imgEl.src = encodeURI(imageUri);
|
|
}
|
|
|
|
async function initDragAndDrop() {
|
|
const reader = new FileReader();
|
|
reader.onload = async (e) => {
|
|
if (e.target.result.startsWith('data:image')) await addImage(e.target.result);
|
|
};
|
|
document.body.addEventListener('dragenter', (evt) => evt.preventDefault());
|
|
document.body.addEventListener('dragleave', (evt) => evt.preventDefault());
|
|
document.body.addEventListener('dragover', (evt) => evt.preventDefault());
|
|
document.body.addEventListener('drop', async (evt) => {
|
|
evt.preventDefault();
|
|
evt.dataTransfer.dropEffect = 'copy';
|
|
for (const f of evt.dataTransfer.files) reader.readAsDataURL(f);
|
|
});
|
|
document.body.onclick = (e) => {
|
|
if (e.target.localName !== 'canvas') document.getElementById('description').innerHTML = '';
|
|
};
|
|
}
|
|
|
|
async function main() {
|
|
showLoader('loading models');
|
|
await human.load();
|
|
showLoader('compiling models');
|
|
await human.warmup();
|
|
showLoader('loading images');
|
|
const images = ['group-1.jpg', 'group-2.jpg', 'group-3.jpg', 'group-4.jpg', 'group-5.jpg', 'group-6.jpg', 'group-7.jpg', 'solvay1927.jpg', 'stock-group-1.jpg', 'stock-group-2.jpg'];
|
|
const imageUris = images.map((a) => `../../samples/in/${a}`);
|
|
for (let i = 0; i < imageUris.length; i++) addImage(imageUris[i]);
|
|
initDragAndDrop();
|
|
hideLoader();
|
|
}
|
|
|
|
window.onload = main;
|