mirror of https://github.com/vladmandic/human
normalize all scores
parent
65ca7fead2
commit
e2ed67e591
|
@ -1,6 +1,6 @@
|
||||||
# @vladmandic/human
|
# @vladmandic/human
|
||||||
|
|
||||||
Version: **1.3.0**
|
Version: **1.3.1**
|
||||||
Description: **Human: AI-powered 3D Face Detection, Face Description & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition**
|
Description: **Human: AI-powered 3D Face Detection, Face Description & 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,8 +9,9 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### **HEAD -> main** 2021/03/30 mandic00@live.com
|
### **1.3.1** 2021/03/30 mandic00@live.com
|
||||||
|
|
||||||
|
- added face3d demo
|
||||||
- initial work on face3d three.js demo
|
- initial work on face3d three.js demo
|
||||||
- enable buffering
|
- enable buffering
|
||||||
- new icons
|
- new icons
|
||||||
|
|
|
@ -12,7 +12,7 @@ const userConfig = {
|
||||||
profile: false,
|
profile: false,
|
||||||
warmup: 'full',
|
warmup: 'full',
|
||||||
videoOptimized: false,
|
videoOptimized: false,
|
||||||
filter: { enabled: true },
|
filter: { enabled: false },
|
||||||
face: { enabled: false,
|
face: { enabled: false,
|
||||||
mesh: { enabled: true },
|
mesh: { enabled: true },
|
||||||
iris: { enabled: true },
|
iris: { enabled: true },
|
||||||
|
|
35
demo/node.js
35
demo/node.js
|
@ -11,8 +11,8 @@ const Human = require('../dist/human.node.js').default; // or const Human = requ
|
||||||
let human = null;
|
let human = null;
|
||||||
|
|
||||||
const myConfig = {
|
const myConfig = {
|
||||||
// backend: 'tensorflow',
|
backend: 'tensorflow',
|
||||||
console: true,
|
debug: true,
|
||||||
videoOptimized: false,
|
videoOptimized: false,
|
||||||
async: false,
|
async: false,
|
||||||
face: {
|
face: {
|
||||||
|
@ -22,17 +22,15 @@ const myConfig = {
|
||||||
iris: { modelPath: 'file://models/iris.json', enabled: true },
|
iris: { modelPath: 'file://models/iris.json', enabled: true },
|
||||||
description: { modelPath: 'file://models/faceres.json', enabled: true },
|
description: { modelPath: 'file://models/faceres.json', enabled: true },
|
||||||
emotion: { modelPath: 'file://models/emotion.json', enabled: true },
|
emotion: { modelPath: 'file://models/emotion.json', enabled: true },
|
||||||
age: { modelPath: 'file://models/age.json', enabled: false },
|
|
||||||
gender: { modelPath: 'file://models/gender.json', enabled: false },
|
|
||||||
embedding: { modelPath: 'file://models/mobileface.json', enabled: false },
|
|
||||||
},
|
},
|
||||||
// body: { modelPath: 'file://models/blazepose.json', enabled: true },
|
|
||||||
body: { modelPath: 'file://models/posenet.json', enabled: true },
|
|
||||||
hand: {
|
hand: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
detector: { modelPath: 'file://models/handdetect.json' },
|
detector: { modelPath: 'file://models/handdetect.json' },
|
||||||
skeleton: { modelPath: 'file://models/handskeleton.json' },
|
skeleton: { modelPath: 'file://models/handskeleton.json' },
|
||||||
},
|
},
|
||||||
|
// body: { modelPath: 'file://models/efficientpose.json', enabled: true },
|
||||||
|
// body: { modelPath: 'file://models/blazepose.json', enabled: true },
|
||||||
|
body: { modelPath: 'file://models/posenet.json', enabled: true },
|
||||||
object: { modelPath: 'file://models/nanodet.json', enabled: true },
|
object: { modelPath: 'file://models/nanodet.json', enabled: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,6 +64,29 @@ async function detect(input) {
|
||||||
// dispose image tensor as we no longer need it
|
// dispose image tensor as we no longer need it
|
||||||
image.dispose();
|
image.dispose();
|
||||||
// print data to console
|
// print data to console
|
||||||
|
log.data('Results:');
|
||||||
|
for (let i = 0; i < result.face.length; i++) {
|
||||||
|
const face = result.face[i];
|
||||||
|
const emotion = face.emotion.reduce((prev, curr) => (prev.score > curr.score ? prev : curr));
|
||||||
|
log.data(` Face: #${i} boxConfidence:${face.boxConfidence} faceConfidence:${face.boxConfidence} age:${face.age} genderConfidence:${face.genderConfidence} gender:${face.gender} emotionScore:${emotion.score} emotion:${emotion.emotion} iris:${face.iris}`);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < result.body.length; i++) {
|
||||||
|
const body = result.body[i];
|
||||||
|
log.data(` Body: #${i} score:${body.score}`);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < result.hand.length; i++) {
|
||||||
|
const hand = result.hand[i];
|
||||||
|
log.data(` Hand: #${i} confidence:${hand.confidence}`);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < result.gesture.length; i++) {
|
||||||
|
const [key, val] = Object.entries(result.gesture[i]);
|
||||||
|
log.data(` Gesture: ${key[0]}#${key[1]} gesture:${val[1]}`);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < result.object.length; i++) {
|
||||||
|
const object = result.object[i];
|
||||||
|
log.data(` Object: #${i} score:${object.score} label:${object.label}`);
|
||||||
|
}
|
||||||
|
result.face.length = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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
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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -41,9 +41,9 @@ export class MediaPipeFaceMesh {
|
||||||
(prediction.box.endPoint[1] - prediction.box.startPoint[1]) / input.shape[1],
|
(prediction.box.endPoint[1] - prediction.box.startPoint[1]) / input.shape[1],
|
||||||
] : [];
|
] : [];
|
||||||
results.push({
|
results.push({
|
||||||
confidence: prediction.faceConfidence || prediction.boxConfidence || 0,
|
confidence: Math.round(100 * prediction.faceConfidence || 100 * prediction.boxConfidence || 0) / 100,
|
||||||
boxConfidence: prediction.boxConfidence,
|
boxConfidence: Math.round(100 * prediction.boxConfidence) / 100,
|
||||||
faceConfidence: prediction.faceConfidence,
|
faceConfidence: Math.round(100 * prediction.faceConfidence) / 100,
|
||||||
box,
|
box,
|
||||||
boxRaw,
|
boxRaw,
|
||||||
mesh,
|
mesh,
|
||||||
|
|
|
@ -53,5 +53,6 @@ export async function predict(image, config) {
|
||||||
presence: (100 - Math.trunc(100 / (1 + Math.exp(points[depth * i + 4])))) / 100, // reverse sigmoid value
|
presence: (100 - Math.trunc(100 / (1 + Math.exp(points[depth * i + 4])))) / 100, // reverse sigmoid value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return [{ keypoints }];
|
const score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);
|
||||||
|
return [{ score, keypoints }];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as profile from '../profile';
|
import * as profile from '../profile';
|
||||||
|
|
||||||
let model;
|
let model;
|
||||||
let keypoints = { };
|
let keypoints: Array<any> = [];
|
||||||
let skipped = Number.MAX_SAFE_INTEGER;
|
let skipped = Number.MAX_SAFE_INTEGER;
|
||||||
|
|
||||||
const bodyParts = ['head', 'neck', 'rightShoulder', 'rightElbow', 'rightWrist', 'chest', 'leftShoulder', 'leftElbow', 'leftWrist', 'pelvis', 'rightHip', 'rightKnee', 'rightAnkle', 'leftHip', 'leftKnee', 'leftAnkle'];
|
const bodyParts = ['head', 'neck', 'rightShoulder', 'rightElbow', 'rightWrist', 'chest', 'leftShoulder', 'leftElbow', 'leftWrist', 'pelvis', 'rightHip', 'rightKnee', 'rightAnkle', 'leftHip', 'leftKnee', 'leftAnkle'];
|
||||||
|
@ -56,9 +56,9 @@ export async function predict(image, config) {
|
||||||
let resT;
|
let resT;
|
||||||
|
|
||||||
if (!config.profile) {
|
if (!config.profile) {
|
||||||
if (config.body.enabled) resT = await model.executeAsync(tensor);
|
if (config.body.enabled) resT = await model.predict(tensor);
|
||||||
} else {
|
} else {
|
||||||
const profileT = config.body.enabled ? await tf.profile(() => model.executeAsync(tensor)) : {};
|
const profileT = config.body.enabled ? await tf.profile(() => model.predict(tensor)) : {};
|
||||||
resT = profileT.result.clone();
|
resT = profileT.result.clone();
|
||||||
profileT.result.dispose();
|
profileT.result.dispose();
|
||||||
profile.run('body', profileT);
|
profile.run('body', profileT);
|
||||||
|
@ -79,7 +79,7 @@ export async function predict(image, config) {
|
||||||
if (score > config.body.scoreThreshold) {
|
if (score > config.body.scoreThreshold) {
|
||||||
parts.push({
|
parts.push({
|
||||||
id,
|
id,
|
||||||
score,
|
score: Math.round(100 * score) / 100,
|
||||||
part: bodyParts[id],
|
part: bodyParts[id],
|
||||||
positionRaw: {
|
positionRaw: {
|
||||||
xRaw: x / model.inputs[0].shape[2], // x normalized to 0..1
|
xRaw: x / model.inputs[0].shape[2], // x normalized to 0..1
|
||||||
|
@ -95,6 +95,7 @@ export async function predict(image, config) {
|
||||||
stack.forEach((s) => tf.dispose(s));
|
stack.forEach((s) => tf.dispose(s));
|
||||||
keypoints = parts;
|
keypoints = parts;
|
||||||
}
|
}
|
||||||
resolve([{ keypoints }]);
|
const score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);
|
||||||
|
resolve([{ score, keypoints }]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ export class HandPose {
|
||||||
(prediction.box.bottomRight[0] - prediction.box.topLeft[0]) / input.shape[2],
|
(prediction.box.bottomRight[0] - prediction.box.topLeft[0]) / input.shape[2],
|
||||||
(prediction.box.bottomRight[1] - prediction.box.topLeft[1]) / input.shape[1],
|
(prediction.box.bottomRight[1] - prediction.box.topLeft[1]) / input.shape[1],
|
||||||
];
|
];
|
||||||
hands.push({ confidence: prediction.confidence, box, boxRaw, landmarks: prediction.landmarks, annotations });
|
hands.push({ confidence: Math.round(100 * prediction.confidence) / 100, box, boxRaw, landmarks: prediction.landmarks, annotations });
|
||||||
}
|
}
|
||||||
return hands;
|
return hands;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ async function process(res, inputSize, outputShape, config) {
|
||||||
const result = {
|
const result = {
|
||||||
id: id++,
|
id: id++,
|
||||||
strideSize,
|
strideSize,
|
||||||
score,
|
score: Math.round(100 * score) / 100,
|
||||||
class: j + 1,
|
class: j + 1,
|
||||||
label: labels[j].label,
|
label: labels[j].label,
|
||||||
center: [Math.trunc(outputShape[0] * cx), Math.trunc(outputShape[1] * cy)],
|
center: [Math.trunc(outputShape[0] * cx), Math.trunc(outputShape[1] * cy)],
|
||||||
|
@ -113,9 +113,9 @@ export async function predict(image, config) {
|
||||||
|
|
||||||
let objectT;
|
let objectT;
|
||||||
if (!config.profile) {
|
if (!config.profile) {
|
||||||
if (config.object.enabled) objectT = await model.executeAsync(transpose);
|
if (config.object.enabled) objectT = await model.predict(transpose);
|
||||||
} else {
|
} else {
|
||||||
const profileObject = config.object.enabled ? await tf.profile(() => model.executeAsync(transpose)) : {};
|
const profileObject = config.object.enabled ? await tf.profile(() => model.predict(transpose)) : {};
|
||||||
objectT = profileObject.result;
|
objectT = profileObject.result;
|
||||||
profile.run('object', profileObject);
|
profile.run('object', profileObject);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFw
|
||||||
// Else start a new detection instance at the position of the root.
|
// Else start a new detection instance at the position of the root.
|
||||||
const keypoints = decodePose.decodePose(root, scoresBuffer, offsetsBuffer, defaultOutputStride, displacementsFwdBuffer, displacementsBwdBuffer);
|
const keypoints = decodePose.decodePose(root, scoresBuffer, offsetsBuffer, defaultOutputStride, displacementsFwdBuffer, displacementsBwdBuffer);
|
||||||
const score = getInstanceScore(poses, squaredNmsRadius, keypoints);
|
const score = getInstanceScore(poses, squaredNmsRadius, keypoints);
|
||||||
if (score > scoreThreshold) poses.push({ keypoints, score });
|
if (score > scoreThreshold) poses.push({ keypoints, score: Math.round(100 * score) / 100 });
|
||||||
}
|
}
|
||||||
return poses;
|
return poses;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export declare function load(config: any): Promise<any>;
|
export declare function load(config: any): Promise<any>;
|
||||||
export declare function predict(image: any, config: any): Promise<{
|
export declare function predict(image: any, config: any): Promise<{
|
||||||
|
score: any;
|
||||||
keypoints: {
|
keypoints: {
|
||||||
id: any;
|
id: any;
|
||||||
part: any;
|
part: any;
|
||||||
|
|
Loading…
Reference in New Issue