update build
parent
63476fcbc0
commit
936ecba7ec
|
@ -57,6 +57,7 @@
|
|||
"no-restricted-syntax": "off",
|
||||
"no-return-assign": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"no-promise-executor-return": "off",
|
||||
"node/no-missing-import": ["error", { "tryExtensions": [".js", ".json", ".ts"] }],
|
||||
"node/no-unpublished-import": "off",
|
||||
"node/no-unpublished-require": "off",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
## Changelog
|
||||
|
||||
### **HEAD -> master** 2021/12/03 mandic00@live.com
|
||||
### **HEAD -> master** 2021/12/06 mandic00@live.com
|
||||
|
||||
- release preview
|
||||
- switch to custom tfjs and new typedefs
|
||||
|
|
|
@ -62,9 +62,6 @@ Three NodeJS examples are:
|
|||
Regular usage of `FaceAPI` from `NodeJS`
|
||||
Using external `canvas` module to load images
|
||||
Which also allows for image drawing and saving inside `NodeJS` environment
|
||||
- `/demo/node-wasm.js`:
|
||||
Same as `node-canvas`, but using `WASM` backend in `NodeJS` environment
|
||||
Because why not :)
|
||||
- `/demo/node-multiprocess.js`:
|
||||
Multiprocessing showcase that uses pool of worker processes
|
||||
(`node-multiprocess-worker.js`)
|
||||
|
|
|
@ -121,7 +121,7 @@ async function main() {
|
|||
await faceapi.tf.ready();
|
||||
|
||||
// check version
|
||||
log(`Version: FaceAPI ${str(faceapi?.version.faceapi || '(not loaded)')} TensorFlow/JS ${str(faceapi?.tf?.version_core || '(not loaded)')} Backend: ${str(faceapi?.tf?.getBackend() || '(not loaded)')}`);
|
||||
log(`Version: FaceAPI ${str(faceapi?.version || '(not loaded)')} TensorFlow/JS ${str(faceapi?.tf?.version_core || '(not loaded)')} Backend: ${str(faceapi?.tf?.getBackend() || '(not loaded)')}`);
|
||||
log(`Flags: ${JSON.stringify(faceapi?.tf?.ENV.flags || { tf: 'not loaded' })}`);
|
||||
|
||||
// load face-api models
|
||||
|
|
|
@ -56,7 +56,7 @@ async function main() {
|
|||
await faceapi.tf.ENV.set('DEBUG', false);
|
||||
await faceapi.tf.ready();
|
||||
|
||||
log.state(`Version: TensorFlow/JS ${faceapi.tf?.version_core} FaceAPI ${faceapi.version.faceapi} Backend: ${faceapi.tf?.getBackend()}`);
|
||||
log.state(`Version: TensorFlow/JS ${faceapi.tf?.version_core} FaceAPI ${faceapi.version} Backend: ${faceapi.tf?.getBackend()}`);
|
||||
|
||||
log.info('Loading FaceAPI models');
|
||||
const modelPath = path.join(__dirname, modelPathRoot);
|
||||
|
|
|
@ -53,7 +53,7 @@ async function main() {
|
|||
await faceapi.tf.enableProdMode();
|
||||
await faceapi.tf.ENV.set('DEBUG', false);
|
||||
await faceapi.tf.ready();
|
||||
log.state('Worker: PID:', process.pid, `TensorFlow/JS ${faceapi.tf.version_core} FaceAPI ${faceapi.version.faceapi} Backend: ${faceapi.tf.getBackend()}`);
|
||||
log.state('Worker: PID:', process.pid, `TensorFlow/JS ${faceapi.tf.version_core} FaceAPI ${faceapi.version} Backend: ${faceapi.tf.getBackend()}`);
|
||||
|
||||
// and load and initialize facepi models
|
||||
const modelPath = path.join(__dirname, modelPathRoot);
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
// @ts-nocheck
|
||||
|
||||
const fs = require('fs');
|
||||
const process = require('process');
|
||||
const path = require('path');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-unpublished-require
|
||||
const log = require('@vladmandic/pilogger');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-unpublished-require, no-unused-vars, @typescript-eslint/no-unused-vars
|
||||
const tf = require('@tensorflow/tfjs');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-unpublished-require
|
||||
require('@tensorflow/tfjs-backend-wasm');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-unpublished-require, no-unused-vars
|
||||
const canvas = require('canvas');
|
||||
const faceapi = require('../dist/face-api.node-cpu.js'); // this is equivalent to '@vladmandic/faceapi'
|
||||
|
||||
const modelPathRoot = '../model';
|
||||
const imgPathRoot = './demo'; // modify to include your sample images
|
||||
const minConfidence = 0.15;
|
||||
const maxResults = 5;
|
||||
let optionsSSDMobileNet;
|
||||
|
||||
async function image(input) {
|
||||
const img = await canvas.loadImage(input);
|
||||
const c = canvas.createCanvas(img.width, img.height);
|
||||
const ctx = c.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height);
|
||||
// const out = fs.createWriteStream('test.jpg');
|
||||
// const stream = c.createJPEGStream({ quality: 0.6, progressive: true, chromaSubsampling: true });
|
||||
// stream.pipe(out);
|
||||
return c;
|
||||
}
|
||||
|
||||
async function detect(tensor) {
|
||||
const result = await faceapi
|
||||
.detectAllFaces(tensor, optionsSSDMobileNet)
|
||||
.withFaceLandmarks()
|
||||
.withFaceExpressions()
|
||||
.withFaceDescriptors()
|
||||
.withAgeAndGender();
|
||||
return result;
|
||||
}
|
||||
|
||||
function print(face) {
|
||||
const expression = Object.entries(face.expressions).reduce((acc, val) => ((val[1] > acc[1]) ? val : acc), ['', 0]);
|
||||
const box = [face.alignedRect._box._x, face.alignedRect._box._y, face.alignedRect._box._width, face.alignedRect._box._height];
|
||||
const gender = `Gender: ${Math.round(100 * face.genderProbability)}% ${face.gender}`;
|
||||
log.data(`Detection confidence: ${Math.round(100 * face.detection._score)}% ${gender} Age: ${Math.round(10 * face.age) / 10} Expression: ${Math.round(100 * expression[1])}% ${expression[0]} Box: ${box.map((a) => Math.round(a))}`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
log.header();
|
||||
log.info('FaceAPI single-process test');
|
||||
|
||||
faceapi.env.monkeyPatch({ Canvas: canvas.Canvas, Image: canvas.Image, ImageData: canvas.ImageData });
|
||||
|
||||
await faceapi.tf.setBackend('wasm');
|
||||
await faceapi.tf.enableProdMode();
|
||||
await faceapi.tf.ENV.set('DEBUG', false);
|
||||
await faceapi.tf.ready();
|
||||
|
||||
log.state(`Version: TensorFlow/JS ${faceapi.tf?.version_core} FaceAPI ${faceapi.version.faceapi} Backend: ${faceapi.tf?.getBackend()}`);
|
||||
|
||||
log.info('Loading FaceAPI models');
|
||||
const modelPath = path.join(__dirname, modelPathRoot);
|
||||
await faceapi.nets.ssdMobilenetv1.loadFromDisk(modelPath);
|
||||
await faceapi.nets.ageGenderNet.loadFromDisk(modelPath);
|
||||
await faceapi.nets.faceLandmark68Net.loadFromDisk(modelPath);
|
||||
await faceapi.nets.faceRecognitionNet.loadFromDisk(modelPath);
|
||||
await faceapi.nets.faceExpressionNet.loadFromDisk(modelPath);
|
||||
optionsSSDMobileNet = new faceapi.SsdMobilenetv1Options({ minConfidence, maxResults });
|
||||
|
||||
if (process.argv.length !== 3) {
|
||||
const t0 = process.hrtime.bigint();
|
||||
const dir = fs.readdirSync(imgPathRoot);
|
||||
let numImages = 0;
|
||||
for (const img of dir) {
|
||||
if (!img.toLocaleLowerCase().endsWith('.jpg')) continue;
|
||||
numImages += 1;
|
||||
const c = await image(path.join(imgPathRoot, img));
|
||||
const result = await detect(c);
|
||||
log.data('Image:', img, 'Detected faces:', result.length);
|
||||
for (const face of result) print(face);
|
||||
}
|
||||
const t1 = process.hrtime.bigint();
|
||||
log.info('Processed', numImages, 'images in', Math.trunc(parseInt(t1 - t0) / 1000 / 1000), 'ms');
|
||||
} else {
|
||||
const param = process.argv[2];
|
||||
if (fs.existsSync(param) || param.startsWith('http:') || param.startsWith('https:')) {
|
||||
const c = await image(param);
|
||||
const result = await detect(c);
|
||||
log.data('Image:', param, 'Detected faces:', result.length);
|
||||
for (const face of result) print(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
|
@ -95,7 +95,7 @@ async function main() {
|
|||
await faceapi.tf.ENV.set('DEBUG', false);
|
||||
await faceapi.tf.ready();
|
||||
|
||||
log.state(`Version: TensorFlow/JS ${faceapi.tf?.version_core} FaceAPI ${faceapi.version.faceapi} Backend: ${faceapi.tf?.getBackend()}`);
|
||||
log.state(`Version: TensorFlow/JS ${faceapi.tf?.version_core} FaceAPI ${faceapi.version} Backend: ${faceapi.tf?.getBackend()}`);
|
||||
|
||||
log.info('Loading FaceAPI models');
|
||||
const modelPath = path.join(__dirname, modelPathRoot);
|
||||
|
|
|
@ -191,7 +191,7 @@ async function main() {
|
|||
await faceapi.tf.ready();
|
||||
|
||||
// check version
|
||||
log(`Version: FaceAPI ${str(faceapi?.version.faceapi || '(not loaded)')} TensorFlow/JS ${str(faceapi?.tf?.version_core || '(not loaded)')} Backend: ${str(faceapi?.tf?.getBackend() || '(not loaded)')}`);
|
||||
log(`Version: FaceAPI ${str(faceapi?.version || '(not loaded)')} TensorFlow/JS ${str(faceapi?.tf?.version_core || '(not loaded)')} Backend: ${str(faceapi?.tf?.getBackend() || '(not loaded)')}`);
|
||||
// log(`Flags: ${JSON.stringify(faceapi?.tf?.ENV.flags || { tf: 'not loaded' })}`);
|
||||
|
||||
await setupFaceAPI();
|
||||
|
|
12
package.json
12
package.json
|
@ -42,7 +42,7 @@
|
|||
],
|
||||
"devDependencies": {
|
||||
"@canvas/image": "^1.0.1",
|
||||
"@microsoft/api-extractor": "^7.18.19",
|
||||
"@microsoft/api-extractor": "^7.18.21",
|
||||
"@tensorflow/tfjs": "^3.11.0",
|
||||
"@tensorflow/tfjs-backend-cpu": "^3.11.0",
|
||||
"@tensorflow/tfjs-backend-wasm": "^3.11.0",
|
||||
|
@ -56,16 +56,16 @@
|
|||
"@tensorflow/tfjs-node-gpu": "^3.11.0",
|
||||
"@types/node": "^16.11.11",
|
||||
"@types/offscreencanvas": "^2019.6.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.5.0",
|
||||
"@typescript-eslint/parser": "^5.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.6.0",
|
||||
"@typescript-eslint/parser": "^5.6.0",
|
||||
"@vladmandic/build": "^0.6.6",
|
||||
"@vladmandic/pilogger": "^0.3.5",
|
||||
"@vladmandic/tfjs": "github:vladmandic/tfjs",
|
||||
"canvas": "^2.8.0",
|
||||
"chokidar": "^3.5.2",
|
||||
"dayjs": "^1.10.7",
|
||||
"esbuild": "^0.14.1",
|
||||
"eslint": "^8.3.0",
|
||||
"esbuild": "^0.14.2",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-json": "^3.1.0",
|
||||
|
@ -74,7 +74,7 @@
|
|||
"node-fetch": "^3.1.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"seedrandom": "^3.0.5",
|
||||
"simple-git": "^2.47.1",
|
||||
"simple-git": "^2.48.0",
|
||||
"tslib": "^2.3.1",
|
||||
"typedoc": "^0.22.10",
|
||||
"typescript": "4.5.2"
|
||||
|
|
Loading…
Reference in New Issue