mirror of https://github.com/vladmandic/human
guard against invalid input images
parent
f8703e3dc0
commit
8de79a92b2
|
@ -1,6 +1,6 @@
|
||||||
# @vladmandic/human
|
# @vladmandic/human
|
||||||
|
|
||||||
Version: **1.1.0**
|
Version: **1.1.1**
|
||||||
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,8 +9,9 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### **HEAD -> main** 2021/03/11 mandic00@live.com
|
### **1.1.1** 2021/03/12 mandic00@live.com
|
||||||
|
|
||||||
|
- switched face embedding to mobileface
|
||||||
|
|
||||||
### **1.0.4** 2021/03/11 mandic00@live.com
|
### **1.0.4** 2021/03/11 mandic00@live.com
|
||||||
|
|
||||||
|
|
13
TODO.md
13
TODO.md
|
@ -2,19 +2,6 @@
|
||||||
|
|
||||||
- Strong typing
|
- Strong typing
|
||||||
- Automated testing
|
- Automated testing
|
||||||
- Guard against corrupt input
|
|
||||||
- Improve face embedding
|
|
||||||
- Dynamic sample processing
|
|
||||||
- Explore EfficientPose
|
- Explore EfficientPose
|
||||||
<https://github.com/daniegr/EfficientPose>
|
<https://github.com/daniegr/EfficientPose>
|
||||||
<https://github.com/PINTO0309/PINTO_model_zoo/tree/main/084_EfficientPose>
|
<https://github.com/PINTO0309/PINTO_model_zoo/tree/main/084_EfficientPose>
|
||||||
|
|
||||||
## WiP: Embedding
|
|
||||||
|
|
||||||
- Implement offsetRaw
|
|
||||||
|
|
||||||
full with and without rotation
|
|
||||||
full with and without embedding
|
|
||||||
full with any without mesh
|
|
||||||
embedding with and without mesh
|
|
||||||
boxRaw and meshRaw with and without mesh
|
|
||||||
|
|
|
@ -3,9 +3,8 @@ import Human from '../src/human';
|
||||||
import Menu from './menu.js';
|
import Menu from './menu.js';
|
||||||
import GLBench from './gl-bench.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 = {
|
const userConfig = {
|
||||||
backend: 'wasm',
|
backend: 'wasm',
|
||||||
async: false,
|
async: false,
|
||||||
|
@ -16,7 +15,6 @@ const userConfig = {
|
||||||
gesture: { enabled: false },
|
gesture: { enabled: false },
|
||||||
body: { enabled: false, modelPath: '../models/blazepose.json' },
|
body: { enabled: false, modelPath: '../models/blazepose.json' },
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|
||||||
const human = new Human(userConfig);
|
const human = new Human(userConfig);
|
||||||
|
|
||||||
|
|
12
package.json
12
package.json
|
@ -21,11 +21,11 @@
|
||||||
"url": "git+https://github.com/vladmandic/human.git"
|
"url": "git+https://github.com/vladmandic/human.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",
|
"start": "node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation demo/node.js",
|
||||||
"dev": "npm install && node server/serve.js",
|
"dev": "node --trace-warnings --unhandled-rejections=strict --trace-uncaught server/serve.js",
|
||||||
"build": "rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",
|
"build": "rimraf dist/* && rimraf types/* && node --trace-warnings --unhandled-rejections=strict --trace-uncaught server/build.js && node server/changelog.js",
|
||||||
"lint": "eslint src demo server",
|
"lint": "eslint src server demo",
|
||||||
"test": "eslint src demo server"
|
"test": "npm run lint && npm run start"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"tensorflowjs",
|
"tensorflowjs",
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
"@vladmandic/pilogger": "^0.2.14",
|
"@vladmandic/pilogger": "^0.2.14",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"esbuild": "=0.9.0",
|
"esbuild": "^0.9.2",
|
||||||
"eslint": "^7.21.0",
|
"eslint": "^7.21.0",
|
||||||
"eslint-config-airbnb-base": "^14.2.1",
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.22.1",
|
||||||
|
|
21
src/draw.ts
21
src/draw.ts
|
@ -20,8 +20,8 @@ export const options = {
|
||||||
bufferedOutput: false,
|
bufferedOutput: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
function point(ctx, x, y) {
|
function point(ctx, x, y, z = null) {
|
||||||
ctx.fillStyle = options.color;
|
ctx.fillStyle = options.useDepth && z ? `rgba(${127.5 + (2 * (z || 0))}, ${127.5 - (2 * (z || 0))}, 255, 0.3)` : options.color;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(x, y, options.pointSize, 0, 2 * Math.PI);
|
ctx.arc(x, y, options.pointSize, 0, 2 * Math.PI);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
@ -53,7 +53,11 @@ function lines(ctx, points: number[] = []) {
|
||||||
if (points === undefined || points.length === 0) return;
|
if (points === undefined || points.length === 0) return;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(points[0][0], points[0][1]);
|
ctx.moveTo(points[0][0], points[0][1]);
|
||||||
for (const pt of points) ctx.lineTo(pt[0], parseInt(pt[1]));
|
for (const pt of points) {
|
||||||
|
ctx.strokeStyle = options.useDepth && pt[2] ? `rgba(${127.5 + (2 * pt[2])}, ${127.5 - (2 * pt[2])}, 255, 0.3)` : options.color;
|
||||||
|
ctx.fillStyle = options.useDepth && pt[2] ? `rgba(${127.5 + (2 * pt[2])}, ${127.5 - (2 * pt[2])}, 255, 0.3)` : options.color;
|
||||||
|
ctx.lineTo(pt[0], parseInt(pt[1]));
|
||||||
|
}
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
if (options.fillPolygons) {
|
if (options.fillPolygons) {
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
|
@ -118,6 +122,7 @@ export async function face(inCanvas, result) {
|
||||||
ctx.fillStyle = options.color;
|
ctx.fillStyle = options.color;
|
||||||
if (options.drawBoxes) {
|
if (options.drawBoxes) {
|
||||||
rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3]);
|
rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3]);
|
||||||
|
// rect(ctx, inCanvas.width * f.boxRaw[0], inCanvas.height * f.boxRaw[1], inCanvas.width * f.boxRaw[2], inCanvas.height * f.boxRaw[3]);
|
||||||
}
|
}
|
||||||
// silly hack since fillText does not suport new line
|
// silly hack since fillText does not suport new line
|
||||||
const labels:string[] = [];
|
const labels:string[] = [];
|
||||||
|
@ -146,21 +151,17 @@ export async function face(inCanvas, result) {
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
if (f.mesh) {
|
if (f.mesh) {
|
||||||
if (options.drawPoints) {
|
if (options.drawPoints) {
|
||||||
for (const pt of f.mesh) {
|
for (const pt of f.mesh) point(ctx, pt[0], pt[1], pt[2]);
|
||||||
ctx.fillStyle = options.useDepth ? `rgba(${127.5 + (2 * pt[2])}, ${127.5 - (2 * pt[2])}, 255, 0.5)` : options.color;
|
// for (const pt of f.meshRaw) point(ctx, pt[0] * inCanvas.offsetWidth, pt[1] * inCanvas.offsetHeight, pt[2]);
|
||||||
point(ctx, pt[0], pt[1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (options.drawPolygons) {
|
if (options.drawPolygons) {
|
||||||
|
ctx.lineWidth = 1;
|
||||||
for (let i = 0; i < triangulation.length / 3; i++) {
|
for (let i = 0; i < triangulation.length / 3; i++) {
|
||||||
const points = [
|
const points = [
|
||||||
triangulation[i * 3 + 0],
|
triangulation[i * 3 + 0],
|
||||||
triangulation[i * 3 + 1],
|
triangulation[i * 3 + 1],
|
||||||
triangulation[i * 3 + 2],
|
triangulation[i * 3 + 2],
|
||||||
].map((index) => f.mesh[index]);
|
].map((index) => f.mesh[index]);
|
||||||
ctx.strokeStyle = options.useDepth ? `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.3)` : options.color;
|
|
||||||
ctx.fillStyle = options.useDepth ? `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.3)` : options.color;
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
lines(ctx, points);
|
lines(ctx, points);
|
||||||
}
|
}
|
||||||
// iris: array[center, left, top, right, bottom]
|
// iris: array[center, left, top, right, bottom]
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { log } from './log';
|
||||||
import * as tf from '../dist/tfjs.esm.js';
|
import * as tf from '../dist/tfjs.esm.js';
|
||||||
import * as fxImage from './imagefx';
|
import * as fxImage from './imagefx';
|
||||||
|
|
||||||
|
const maxSize = 2048;
|
||||||
// internal temp canvases
|
// internal temp canvases
|
||||||
let inCanvas = null;
|
let inCanvas = null;
|
||||||
let outCanvas = null;
|
let outCanvas = null;
|
||||||
|
@ -22,6 +23,14 @@ export function process(input, config): { tensor, canvas } {
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || (input.shape && (input.shape[2] > 0));
|
const originalHeight = input.naturalHeight || input.videoHeight || input.height || (input.shape && (input.shape[2] > 0));
|
||||||
let targetWidth = originalWidth;
|
let targetWidth = originalWidth;
|
||||||
let targetHeight = originalHeight;
|
let targetHeight = originalHeight;
|
||||||
|
if (targetWidth > maxSize) {
|
||||||
|
targetWidth = maxSize;
|
||||||
|
targetHeight = targetWidth * originalHeight / originalWidth;
|
||||||
|
}
|
||||||
|
if (targetHeight > maxSize) {
|
||||||
|
targetHeight = maxSize;
|
||||||
|
targetWidth = targetHeight * originalWidth / originalHeight;
|
||||||
|
}
|
||||||
if (config.filter.width > 0) targetWidth = config.filter.width;
|
if (config.filter.width > 0) targetWidth = config.filter.width;
|
||||||
else if (config.filter.height > 0) targetWidth = originalWidth * (config.filter.height / originalHeight);
|
else if (config.filter.height > 0) targetWidth = originalWidth * (config.filter.height / originalHeight);
|
||||||
if (config.filter.height > 0) targetHeight = config.filter.height;
|
if (config.filter.height > 0) targetHeight = config.filter.height;
|
||||||
|
|
Loading…
Reference in New Issue