diff --git a/CHANGELOG.md b/CHANGELOG.md index 326bba97..5cb5d940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,14 @@ Repository: **** ## Changelog -### **HEAD -> main** 2021/03/10 mandic00@live.com +### **HEAD -> main** 2021/03/11 mandic00@live.com + +- wip on embedding +- simplify face box coordinate calculations +- annotated models and removed gender-ssrnet +- autodetect inputsizes + +### **origin/main** 2021/03/10 mandic00@live.com ### **1.0.3** 2021/03/10 mandic00@live.com diff --git a/TODO.md b/TODO.md index fc71ed9b..43527a9a 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,6 @@ - Automated testing - Guard against corrupt input - Improve face embedding -- Build Face embedding database - Dynamic sample processing - Explore EfficientPose diff --git a/config.js b/config.js index f67e7a77..569c3da4 100644 --- a/config.js +++ b/config.js @@ -67,7 +67,7 @@ export default { // (note: module is not loaded until it is required) detector: { modelPath: '../models/blazeface-back.json', - rotation: true, // use best-guess rotated face image or just box with rotation as-is + rotation: false, // use best-guess rotated face image or just box with rotation as-is // false means higher performance, but incorrect mesh mapping if face angle is above 20 degrees // this parameter is not valid in nodejs maxFaces: 10, // maximum number of faces detected in the input @@ -85,7 +85,7 @@ export default { scoreThreshold: 0.2, // threshold for deciding when to remove boxes based on score // in non-maximum suppression, // this is applied on detection objects only and before minConfidence - return: true, // return extracted face as tensor + return: false, // return extracted face as tensor }, mesh: { @@ -121,7 +121,8 @@ export default { }, embedding: { - enabled: false, + enabled: false, // to improve accuracy of face embedding extraction it is recommended + // to enable detector.rotation and mesh.enabled modelPath: '../models/mobilefacenet.json', }, }, diff --git a/demo/browser.js b/demo/browser.js index b99a444c..57aeedbb 100644 --- a/demo/browser.js +++ b/demo/browser.js @@ -3,18 +3,20 @@ import Human from '../src/human'; import Menu from './menu.js'; import GLBench from './gl-bench.js'; -// const userConfig = { backend: 'webgl' }; // add any user configuration overrides +const userConfig = { backend: 'webgl' }; // add any user configuration overrides +/* const userConfig = { backend: 'wasm', async: false, warmup: 'face', videoOptimized: false, - face: { enabled: true, mesh: { enabled: true }, iris: { enabled: false }, age: { enabled: false }, gender: { enabled: false }, emotion: { enabled: false }, embedding: { enabled: true } }, + face: { enabled: true, mesh: { enabled: true }, iris: { enabled: false }, age: { enabled: false }, gender: { enabled: false }, emotion: { enabled: false }, embedding: { enabled: false } }, hand: { enabled: false }, gesture: { enabled: false }, body: { enabled: false, modelPath: '../models/blazepose.json' }, }; +*/ const human = new Human(userConfig); diff --git a/demo/embedding.html b/demo/embedding.html index c664ab13..30bb545b 100644 --- a/demo/embedding.html +++ b/demo/embedding.html @@ -20,12 +20,14 @@ body { margin: 0; background: black; color: white; overflow-x: hidden; scrollbar-width: none; } body::-webkit-scrollbar { display: none; } img { object-fit: contain; } - .face { width: 200px; height: 200px; } + .face { width: 150px; height: 150px; }
Sample Images:
+
Selected Face
+
Extracted Faces - click on a face to sort by simmilarity:
diff --git a/demo/embedding.js b/demo/embedding.js index 620a93b4..8eb1b007 100644 --- a/demo/embedding.js +++ b/demo/embedding.js @@ -9,7 +9,7 @@ const userConfig = { videoOptimized: false, face: { enabled: true, - detector: { rotation: true }, + detector: { rotation: true, return: true }, mesh: { enabled: true }, embedding: { enabled: true, modelPath: '../models/mobilefacenet.json' }, iris: { enabled: false }, @@ -22,9 +22,10 @@ const userConfig = { body: { enabled: false }, }; const human = new Human(userConfig); -const samples = ['../assets/sample-me.jpg', '../assets/sample6.jpg', '../assets/sample1.jpg', '../assets/sample4.jpg', '../assets/sample5.jpg', '../assets/sample3.jpg', '../assets/sample2.jpg', - '../private/me (1).jpg', '../private/me (2).jpg', '../private/me (3).jpg', '../private/me (4).jpg', '../private/me (5).jpg', '../private/me (6).jpg', '../private/me (7).jpg', '../private/me (8).jpg', - '../private/me (9).jpg', '../private/me (10).jpg', '../private/me (11).jpg', '../private/me (12).jpg', '../private/me (13).jpg']; +const samples = ['../assets/sample-me.jpg', '../assets/sample6.jpg', '../assets/sample1.jpg', '../assets/sample4.jpg', '../assets/sample5.jpg', '../assets/sample3.jpg', '../assets/sample2.jpg']; +// const samples = ['../assets/sample-me.jpg', '../assets/sample6.jpg', '../assets/sample1.jpg', '../assets/sample4.jpg', '../assets/sample5.jpg', '../assets/sample3.jpg', '../assets/sample2.jpg', +// '../private/me (1).jpg', '../private/me (2).jpg', '../private/me (3).jpg', '../private/me (4).jpg', '../private/me (5).jpg', '../private/me (6).jpg', '../private/me (7).jpg', '../private/me (8).jpg', +// '../private/me (9).jpg', '../private/me (10).jpg', '../private/me (11).jpg', '../private/me (12).jpg', '../private/me (13).jpg']; const all = []; function log(...msg) { @@ -36,6 +37,12 @@ function log(...msg) { async function analyze(face) { log('Face:', face); + + const box = [[0.05, 0.15, 0.90, 0.85]]; // top, left, bottom, right + const crop = human.tf.image.cropAndResize(face.tensor.expandDims(0), box, [0], [200, 200]); // optionally do a tight box crop + const c = document.getElementById('orig'); + human.tf.browser.toPixels(crop.squeeze(), c); + const canvases = document.getElementsByClassName('face'); for (const canvas of canvases) { const res = human.simmilarity(face.embedding, all[canvas.tag.sample][canvas.tag.face].embedding); @@ -64,7 +71,7 @@ async function faces(index, res) { canvas.height = 200; canvas.className = 'face'; canvas.addEventListener('click', (evt) => { - log('Select:', evt.target.tag.sample, evt.target.tag.face); + log('Select:', 'Image:', evt.target.tag.sample, 'Face:', evt.target.tag.face); analyze(all[evt.target.tag.sample][evt.target.tag.face]); }); human.tf.browser.toPixels(res.face[i].tensor, canvas); @@ -73,7 +80,7 @@ async function faces(index, res) { } async function add(index) { - log('Add:', samples[index]); + log('Add image:', samples[index]); return new Promise((resolve) => { const img = new Image(100, 100); img.onload = () => { @@ -89,6 +96,7 @@ async function add(index) { async function main() { await human.load(); for (const i in samples) await add(i); + log('Ready'); } window.onload = main; diff --git a/wiki b/wiki index fa7ac1f6..a6a1fb71 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit fa7ac1f695547aa0fd25845e6cac7ed5ee0adcae +Subproject commit a6a1fb7149d8a25da4874ce469f66977d517420d