new module: face description

pull/91/head
Vladimir Mandic 2021-03-21 14:18:51 -04:00
parent 343e8c8d93
commit ee05c6a283
34 changed files with 1534 additions and 1026 deletions

View File

@ -1,6 +1,6 @@
# @vladmandic/human # @vladmandic/human
Version: **1.1.10** Version: **1.2.0**
Description: **Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition** Description: **Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition**
Author: **Vladimir Mandic <mandic00@live.com>** Author: **Vladimir Mandic <mandic00@live.com>**
@ -9,6 +9,10 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
## Changelog ## Changelog
### **1.1.11** 2021/03/21 mandic00@live.com
- refactor face classes
### **1.1.10** 2021/03/18 mandic00@live.com ### **1.1.10** 2021/03/18 mandic00@live.com
- cleanup - cleanup

View File

@ -102,8 +102,8 @@ async function calcSimmilariry(result) {
document.getElementById('compare-canvas').getContext('2d').drawImage(original.canvas, 0, 0, 200, 200); 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); const similarity = human.similarity(original?.face[0]?.embedding, result?.face[0]?.embedding);
document.getElementById('simmilarity').innerText = `simmilarity: ${Math.trunc(1000 * simmilarity) / 10}%`; document.getElementById('similarity').innerText = `similarity: ${Math.trunc(1000 * similarity) / 10}%`;
} }
// draws processed results and starts processing of a next frame // draws processed results and starts processing of a next frame

View File

@ -27,7 +27,8 @@
<div id="images"></div> <div id="images"></div>
<br>Selected Face (Enhanced):<br> <br>Selected Face (Enhanced):<br>
<canvas id="orig" style="width: 200px; height: 200px;"></canvas> <canvas id="orig" style="width: 200px; height: 200px;"></canvas>
<br><br>Extracted Faces - click on a face to sort by simmilarity and get a known face match:<br> <span id="desc" style="visibility: hidden; font-size: 0.4rem;"></span>
<br><br>Extracted Faces - click on a face to sort by similarity and get a known face match:<br>
<div id="faces"></div> <div id="faces"></div>
</body> </body>
</html> </html>

View File

@ -12,9 +12,10 @@ const userConfig = {
mesh: { enabled: true }, mesh: { enabled: true },
embedding: { enabled: true }, embedding: { enabled: true },
iris: { enabled: false }, iris: { enabled: false },
age: { enabled: true }, age: { enabled: false },
gender: { enabled: true }, gender: { enabled: false },
emotion: { enabled: false }, emotion: { enabled: false },
description: { enabled: true },
}, },
hand: { enabled: false }, hand: { enabled: false },
gesture: { enabled: false }, gesture: { enabled: false },
@ -40,41 +41,52 @@ async function analyze(face) {
// if we have face image tensor, enhance it and display it // if we have face image tensor, enhance it and display it
if (face.tensor) { if (face.tensor) {
const enhanced = human.enhance(face); const enhanced = human.enhance(face);
// const desc = document.getElementById('desc');
// desc.innerText = `{"name":"unknown", "source":"${face.fileName}", "embedding":[${face.embedding}]},`;
navigator.clipboard.writeText(`{"name":"unknown", "source":"${face.fileName}", "embedding":[${face.embedding}]},`);
if (enhanced) { if (enhanced) {
const c = document.getElementById('orig'); const c = document.getElementById('orig');
const squeeze = enhanced.squeeze(); const squeeze = enhanced.squeeze().div(255);
human.tf.browser.toPixels(squeeze, c); await human.tf.browser.toPixels(squeeze, c);
enhanced.dispose(); enhanced.dispose();
squeeze.dispose(); squeeze.dispose();
const ctx = c.getContext('2d');
ctx.font = 'small-caps 0.4rem "Lato"';
ctx.fillStyle = 'rgba(255, 255, 255, 1)';
} }
} }
// loop through all canvases that contain faces // loop through all canvases that contain faces
const canvases = document.getElementsByClassName('face'); const canvases = document.getElementsByClassName('face');
for (const canvas of canvases) { for (const canvas of canvases) {
// calculate simmilarity from selected face to current one in the loop // calculate similarity from selected face to current one in the loop
const simmilarity = human.simmilarity(face.embedding, all[canvas.tag.sample][canvas.tag.face].embedding, 2); const current = all[canvas.tag.sample][canvas.tag.face];
const similarity = human.similarity(face.embedding, current.embedding, 2);
// get best match // get best match
const person = (simmilarity > 0.99) ? await human.match(face.embedding, db) : { name: '' }; const person = await human.match(current.embedding, db);
// draw the canvas and simmilarity score // draw the canvas and similarity score
canvas.title = simmilarity; canvas.title = similarity;
await human.tf.browser.toPixels(all[canvas.tag.sample][canvas.tag.face].tensor, canvas); await human.tf.browser.toPixels(current.tensor, canvas);
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
ctx.font = 'small-caps 1rem "Lato"'; ctx.font = 'small-caps 1rem "Lato"';
ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillStyle = 'rgba(0, 0, 0, 1)';
ctx.fillText(`${(100 * simmilarity).toFixed(1)}% ${person.name}`, 3, 23); ctx.fillText(`${(100 * similarity).toFixed(1)}%`, 3, 23);
ctx.fillStyle = 'rgba(255, 255, 255, 1)'; ctx.fillStyle = 'rgba(255, 255, 255, 1)';
ctx.fillText(`${(100 * simmilarity).toFixed(1)}% ${person.name}`, 4, 24); ctx.fillText(`${(100 * similarity).toFixed(1)}%`, 4, 24);
ctx.font = 'small-caps 0.8rem "Lato"';
ctx.fillText(`${current.age}y ${(100 * current.genderConfidence).toFixed(1)}% ${current.gender}`, 4, canvas.height - 6);
ctx.font = 'small-caps 1rem "Lato"';
if (person.similarity) ctx.fillText(`${(100 * person.similarity).toFixed(1)}% ${person.name}`, 4, canvas.height - 30);
} }
// sort all faces by simmilarity // sort all faces by similarity
const sorted = document.getElementById('faces'); const sorted = document.getElementById('faces');
[...sorted.children] [...sorted.children]
.sort((a, b) => parseFloat(b.title) - parseFloat(a.title)) .sort((a, b) => parseFloat(b.title) - parseFloat(a.title))
.forEach((canvas) => sorted.appendChild(canvas)); .forEach((canvas) => sorted.appendChild(canvas));
} }
function faces(index, res, fileName) { async function faces(index, res, fileName) {
all[index] = res.face; all[index] = res.face;
for (const i in res.face) { for (const i in res.face) {
// log(res.face[i]); // log(res.face[i]);
@ -87,13 +99,19 @@ function faces(index, res, fileName) {
// mouse click on any face canvas triggers analysis // mouse click on any face canvas triggers analysis
canvas.addEventListener('click', (evt) => { canvas.addEventListener('click', (evt) => {
log('Select:', 'Image:', evt.target.tag.sample, 'Face:', evt.target.tag.face, all[evt.target.tag.sample][evt.target.tag.face]); log('Select:', 'Image:', evt.target.tag.sample, 'Face:', evt.target.tag.face, all[evt.target.tag.sample][evt.target.tag.face]);
log('Select:', 'Gender:', all[evt.target.tag.sample][evt.target.tag.face].gender);
analyze(all[evt.target.tag.sample][evt.target.tag.face]); analyze(all[evt.target.tag.sample][evt.target.tag.face]);
}); });
// if we actually got face image tensor, draw canvas with that face // if we actually got face image tensor, draw canvas with that face
if (res.face[i].tensor) { if (res.face[i].tensor) {
human.tf.browser.toPixels(res.face[i].tensor, canvas); await human.tf.browser.toPixels(res.face[i].tensor, canvas);
document.getElementById('faces').appendChild(canvas); document.getElementById('faces').appendChild(canvas);
const ctx = canvas.getContext('2d');
ctx.font = 'small-caps 0.8rem "Lato"';
ctx.fillStyle = 'rgba(255, 255, 255, 1)';
ctx.fillText(`${res.face[i].age}y ${(100 * res.face[i].genderConfidence).toFixed(1)}% ${res.face[i].gender}`, 4, canvas.height - 6);
const person = await human.match(res.face[i].embedding, db);
ctx.font = 'small-caps 1rem "Lato"';
if (person.similarity && person.similarity > 0.60) ctx.fillText(`${(100 * person.similarity).toFixed(1)}% ${person.name}`, 4, canvas.height - 30);
} }
} }
} }
@ -102,8 +120,8 @@ async function process(index, image) {
return new Promise((resolve) => { return new Promise((resolve) => {
const img = new Image(128, 128); const img = new Image(128, 128);
img.onload = () => { // must wait until image is loaded img.onload = () => { // must wait until image is loaded
human.detect(img).then((res) => { human.detect(img).then(async (res) => {
faces(index, res, image); // then wait until image is analyzed await faces(index, res, image); // then wait until image is analyzed
log('Add image:', index + 1, image, 'faces:', res.face.length); log('Add image:', index + 1, image, 'faces:', res.face.length);
document.getElementById('images').appendChild(img); // and finally we can add it document.getElementById('images').appendChild(img); // and finally we can add it
resolve(true); resolve(true);
@ -136,10 +154,14 @@ async function main() {
let images = dir.filter((img) => (img.endsWith('.jpg') && img.includes('sample'))); let images = dir.filter((img) => (img.endsWith('.jpg') && img.includes('sample')));
// enumerate additional private test images in /private, not includded in git repository // enumerate additional private test images in /private, not includded in git repository
res = await fetch('/private/err'); res = await fetch('/private/me');
dir = (res && res.ok) ? await res.json() : []; dir = (res && res.ok) ? await res.json() : [];
// images = images.concat(dir.filter((img) => (img.endsWith('.jpg')))); images = images.concat(dir.filter((img) => (img.endsWith('.jpg'))));
images = dir.filter((img) => (img.endsWith('.jpg')));
// enumerate just possible error images, not includded in git repository
// res = await fetch('/private/err');
// dir = (res && res.ok) ? await res.json() : [];
// images = dir.filter((img) => (img.endsWith('.jpg')));
// download and analyze all images // download and analyze all images
log('Enumerated:', images.length, 'images'); log('Enumerated:', images.length, 'images');

File diff suppressed because one or more lines are too long

View File

@ -93,7 +93,7 @@
</div> </div>
<div id="compare-container" style="display: none" class="compare-image"> <div id="compare-container" style="display: none" class="compare-image">
<canvas id="compare-canvas" width="200px" height="200px"></canvas> <canvas id="compare-canvas" width="200px" height="200px"></canvas>
<div id="simmilarity"></div> <div id="similarity"></div>
</div> </div>
<div id="samples-container" class="samples-container"></div> <div id="samples-container" class="samples-container"></div>
<div id="log" class="log"></div> <div id="log" class="log"></div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

518
dist/human.esm.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

518
dist/human.js vendored

File diff suppressed because one or more lines are too long

6
dist/human.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

16
dist/human.node.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
models/faceres.bin Normal file

Binary file not shown.

315
models/faceres.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "@vladmandic/human", "name": "@vladmandic/human",
"version": "1.1.11", "version": "1.2.0",
"description": "Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition", "description": "Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",
"sideEffects": false, "sideEffects": false,
"main": "dist/human.node.js", "main": "dist/human.node.js",

View File

@ -59,6 +59,11 @@ export interface Config {
enabled: boolean, enabled: boolean,
modelPath: string, modelPath: string,
}, },
description: {
enabled: boolean,
modelPath: string,
skipFrames: number,
},
age: { age: {
enabled: boolean, enabled: boolean,
modelPath: string, modelPath: string,
@ -212,21 +217,14 @@ const config: Config = {
modelPath: '../models/iris.json', modelPath: '../models/iris.json',
}, },
age: { description: {
enabled: true, enabled: true, // to improve accuracy of face embedding extraction it is
modelPath: '../models/age.json', // recommended to enable detector.rotation and mesh.enabled
modelPath: '../models/faceres.json',
skipFrames: 31, // how many frames to go without re-running the detector skipFrames: 31, // how many frames to go without re-running the detector
// only used for video inputs // only used for video inputs
}, },
gender: {
enabled: true,
minConfidence: 0.1, // threshold for discarding a prediction
modelPath: '../models/gender.json',
skipFrames: 32, // how many frames to go without re-running the detector
// only used for video inputs
},
emotion: { emotion: {
enabled: true, enabled: true,
minConfidence: 0.1, // threshold for discarding a prediction minConfidence: 0.1, // threshold for discarding a prediction
@ -234,9 +232,23 @@ const config: Config = {
modelPath: '../models/emotion.json', modelPath: '../models/emotion.json',
}, },
age: {
enabled: false, // obsolete, replaced by description module
modelPath: '../models/age.json',
skipFrames: 31, // how many frames to go without re-running the detector
// only used for video inputs
},
gender: {
enabled: false, // obsolete, replaced by description module
minConfidence: 0.1, // threshold for discarding a prediction
modelPath: '../models/gender.json',
skipFrames: 32, // how many frames to go without re-running the detector
// only used for video inputs
},
embedding: { embedding: {
enabled: false, // to improve accuracy of face embedding extraction it is enabled: false, // obsolete, replaced by description module
// highly recommended to enable detector.rotation and mesh.enabled
modelPath: '../models/mobileface.json', modelPath: '../models/mobileface.json',
}, },
}, },

View File

@ -14,7 +14,7 @@ export async function load(config) {
return model; return model;
} }
export function simmilarity(embedding1, embedding2, order = 2): number { export function similarity(embedding1, embedding2, order = 2): number {
if (!embedding1 || !embedding2) return 0; if (!embedding1 || !embedding2) return 0;
if (embedding1?.length === 0 || embedding2?.length === 0) return 0; if (embedding1?.length === 0 || embedding2?.length === 0) return 0;
if (embedding1?.length !== embedding2?.length) return 0; if (embedding1?.length !== embedding2?.length) return 0;
@ -28,12 +28,12 @@ export function simmilarity(embedding1, embedding2, order = 2): number {
} }
export function match(embedding: Array<number>, db: DB, threshold = 0) { export function match(embedding: Array<number>, db: DB, threshold = 0) {
let best = { simmilarity: 0, name: '', source: '', embedding: [] as number[] }; let best = { similarity: 0, name: '', source: '', embedding: [] as number[] };
if (!embedding || !db || !Array.isArray(embedding) || !Array.isArray(db)) return best; if (!embedding || !db || !Array.isArray(embedding) || !Array.isArray(db)) return best;
for (const f of db) { for (const f of db) {
if (f.embedding && f.name) { if (f.embedding && f.name) {
const perc = simmilarity(embedding, f.embedding); const perc = similarity(embedding, f.embedding);
if (perc > threshold && perc > best.simmilarity) best = { ...f, simmilarity: perc }; if (perc > threshold && perc > best.similarity) best = { ...f, similarity: perc };
} }
} }
return best; return best;

View File

@ -4,6 +4,7 @@ import * as age from './age/age';
import * as gender from './gender/gender'; import * as gender from './gender/gender';
import * as emotion from './emotion/emotion'; import * as emotion from './emotion/emotion';
import * as embedding from './embedding/embedding'; import * as embedding from './embedding/embedding';
import * as faceres from './faceres/faceres';
type Tensor = typeof tf.Tensor; type Tensor = typeof tf.Tensor;
@ -33,6 +34,7 @@ export const detectFace = async (parent, input): Promise<any> => {
let genderRes; let genderRes;
let emotionRes; let emotionRes;
let embeddingRes; let embeddingRes;
let descRes;
const faceRes: Array<{ const faceRes: Array<{
confidence: number, confidence: number,
boxConfidence: number, boxConfidence: number,
@ -111,11 +113,23 @@ export const detectFace = async (parent, input): Promise<any> => {
embeddingRes = parent.config.face.embedding.enabled ? await embedding.predict(face, parent.config) : []; embeddingRes = parent.config.face.embedding.enabled ? await embedding.predict(face, parent.config) : [];
parent.perf.embedding = Math.trunc(now() - timeStamp); parent.perf.embedding = Math.trunc(now() - timeStamp);
} }
parent.analyze('End Emotion:'); parent.analyze('End Embedding:');
// run emotion, inherits face from blazeface
parent.analyze('Start Description:');
if (parent.config.async) {
descRes = parent.config.face.description.enabled ? faceres.predict(face, parent.config) : [];
} else {
parent.state = 'run:description';
timeStamp = now();
descRes = parent.config.face.description.enabled ? await faceres.predict(face.image, parent.config) : [];
parent.perf.embedding = Math.trunc(now() - timeStamp);
}
parent.analyze('End Description:');
// if async wait for results // if async wait for results
if (parent.config.async) { if (parent.config.async) {
[ageRes, genderRes, emotionRes, embeddingRes] = await Promise.all([ageRes, genderRes, emotionRes, embeddingRes]); [ageRes, genderRes, emotionRes, embeddingRes, descRes] = await Promise.all([ageRes, genderRes, emotionRes, embeddingRes, descRes]);
} }
parent.analyze('Finish Face:'); parent.analyze('Finish Face:');
@ -134,11 +148,11 @@ export const detectFace = async (parent, input): Promise<any> => {
// combine results // combine results
faceRes.push({ faceRes.push({
...face, ...face,
age: ageRes.age, age: descRes.age || ageRes.age,
gender: genderRes.gender, gender: descRes.gender || genderRes.gender,
genderConfidence: genderRes.confidence, genderConfidence: descRes.genderConfidence || genderRes.confidence,
embedding: descRes.descriptor || embeddingRes,
emotion: emotionRes, emotion: emotionRes,
embedding: embeddingRes,
iris: (irisSize !== 0) ? Math.trunc(irisSize) / 100 : 0, iris: (irisSize !== 0) ? Math.trunc(irisSize) / 100 : 0,
angle, angle,
tensor: parent.config.face.detector.return ? face.image?.squeeze() : null, tensor: parent.config.face.detector.return ? face.image?.squeeze() : null,

146
src/faceres/faceres.ts Normal file
View File

@ -0,0 +1,146 @@
import { log } from '../helpers';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile';
let model;
let last = { age: 0 };
let skipped = Number.MAX_SAFE_INTEGER;
type Tensor = typeof tf.Tensor;
type DB = Array<{ name: string, source: string, embedding: number[] }>;
export async function load(config) {
if (!model) {
model = await tf.loadGraphModel(config.face.description.modelPath);
if (config.debug) log(`load model: ${config.face.description.modelPath.match(/\/(.*)\./)[1]}`);
}
return model;
}
export function similarity(embedding1, embedding2, order = 2): number {
if (!embedding1 || !embedding2) return 0;
if (embedding1?.length === 0 || embedding2?.length === 0) return 0;
if (embedding1?.length !== embedding2?.length) return 0;
// general minkowski distance, euclidean distance is limited case where order is 2
const distance = 4.0 * embedding1
.map((val, i) => (Math.abs(embedding1[i] - embedding2[i]) ** order)) // distance squared
.reduce((sum, now) => (sum + now), 0) // sum all distances
** (1 / order); // get root of
const res = Math.max(0, 100 - distance) / 100.0;
return res;
}
export function match(embedding: Array<number>, db: DB, threshold = 0) {
let best = { similarity: 0, name: '', source: '', embedding: [] as number[] };
if (!embedding || !db || !Array.isArray(embedding) || !Array.isArray(db)) return best;
for (const f of db) {
if (f.embedding && f.name) {
const perc = similarity(embedding, f.embedding);
if (perc > threshold && perc > best.similarity) best = { ...f, similarity: perc };
}
}
return best;
}
export function enhance(input): Tensor {
const image = tf.tidy(() => {
// input received from detector is already normalized to 0..1
// input is also assumed to be straightened
const tensor = input.image || input.tensor || input;
/*
// do a tight crop of image and resize it to fit the model
const box = [[0.05, 0.15, 0.85, 0.85]]; // empyrical values for top, left, bottom, right
if (!(tensor instanceof tf.Tensor)) return null;
const crop = (tensor.shape.length === 3)
? tf.image.cropAndResize(tf.expandDims(tensor, 0), box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) // add batch dimension if missing
: tf.image.cropAndResize(tensor, box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
*/
const crop = tf.image.resizeBilinear(tensor, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false); // just resize to fit the embedding model
/*
// convert to black&white to avoid colorization impact
const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale: https://www.mathworks.com/help/matlab/ref/rgb2gray.html
const [red, green, blue] = tf.split(crop, 3, 3);
const redNorm = tf.mul(red, rgb[0]);
const greenNorm = tf.mul(green, rgb[1]);
const blueNorm = tf.mul(blue, rgb[2]);
const grayscale = tf.addN([redNorm, greenNorm, blueNorm]);
const merge = tf.stack([grayscale, grayscale, grayscale], 3).squeeze(4);
*/
/*
// optional increase image contrast
// or do it per-channel so mean is done on each channel
// or do it based on histogram
const mean = merge.mean();
const factor = 5;
const contrast = merge.sub(mean).mul(factor).add(mean);
*/
/*
// normalize brightness from 0..1
const darken = crop.sub(crop.min());
const lighten = darken.div(darken.max());
*/
const norm = crop.mul(255);
return norm;
});
return image;
}
export async function predict(image, config) {
if (!model) return null;
if ((skipped < config.face.description.skipFrames) && config.videoOptimized && last.age && (last.age > 0)) {
skipped++;
return last;
}
if (config.videoOptimized) skipped = 0;
else skipped = Number.MAX_SAFE_INTEGER;
return new Promise(async (resolve) => {
// const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);
// const enhanced = tf.mul(resize, [255.0]);
// tf.dispose(resize);
const enhanced = enhance(image);
let resT;
const obj = {
age: <number>0,
gender: <string>'unknown',
genderConfidence: <number>0,
descriptor: <number[]>[] };
if (!config.profile) {
if (config.face.description.enabled) resT = await model.predict(enhanced);
} else {
const profileAge = config.face.description.enabled ? await tf.profile(() => model.predict(enhanced)) : {};
resT = profileAge.result.clone();
profileAge.result.dispose();
profile.run('age', profileAge);
}
tf.dispose(enhanced);
if (resT) {
tf.tidy(() => {
const gender = resT.find((t) => t.shape[1] === 1).dataSync();
const confidence = Math.trunc(200 * Math.abs((gender[0] - 0.5))) / 100;
if (confidence > config.face.gender.minConfidence) {
obj.gender = gender[0] <= 0.5 ? 'female' : 'male';
obj.genderConfidence = Math.min(0.99, confidence);
}
const age = resT.find((t) => t.shape[1] === 100).argMax(1).dataSync()[0];
const all = resT.find((t) => t.shape[1] === 100).dataSync();
obj.age = Math.round(all[age - 1] > all[age + 1] ? 10 * age - 100 * all[age - 1] : 10 * age + 100 * all[age + 1]) / 10;
const desc = resT.find((t) => t.shape[1] === 1024);
// const reshape = desc.reshape([128, 8]);
// const reduce = reshape.logSumExp(1); // reduce 2nd dimension by calculating logSumExp on it
obj.descriptor = [...desc.dataSync()];
});
resT.forEach((t) => tf.dispose(t));
}
last = obj;
resolve(obj);
});
}

View File

@ -59,24 +59,39 @@ export async function predict(image, config) {
enhance.dispose(); enhance.dispose();
if (genderT) { if (genderT) {
const data = genderT.dataSync(); if (!Array.isArray(genderT)) {
if (alternative) { const data = genderT.dataSync();
// returns two values 0..1, bigger one is prediction if (alternative) {
if (data[0] > config.face.gender.minConfidence || data[1] > config.face.gender.minConfidence) { // returns two values 0..1, bigger one is prediction
obj.gender = data[0] > data[1] ? 'female' : 'male'; if (data[0] > config.face.gender.minConfidence || data[1] > config.face.gender.minConfidence) {
obj.confidence = data[0] > data[1] ? (Math.trunc(100 * data[0]) / 100) : (Math.trunc(100 * data[1]) / 100); obj.gender = data[0] > data[1] ? 'female' : 'male';
obj.confidence = data[0] > data[1] ? (Math.trunc(100 * data[0]) / 100) : (Math.trunc(100 * data[1]) / 100);
}
} else {
// returns one value 0..1, .5 is prediction threshold
const confidence = Math.trunc(200 * Math.abs((data[0] - 0.5))) / 100;
if (confidence > config.face.gender.minConfidence) {
obj.gender = data[0] <= 0.5 ? 'female' : 'male';
obj.confidence = Math.min(0.99, confidence);
}
} }
genderT.dispose();
} else { } else {
// returns one value 0..1, .5 is prediction threshold const gender = genderT[0].dataSync();
const confidence = Math.trunc(200 * Math.abs((data[0] - 0.5))) / 100; const confidence = Math.trunc(200 * Math.abs((gender[0] - 0.5))) / 100;
if (confidence > config.face.gender.minConfidence) { if (confidence > config.face.gender.minConfidence) {
obj.gender = data[0] <= 0.5 ? 'female' : 'male'; obj.gender = gender[0] <= 0.5 ? 'female' : 'male';
obj.confidence = Math.min(0.99, confidence); obj.confidence = Math.min(0.99, confidence);
} }
/*
let age = genderT[1].argMax(1).dataSync()[0];
const all = genderT[1].dataSync();
age = Math.round(all[age - 1] > all[age + 1] ? 10 * age - 100 * all[age - 1] : 10 * age + 100 * all[age + 1]) / 10;
const descriptor = genderT[1].dataSync();
*/
genderT.forEach((t) => tf.dispose(t));
} }
} }
genderT.dispose();
last = obj; last = obj;
resolve(obj); resolve(obj);
}); });

View File

@ -6,6 +6,7 @@ import * as faceall from './faceall';
import * as facemesh from './blazeface/facemesh'; import * as facemesh from './blazeface/facemesh';
import * as age from './age/age'; import * as age from './age/age';
import * as gender from './gender/gender'; import * as gender from './gender/gender';
import * as faceres from './faceres/faceres';
import * as emotion from './emotion/emotion'; import * as emotion from './emotion/emotion';
import * as embedding from './embedding/embedding'; import * as embedding from './embedding/embedding';
import * as posenet from './posenet/posenet'; import * as posenet from './posenet/posenet';
@ -71,6 +72,7 @@ export class Human {
emotion: Model | null, emotion: Model | null,
embedding: Model | null, embedding: Model | null,
nanodet: Model | null, nanodet: Model | null,
faceres: Model | null,
}; };
classes: { classes: {
facemesh: typeof facemesh; facemesh: typeof facemesh;
@ -80,6 +82,7 @@ export class Human {
body: typeof posenet | typeof blazepose; body: typeof posenet | typeof blazepose;
hand: typeof handpose; hand: typeof handpose;
nanodet: typeof nanodet; nanodet: typeof nanodet;
faceres: typeof faceres;
}; };
sysinfo: { platform: string, agent: string }; sysinfo: { platform: string, agent: string };
perf: any; perf: any;
@ -112,6 +115,7 @@ export class Human {
emotion: null, emotion: null,
embedding: null, embedding: null,
nanodet: null, nanodet: null,
faceres: null,
}; };
// export access to image processing // export access to image processing
// @ts-ignore // @ts-ignore
@ -122,6 +126,7 @@ export class Human {
age, age,
gender, gender,
emotion, emotion,
faceres,
body: this.config.body.modelPath.includes('posenet') ? posenet : blazepose, body: this.config.body.modelPath.includes('posenet') ? posenet : blazepose,
hand: handpose, hand: handpose,
nanodet, nanodet,
@ -160,19 +165,20 @@ export class Human {
return null; return null;
} }
simmilarity(embedding1: Array<number>, embedding2: Array<number>): number { similarity(embedding1: Array<number>, embedding2: Array<number>): number {
if (this.config.face.embedding.enabled) return embedding.simmilarity(embedding1, embedding2); if (this.config.face.description.enabled) return faceres.similarity(embedding1, embedding2);
if (this.config.face.embedding.enabled) return embedding.similarity(embedding1, embedding2);
return 0; return 0;
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
enhance(input: Tensor): Tensor | null { enhance(input: Tensor): Tensor | null {
return embedding.enhance(input); return faceres.enhance(input);
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
match(faceEmbedding: Array<number>, db: Array<{ name: string, source: string, embedding: number[] }>, threshold = 0): { name: string, source: string, simmilarity: number, embedding: number[] } { match(faceEmbedding: Array<number>, db: Array<{ name: string, source: string, embedding: number[] }>, threshold = 0): { name: string, source: string, similarity: number, embedding: number[] } {
return embedding.match(faceEmbedding, db, threshold); return faceres.match(faceEmbedding, db, threshold);
} }
// preload models, not explicitly required as it's done automatically on first use // preload models, not explicitly required as it's done automatically on first use
@ -204,6 +210,7 @@ export class Human {
this.models.posenet, this.models.posenet,
this.models.blazepose, this.models.blazepose,
this.models.nanodet, this.models.nanodet,
this.models.faceres,
] = await Promise.all([ ] = await Promise.all([
this.models.face || (this.config.face.enabled ? facemesh.load(this.config) : null), this.models.face || (this.config.face.enabled ? facemesh.load(this.config) : null),
this.models.age || ((this.config.face.enabled && this.config.face.age.enabled) ? age.load(this.config) : null), this.models.age || ((this.config.face.enabled && this.config.face.age.enabled) ? age.load(this.config) : null),
@ -214,6 +221,7 @@ export class Human {
this.models.posenet || (this.config.body.enabled && this.config.body.modelPath.includes('posenet') ? posenet.load(this.config) : null), this.models.posenet || (this.config.body.enabled && this.config.body.modelPath.includes('posenet') ? posenet.load(this.config) : null),
this.models.posenet || (this.config.body.enabled && this.config.body.modelPath.includes('blazepose') ? blazepose.load(this.config) : null), this.models.posenet || (this.config.body.enabled && this.config.body.modelPath.includes('blazepose') ? blazepose.load(this.config) : null),
this.models.nanodet || (this.config.object.enabled ? nanodet.load(this.config) : null), this.models.nanodet || (this.config.object.enabled ? nanodet.load(this.config) : null),
this.models.faceres || ((this.config.face.enabled && this.config.face.description.enabled) ? faceres.load(this.config) : null),
]); ]);
} else { } else {
if (this.config.face.enabled && !this.models.face) this.models.face = await facemesh.load(this.config); if (this.config.face.enabled && !this.models.face) this.models.face = await facemesh.load(this.config);
@ -225,6 +233,7 @@ export class Human {
if (this.config.body.enabled && !this.models.posenet && this.config.body.modelPath.includes('posenet')) this.models.posenet = await posenet.load(this.config); if (this.config.body.enabled && !this.models.posenet && this.config.body.modelPath.includes('posenet')) this.models.posenet = await posenet.load(this.config);
if (this.config.body.enabled && !this.models.blazepose && this.config.body.modelPath.includes('blazepose')) this.models.blazepose = await blazepose.load(this.config); if (this.config.body.enabled && !this.models.blazepose && this.config.body.modelPath.includes('blazepose')) this.models.blazepose = await blazepose.load(this.config);
if (this.config.object.enabled && !this.models.nanodet) this.models.nanodet = await nanodet.load(this.config); if (this.config.object.enabled && !this.models.nanodet) this.models.nanodet = await nanodet.load(this.config);
if (this.config.face.enabled && this.config.face.description.enabled && !this.models.faceres) this.models.faceres = await faceres.load(this.config);
} }
if (this.#firstRun) { if (this.#firstRun) {

File diff suppressed because one or more lines are too long

View File

@ -117,7 +117,7 @@
<li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#load" class="tsd-kind-icon">load</a></li> <li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#load" class="tsd-kind-icon">load</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#match" class="tsd-kind-icon">match</a></li> <li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#match" class="tsd-kind-icon">match</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#profiledata" class="tsd-kind-icon">profile<wbr>Data</a></li> <li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#profiledata" class="tsd-kind-icon">profile<wbr>Data</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#simmilarity" class="tsd-kind-icon">simmilarity</a></li> <li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#similarity" class="tsd-kind-icon">similarity</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#warmup" class="tsd-kind-icon">warmup</a></li> <li class="tsd-kind-method tsd-parent-kind-class"><a href="human.html#warmup" class="tsd-kind-icon">warmup</a></li>
</ul> </ul>
</section> </section>
@ -152,7 +152,7 @@
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class"> <section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class">
<a name="classes" class="tsd-anchor"></a> <a name="classes" class="tsd-anchor"></a>
<h3>classes</h3> <h3>classes</h3>
<div class="tsd-signature tsd-kind-icon">classes<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{ </span>age<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>body<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>emotion<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>facemesh<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>hand<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>nanodet<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol"> }</span></div> <div class="tsd-signature tsd-kind-icon">classes<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{ </span>age<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>body<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>emotion<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>facemesh<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>faceres<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>hand<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol">; </span>nanodet<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span><span class="tsd-signature-symbol"> }</span></div>
<aside class="tsd-sources"> <aside class="tsd-sources">
</aside> </aside>
<div class="tsd-type-declaration"> <div class="tsd-type-declaration">
@ -170,6 +170,9 @@
<li class="tsd-parameter"> <li class="tsd-parameter">
<h5>facemesh<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span></h5> <h5>facemesh<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span></h5>
</li> </li>
<li class="tsd-parameter">
<h5>faceres<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span></h5>
</li>
<li class="tsd-parameter"> <li class="tsd-parameter">
<h5>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span></h5> <h5>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">__module</span></h5>
</li> </li>
@ -422,7 +425,7 @@
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class"> <section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class">
<a name="models" class="tsd-anchor"></a> <a name="models" class="tsd-anchor"></a>
<h3>models</h3> <h3>models</h3>
<div class="tsd-signature tsd-kind-icon">models<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{ </span>age<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>blazepose<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>emotion<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>face<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">MediaPipeFaceMesh</span><span class="tsd-signature-symbol">; </span>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>handpose<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HandPose</span><span class="tsd-signature-symbol">; </span>iris<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>nanodet<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>posenet<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">PoseNet</span><span class="tsd-signature-symbol"> }</span></div> <div class="tsd-signature tsd-kind-icon">models<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{ </span>age<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>blazepose<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>emotion<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>face<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">MediaPipeFaceMesh</span><span class="tsd-signature-symbol">; </span>faceres<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>handpose<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">HandPose</span><span class="tsd-signature-symbol">; </span>iris<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>nanodet<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span><span class="tsd-signature-symbol">; </span>posenet<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">PoseNet</span><span class="tsd-signature-symbol"> }</span></div>
<aside class="tsd-sources"> <aside class="tsd-sources">
</aside> </aside>
<div class="tsd-type-declaration"> <div class="tsd-type-declaration">
@ -443,6 +446,9 @@
<li class="tsd-parameter"> <li class="tsd-parameter">
<h5>face<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">MediaPipeFaceMesh</span></h5> <h5>face<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">MediaPipeFaceMesh</span></h5>
</li> </li>
<li class="tsd-parameter">
<h5>faceres<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span></h5>
</li>
<li class="tsd-parameter"> <li class="tsd-parameter">
<h5>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span></h5> <h5>gender<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">null</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">Object</span></h5>
</li> </li>
@ -577,7 +583,7 @@
<a name="match" class="tsd-anchor"></a> <a name="match" class="tsd-anchor"></a>
<h3>match</h3> <h3>match</h3>
<ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class"> <ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon">match<span class="tsd-signature-symbol">(</span>faceEmbedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span>, db<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">; </span>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">; </span>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> }</span><span class="tsd-signature-symbol">[]</span>, threshold<span class="tsd-signature-symbol">?: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">; </span>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">; </span>simmilarity<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">; </span>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> }</span></li> <li class="tsd-signature tsd-kind-icon">match<span class="tsd-signature-symbol">(</span>faceEmbedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span>, db<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">; </span>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">; </span>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> }</span><span class="tsd-signature-symbol">[]</span>, threshold<span class="tsd-signature-symbol">?: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">; </span>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">; </span>similarity<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">; </span>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> }</span></li>
</ul> </ul>
<ul class="tsd-descriptions"> <ul class="tsd-descriptions">
<li class="tsd-description"> <li class="tsd-description">
@ -595,7 +601,7 @@
<h5>threshold: <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol"> = 0</span></h5> <h5>threshold: <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol"> = 0</span></h5>
</li> </li>
</ul> </ul>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-symbol">{ </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">; </span>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">; </span>simmilarity<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">; </span>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> }</span></h4> <h4 class="tsd-returns-title">Returns <span class="tsd-signature-symbol">{ </span>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">; </span>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">; </span>similarity<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">; </span>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> }</span></h4>
<ul class="tsd-parameters"> <ul class="tsd-parameters">
<li class="tsd-parameter"> <li class="tsd-parameter">
<h5>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span></h5> <h5>embedding<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span></h5>
@ -604,7 +610,7 @@
<h5>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span></h5> <h5>name<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span></h5>
</li> </li>
<li class="tsd-parameter"> <li class="tsd-parameter">
<h5>simmilarity<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5> <h5>similarity<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5>
</li> </li>
<li class="tsd-parameter"> <li class="tsd-parameter">
<h5>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span></h5> <h5>source<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span></h5>
@ -628,10 +634,10 @@
</ul> </ul>
</section> </section>
<section class="tsd-panel tsd-member tsd-kind-method tsd-parent-kind-class"> <section class="tsd-panel tsd-member tsd-kind-method tsd-parent-kind-class">
<a name="simmilarity" class="tsd-anchor"></a> <a name="similarity" class="tsd-anchor"></a>
<h3>simmilarity</h3> <h3>similarity</h3>
<ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class"> <ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon">simmilarity<span class="tsd-signature-symbol">(</span>embedding1<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span>, embedding2<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></li> <li class="tsd-signature tsd-kind-icon">similarity<span class="tsd-signature-symbol">(</span>embedding1<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span>, embedding2<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></li>
</ul> </ul>
<ul class="tsd-descriptions"> <ul class="tsd-descriptions">
<li class="tsd-description"> <li class="tsd-description">
@ -739,7 +745,7 @@
<a href="human.html#profiledata" class="tsd-kind-icon">profile<wbr>Data</a> <a href="human.html#profiledata" class="tsd-kind-icon">profile<wbr>Data</a>
</li> </li>
<li class=" tsd-kind-method tsd-parent-kind-class"> <li class=" tsd-kind-method tsd-parent-kind-class">
<a href="human.html#simmilarity" class="tsd-kind-icon">simmilarity</a> <a href="human.html#similarity" class="tsd-kind-icon">similarity</a>
</li> </li>
<li class=" tsd-kind-method tsd-parent-kind-class"> <li class=" tsd-kind-method tsd-parent-kind-class">
<a href="human.html#warmup" class="tsd-kind-icon">warmup</a> <a href="human.html#warmup" class="tsd-kind-icon">warmup</a>

File diff suppressed because one or more lines are too long

5
types/config.d.ts vendored
View File

@ -56,6 +56,11 @@ export interface Config {
enabled: boolean; enabled: boolean;
modelPath: string; modelPath: string;
}; };
description: {
enabled: boolean;
modelPath: string;
skipFrames: number;
};
age: { age: {
enabled: boolean; enabled: boolean;
modelPath: string; modelPath: string;

View File

@ -6,9 +6,9 @@ declare type DB = Array<{
embedding: number[]; embedding: number[];
}>; }>;
export declare function load(config: any): Promise<any>; export declare function load(config: any): Promise<any>;
export declare function simmilarity(embedding1: any, embedding2: any, order?: number): number; export declare function similarity(embedding1: any, embedding2: any, order?: number): number;
export declare function match(embedding: Array<number>, db: DB, threshold?: number): { export declare function match(embedding: Array<number>, db: DB, threshold?: number): {
simmilarity: number; similarity: number;
name: string; name: string;
source: string; source: string;
embedding: number[]; embedding: number[];

18
types/faceres/faceres.d.ts vendored Normal file
View File

@ -0,0 +1,18 @@
import * as tf from '../../dist/tfjs.esm.js';
declare type Tensor = typeof tf.Tensor;
declare type DB = Array<{
name: string;
source: string;
embedding: number[];
}>;
export declare function load(config: any): Promise<any>;
export declare function similarity(embedding1: any, embedding2: any, order?: number): number;
export declare function match(embedding: Array<number>, db: DB, threshold?: number): {
similarity: number;
name: string;
source: string;
embedding: number[];
};
export declare function enhance(input: any): Tensor;
export declare function predict(image: any, config: any): Promise<unknown>;
export {};

7
types/human.d.ts vendored
View File

@ -2,6 +2,7 @@ import * as tf from '../dist/tfjs.esm.js';
import * as facemesh from './blazeface/facemesh'; import * as facemesh from './blazeface/facemesh';
import * as age from './age/age'; import * as age from './age/age';
import * as gender from './gender/gender'; import * as gender from './gender/gender';
import * as faceres from './faceres/faceres';
import * as emotion from './emotion/emotion'; import * as emotion from './emotion/emotion';
import * as posenet from './posenet/posenet'; import * as posenet from './posenet/posenet';
import * as handpose from './handpose/handpose'; import * as handpose from './handpose/handpose';
@ -63,6 +64,7 @@ export declare class Human {
emotion: Model | null; emotion: Model | null;
embedding: Model | null; embedding: Model | null;
nanodet: Model | null; nanodet: Model | null;
faceres: Model | null;
}; };
classes: { classes: {
facemesh: typeof facemesh; facemesh: typeof facemesh;
@ -72,6 +74,7 @@ export declare class Human {
body: typeof posenet | typeof blazepose; body: typeof posenet | typeof blazepose;
hand: typeof handpose; hand: typeof handpose;
nanodet: typeof nanodet; nanodet: typeof nanodet;
faceres: typeof faceres;
}; };
sysinfo: { sysinfo: {
platform: string; platform: string;
@ -90,7 +93,7 @@ export declare class Human {
} | {}; } | {};
/** @hidden */ /** @hidden */
analyze: (...msg: any[]) => void; analyze: (...msg: any[]) => void;
simmilarity(embedding1: Array<number>, embedding2: Array<number>): number; similarity(embedding1: Array<number>, embedding2: Array<number>): number;
enhance(input: Tensor): Tensor | null; enhance(input: Tensor): Tensor | null;
match(faceEmbedding: Array<number>, db: Array<{ match(faceEmbedding: Array<number>, db: Array<{
name: string; name: string;
@ -99,7 +102,7 @@ export declare class Human {
}>, threshold?: number): { }>, threshold?: number): {
name: string; name: string;
source: string; source: string;
simmilarity: number; similarity: number;
embedding: number[]; embedding: number[];
}; };
load(userConfig?: Config | Object): Promise<void>; load(userConfig?: Config | Object): Promise<void>;