mirror of https://github.com/vladmandic/human
add face return tensor
parent
c3ecdf5486
commit
e4574d9fdf
|
@ -9,7 +9,14 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
|
|||
|
||||
## 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
|
||||
|
|
1
TODO.md
1
TODO.md
|
@ -4,7 +4,6 @@
|
|||
- Automated testing
|
||||
- Guard against corrupt input
|
||||
- Improve face embedding
|
||||
- Build Face embedding database
|
||||
- Dynamic sample processing
|
||||
- Explore EfficientPose
|
||||
<https://github.com/daniegr/EfficientPose>
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<br>Sample Images:
|
||||
<div id="images"></div>
|
||||
<br>Selected Face<br>
|
||||
<canvas id="orig" style="width: 200px; height: 200px;"></canvas>
|
||||
<br>Extracted Faces - click on a face to sort by simmilarity:<br>
|
||||
<div id="faces"></div>
|
||||
</body>
|
||||
|
|
|
@ -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;
|
||||
|
|
2
wiki
2
wiki
|
@ -1 +1 @@
|
|||
Subproject commit fa7ac1f695547aa0fd25845e6cac7ed5ee0adcae
|
||||
Subproject commit a6a1fb7149d8a25da4874ce469f66977d517420d
|
Loading…
Reference in New Issue