From 936ecba7ec546af3f44f7c84a94b26f3922ac137 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 6 Dec 2021 21:43:06 -0500 Subject: [PATCH] update build --- .eslintrc.json | 1 + CHANGELOG.md | 2 +- README.md | 3 - demo/index.js | 2 +- demo/node-canvas.js | 2 +- demo/node-multiprocess-worker.js | 2 +- demo/node-wasm.js | 97 -------------------------------- demo/node.js | 2 +- demo/webcam.js | 2 +- package.json | 12 ++-- 10 files changed, 13 insertions(+), 112 deletions(-) delete mode 100644 demo/node-wasm.js diff --git a/.eslintrc.json b/.eslintrc.json index b6a55e5..98c719d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -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", diff --git a/CHANGELOG.md b/CHANGELOG.md index cf529e2..3fdb866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index b2e898c..fc6438c 100644 --- a/README.md +++ b/README.md @@ -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`) diff --git a/demo/index.js b/demo/index.js index b83f052..7311401 100644 --- a/demo/index.js +++ b/demo/index.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 diff --git a/demo/node-canvas.js b/demo/node-canvas.js index 8b191e1..073cea2 100644 --- a/demo/node-canvas.js +++ b/demo/node-canvas.js @@ -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); diff --git a/demo/node-multiprocess-worker.js b/demo/node-multiprocess-worker.js index 324724d..e84f071 100644 --- a/demo/node-multiprocess-worker.js +++ b/demo/node-multiprocess-worker.js @@ -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); diff --git a/demo/node-wasm.js b/demo/node-wasm.js deleted file mode 100644 index f62301e..0000000 --- a/demo/node-wasm.js +++ /dev/null @@ -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(); diff --git a/demo/node.js b/demo/node.js index 993312f..8a05b17 100644 --- a/demo/node.js +++ b/demo/node.js @@ -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); diff --git a/demo/webcam.js b/demo/webcam.js index b0ab210..ae00d54 100644 --- a/demo/webcam.js +++ b/demo/webcam.js @@ -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(); diff --git a/package.json b/package.json index edff4d7..1fa3ebb 100644 --- a/package.json +++ b/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"