mirror of https://github.com/vladmandic/human
fix for human.draw labels and typedefs
parent
b28327d063
commit
06f20e86c2
|
@ -9,8 +9,9 @@
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### **HEAD -> main** 2021/10/19 mandic00@live.com
|
### **HEAD -> main** 2021/10/21 mandic00@live.com
|
||||||
|
|
||||||
|
- add human.custom.esm using custom tfjs build
|
||||||
|
|
||||||
### **2.3.5** 2021/10/19 mandic00@live.com
|
### **2.3.5** 2021/10/19 mandic00@live.com
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ const drawOptions = {
|
||||||
drawBoxes: true,
|
drawBoxes: true,
|
||||||
drawGaze: true,
|
drawGaze: true,
|
||||||
drawLabels: true,
|
drawLabels: true,
|
||||||
|
drawGestures: true,
|
||||||
drawPolygons: true,
|
drawPolygons: true,
|
||||||
drawPoints: false,
|
drawPoints: false,
|
||||||
fillPolygons: false,
|
fillPolygons: false,
|
||||||
|
|
|
@ -48,11 +48,11 @@ export const detectFace = async (parent /* instance of human */, input: Tensor):
|
||||||
// run emotion, inherits face from blazeface
|
// run emotion, inherits face from blazeface
|
||||||
parent.analyze('Start Emotion:');
|
parent.analyze('Start Emotion:');
|
||||||
if (parent.config.async) {
|
if (parent.config.async) {
|
||||||
emotionRes = parent.config.face.emotion.enabled ? emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};
|
emotionRes = parent.config.face.emotion.enabled ? emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : null;
|
||||||
} else {
|
} else {
|
||||||
parent.state = 'run:emotion';
|
parent.state = 'run:emotion';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
emotionRes = parent.config.face.emotion.enabled ? await emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};
|
emotionRes = parent.config.face.emotion.enabled ? await emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : null;
|
||||||
parent.performance.emotion = Math.trunc(now() - timeStamp);
|
parent.performance.emotion = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
parent.analyze('End Emotion:');
|
parent.analyze('End Emotion:');
|
||||||
|
@ -60,11 +60,11 @@ export const detectFace = async (parent /* instance of human */, input: Tensor):
|
||||||
// run antispoof, inherits face from blazeface
|
// run antispoof, inherits face from blazeface
|
||||||
parent.analyze('Start AntiSpoof:');
|
parent.analyze('Start AntiSpoof:');
|
||||||
if (parent.config.async) {
|
if (parent.config.async) {
|
||||||
antispoofRes = parent.config.face.antispoof.enabled ? antispoof.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};
|
antispoofRes = parent.config.face.antispoof.enabled ? antispoof.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : null;
|
||||||
} else {
|
} else {
|
||||||
parent.state = 'run:antispoof';
|
parent.state = 'run:antispoof';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
antispoofRes = parent.config.face.antispoof.enabled ? await antispoof.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};
|
antispoofRes = parent.config.face.antispoof.enabled ? await antispoof.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : null;
|
||||||
parent.performance.antispoof = Math.trunc(now() - timeStamp);
|
parent.performance.antispoof = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
parent.analyze('End AntiSpoof:');
|
parent.analyze('End AntiSpoof:');
|
||||||
|
@ -86,11 +86,11 @@ export const detectFace = async (parent /* instance of human */, input: Tensor):
|
||||||
// run emotion, inherits face from blazeface
|
// run emotion, inherits face from blazeface
|
||||||
parent.analyze('Start Description:');
|
parent.analyze('Start Description:');
|
||||||
if (parent.config.async) {
|
if (parent.config.async) {
|
||||||
descRes = parent.config.face.description.enabled ? faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : [];
|
descRes = parent.config.face.description.enabled ? faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : null;
|
||||||
} else {
|
} else {
|
||||||
parent.state = 'run:description';
|
parent.state = 'run:description';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
descRes = parent.config.face.description.enabled ? await faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : [];
|
descRes = parent.config.face.description.enabled ? await faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : null;
|
||||||
parent.performance.embedding = Math.trunc(now() - timeStamp);
|
parent.performance.embedding = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
parent.analyze('End Description:');
|
parent.analyze('End Description:');
|
||||||
|
@ -124,10 +124,10 @@ export const detectFace = async (parent /* instance of human */, input: Tensor):
|
||||||
faceRes.push({
|
faceRes.push({
|
||||||
...faces[i],
|
...faces[i],
|
||||||
id: i,
|
id: i,
|
||||||
age: descRes.age,
|
age: descRes?.age,
|
||||||
gender: descRes.gender,
|
gender: descRes?.gender,
|
||||||
genderScore: descRes.genderScore,
|
genderScore: descRes?.genderScore,
|
||||||
embedding: descRes.descriptor,
|
embedding: descRes?.descriptor,
|
||||||
emotion: emotionRes,
|
emotion: emotionRes,
|
||||||
real: antispoofRes,
|
real: antispoofRes,
|
||||||
iris: irisSize !== 0 ? Math.trunc(500 / irisSize / 11.7) / 100 : 0,
|
iris: irisSize !== 0 ? Math.trunc(500 / irisSize / 11.7) / 100 : 0,
|
||||||
|
|
|
@ -135,7 +135,7 @@ export class Human {
|
||||||
* - canvas: draw processed canvas which is a processed copy of the input
|
* - canvas: draw processed canvas which is a processed copy of the input
|
||||||
* - all: meta-function that performs: canvas, face, body, hand
|
* - all: meta-function that performs: canvas, face, body, hand
|
||||||
*/
|
*/
|
||||||
draw: { canvas, face, body, hand, gesture, object, person, all, options: DrawOptions };
|
draw: { canvas: typeof draw.canvas, face: typeof draw.face, body: typeof draw.body, hand: typeof draw.hand, gesture: typeof draw.gesture, object: typeof draw.object, person: typeof draw.person, all: typeof draw.all, options: DrawOptions };
|
||||||
|
|
||||||
/** Currently loaded models
|
/** Currently loaded models
|
||||||
* @internal
|
* @internal
|
||||||
|
|
|
@ -37,6 +37,7 @@ export interface DrawOptions {
|
||||||
roundRect: number,
|
roundRect: number,
|
||||||
drawPoints: boolean,
|
drawPoints: boolean,
|
||||||
drawLabels: boolean,
|
drawLabels: boolean,
|
||||||
|
drawGestures: boolean,
|
||||||
drawBoxes: boolean,
|
drawBoxes: boolean,
|
||||||
drawPolygons: boolean,
|
drawPolygons: boolean,
|
||||||
drawGaze: boolean,
|
drawGaze: boolean,
|
||||||
|
@ -58,6 +59,7 @@ export const options: DrawOptions = {
|
||||||
drawPoints: <boolean>false,
|
drawPoints: <boolean>false,
|
||||||
drawLabels: <boolean>true,
|
drawLabels: <boolean>true,
|
||||||
drawBoxes: <boolean>true,
|
drawBoxes: <boolean>true,
|
||||||
|
drawGestures: <boolean>true,
|
||||||
drawPolygons: <boolean>true,
|
drawPolygons: <boolean>true,
|
||||||
drawGaze: <boolean>true,
|
drawGaze: <boolean>true,
|
||||||
fillPolygons: <boolean>false,
|
fillPolygons: <boolean>false,
|
||||||
|
@ -166,24 +168,26 @@ function arrow(ctx: CanvasRenderingContext2D, from: Point, to: Point, radius = 5
|
||||||
export async function gesture(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array<GestureResult>, drawOptions?: Partial<DrawOptions>) {
|
export async function gesture(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array<GestureResult>, drawOptions?: Partial<DrawOptions>) {
|
||||||
const localOptions = mergeDeep(options, drawOptions);
|
const localOptions = mergeDeep(options, drawOptions);
|
||||||
if (!result || !inCanvas) return;
|
if (!result || !inCanvas) return;
|
||||||
const ctx = getCanvasContext(inCanvas);
|
if (localOptions.drawGestures) {
|
||||||
ctx.font = localOptions.font;
|
const ctx = getCanvasContext(inCanvas);
|
||||||
ctx.fillStyle = localOptions.color;
|
ctx.font = localOptions.font;
|
||||||
let i = 1;
|
ctx.fillStyle = localOptions.color;
|
||||||
for (let j = 0; j < result.length; j++) {
|
let i = 1;
|
||||||
let where: unknown[] = []; // what&where is a record
|
for (let j = 0; j < result.length; j++) {
|
||||||
let what: unknown[] = []; // what&where is a record
|
let where: unknown[] = []; // what&where is a record
|
||||||
[where, what] = Object.entries(result[j]);
|
let what: unknown[] = []; // what&where is a record
|
||||||
if ((what.length > 1) && ((what[1] as string).length > 0)) {
|
[where, what] = Object.entries(result[j]);
|
||||||
const who = where[1] as number > 0 ? `#${where[1]}` : '';
|
if ((what.length > 1) && ((what[1] as string).length > 0)) {
|
||||||
const label = `${where[0]} ${who}: ${what[1]}`;
|
const who = where[1] as number > 0 ? `#${where[1]}` : '';
|
||||||
if (localOptions.shadowColor && localOptions.shadowColor !== '') {
|
const label = `${where[0]} ${who}: ${what[1]}`;
|
||||||
ctx.fillStyle = localOptions.shadowColor;
|
if (localOptions.shadowColor && localOptions.shadowColor !== '') {
|
||||||
ctx.fillText(label, 8, 2 + (i * localOptions.lineHeight));
|
ctx.fillStyle = localOptions.shadowColor;
|
||||||
|
ctx.fillText(label, 8, 2 + (i * localOptions.lineHeight));
|
||||||
|
}
|
||||||
|
ctx.fillStyle = localOptions.labelColor;
|
||||||
|
ctx.fillText(label, 6, 0 + (i * localOptions.lineHeight));
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
ctx.fillStyle = localOptions.labelColor;
|
|
||||||
ctx.fillText(label, 6, 0 + (i * localOptions.lineHeight));
|
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,33 +201,35 @@ export async function face(inCanvas: HTMLCanvasElement | OffscreenCanvas, result
|
||||||
ctx.strokeStyle = localOptions.color;
|
ctx.strokeStyle = localOptions.color;
|
||||||
ctx.fillStyle = localOptions.color;
|
ctx.fillStyle = localOptions.color;
|
||||||
if (localOptions.drawBoxes) rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3], localOptions);
|
if (localOptions.drawBoxes) rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3], localOptions);
|
||||||
// silly hack since fillText does not suport new line
|
if (localOptions.drawLabels) {
|
||||||
const labels:string[] = [];
|
// silly hack since fillText does not suport new line
|
||||||
labels.push(`face: ${Math.trunc(100 * f.score)}%`);
|
const labels:string[] = [];
|
||||||
if (f.genderScore) labels.push(`${f.gender || ''} ${Math.trunc(100 * f.genderScore)}%`);
|
labels.push(`face: ${Math.trunc(100 * f.score)}%`);
|
||||||
if (f.age) labels.push(`age: ${f.age || ''}`);
|
if (f.genderScore) labels.push(`${f.gender || ''} ${Math.trunc(100 * f.genderScore)}%`);
|
||||||
if (f.iris) labels.push(`distance: ${f.iris}`);
|
if (f.age) labels.push(`age: ${f.age || ''}`);
|
||||||
if (f.real) labels.push(`Real: ${Math.trunc(100 * f.real)}%`);
|
if (f.iris) labels.push(`distance: ${f.iris}`);
|
||||||
if (f.emotion && f.emotion.length > 0) {
|
if (f.real) labels.push(`real: ${Math.trunc(100 * f.real)}%`);
|
||||||
const emotion = f.emotion.map((a) => `${Math.trunc(100 * a.score)}% ${a.emotion}`);
|
if (f.emotion && f.emotion.length > 0) {
|
||||||
if (emotion.length > 3) emotion.length = 3;
|
const emotion = f.emotion.map((a) => `${Math.trunc(100 * a.score)}% ${a.emotion}`);
|
||||||
labels.push(emotion.join(' '));
|
if (emotion.length > 3) emotion.length = 3;
|
||||||
}
|
labels.push(emotion.join(' '));
|
||||||
if (f.rotation && f.rotation.angle && f.rotation.gaze) {
|
}
|
||||||
if (f.rotation.angle.roll) labels.push(`roll: ${rad2deg(f.rotation.angle.roll)}° yaw:${rad2deg(f.rotation.angle.yaw)}° pitch:${rad2deg(f.rotation.angle.pitch)}°`);
|
if (f.rotation && f.rotation.angle && f.rotation.gaze) {
|
||||||
if (f.rotation.gaze.bearing) labels.push(`gaze: ${rad2deg(f.rotation.gaze.bearing)}°`);
|
if (f.rotation.angle.roll) labels.push(`roll: ${rad2deg(f.rotation.angle.roll)}° yaw:${rad2deg(f.rotation.angle.yaw)}° pitch:${rad2deg(f.rotation.angle.pitch)}°`);
|
||||||
}
|
if (f.rotation.gaze.bearing) labels.push(`gaze: ${rad2deg(f.rotation.gaze.bearing)}°`);
|
||||||
if (labels.length === 0) labels.push('face');
|
}
|
||||||
ctx.fillStyle = localOptions.color;
|
if (labels.length === 0) labels.push('face');
|
||||||
for (let i = labels.length - 1; i >= 0; i--) {
|
ctx.fillStyle = localOptions.color;
|
||||||
const x = Math.max(f.box[0], 0);
|
for (let i = labels.length - 1; i >= 0; i--) {
|
||||||
const y = i * localOptions.lineHeight + f.box[1];
|
const x = Math.max(f.box[0], 0);
|
||||||
if (localOptions.shadowColor && localOptions.shadowColor !== '') {
|
const y = i * localOptions.lineHeight + f.box[1];
|
||||||
ctx.fillStyle = localOptions.shadowColor;
|
if (localOptions.shadowColor && localOptions.shadowColor !== '') {
|
||||||
ctx.fillText(labels[i], x + 5, y + 16);
|
ctx.fillStyle = localOptions.shadowColor;
|
||||||
|
ctx.fillText(labels[i], x + 5, y + 16);
|
||||||
|
}
|
||||||
|
ctx.fillStyle = localOptions.labelColor;
|
||||||
|
ctx.fillText(labels[i], x + 4, y + 15);
|
||||||
}
|
}
|
||||||
ctx.fillStyle = localOptions.labelColor;
|
|
||||||
ctx.fillText(labels[i], x + 4, y + 15);
|
|
||||||
}
|
}
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
if (f.mesh && f.mesh.length > 0) {
|
if (f.mesh && f.mesh.length > 0) {
|
||||||
|
|
Loading…
Reference in New Issue