diff --git a/CHANGELOG.md b/CHANGELOG.md index 41b1b5d..4066eee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ## Changelog -### **HEAD -> master** 2022/08/16 mandic00@live.com +### **HEAD -> master** 2022/08/22 mandic00@live.com ### **release: 1.7.1** 2022/07/25 mandic00@live.com diff --git a/demo/index.js b/demo/index.js index 4c03ae8..3732dd3 100644 --- a/demo/index.js +++ b/demo/index.js @@ -1,8 +1,14 @@ -import * as faceapi from '../dist/face-api.esm.js'; +/** + * FaceAPI Demo for Browsers + * Loaded via `index.html` + */ + +import * as faceapi from '../dist/face-api.esm.js'; // use when in dev mode +// import * as faceapi from '@vladmandic/face-api'; // use when downloading face-api as npm // configuration options const modelPath = '../model/'; // path to model folder that will be loaded using http -// const modelPath = 'https://vladmandic.github.io/face-api/model/'; // path to model folder that will be loaded using http +// const modelPath = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api/model/'; // path to model folder that will be loaded using http const imgSize = 800; // maximum image size in pixels const minScore = 0.3; // minimum score const maxResults = 10; // maximum number of results to return @@ -13,8 +19,7 @@ const str = (json) => (json ? JSON.stringify(json).replace(/{|}|"|\[|\]/g, '').r // helper function to print strings to html document as a log function log(...txt) { - // eslint-disable-next-line no-console - console.log(...txt); + console.log(...txt); // eslint-disable-line no-console const div = document.getElementById('log'); if (div) div.innerHTML += `
${txt}`; } @@ -67,8 +72,7 @@ function faces(name, title, id, data) { // helper function to draw processed image and its results function print(title, img, data) { - // eslint-disable-next-line no-console - console.log('Results:', title, img, data); + console.log('Results:', title, img, data); // eslint-disable-line no-console const el = new Image(); el.id = Math.floor(Math.random() * 100000).toString(); el.src = img; @@ -174,8 +178,7 @@ async function main() { print('SSDMobileNet:', img, dataSSDMobileNet); } catch (err) { log(`Image: ${img} Error during processing ${str(err)}`); - // eslint-disable-next-line no-console - console.error(err); + console.error(err); // eslint-disable-line no-console } } } diff --git a/demo/node-canvas.js b/demo/node-canvas.js index a8604cd..6f49050 100644 --- a/demo/node-canvas.js +++ b/demo/node-canvas.js @@ -1,13 +1,20 @@ +/** + * FaceAPI Demo for NodeJS + * - Uses external library [canvas](https://www.npmjs.com/package/canvas) to decode image + * - Loads image from provided param + * - Outputs results to console + */ + +// canvas library provides full canvas (load/draw/write) functionality for nodejs +// must be installed manually as it just a demo dependency and not actual face-api dependency +const canvas = require('canvas'); // eslint-disable-line node/no-missing-require const fs = require('fs'); const path = require('path'); const process = require('process'); const log = require('@vladmandic/pilogger'); -const canvas = require('canvas'); - -// eslint-disable-next-line import/no-extraneous-dependencies, no-unused-vars, @typescript-eslint/no-unused-vars const tf = require('@tensorflow/tfjs-node'); // in nodejs environments tfjs-node is required to be loaded before face-api -// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const faceapi = require('../dist/face-api.node.js'); // use this when using face-api in dev mode +// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const modelPathRoot = '../model'; const imgPathRoot = './demo'; // modify to include your sample images @@ -50,11 +57,9 @@ async function main() { faceapi.env.monkeyPatch({ Canvas: canvas.Canvas, Image: canvas.Image, ImageData: canvas.ImageData }); await faceapi.tf.setBackend('tensorflow'); - 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} Backend: ${faceapi.tf?.getBackend()}`); + log.state(`Version: FaceAPI ${faceapi.version} TensorFlow/JS ${tf.version_core} Backend: ${faceapi.tf?.getBackend()}`); log.info('Loading FaceAPI models'); const modelPath = path.join(__dirname, modelPathRoot); diff --git a/demo/node-image.js b/demo/node-image.js index 7114a0e..6817a24 100644 --- a/demo/node-image.js +++ b/demo/node-image.js @@ -1,12 +1,18 @@ -const fs = require('fs'); -// eslint-disable-next-line import/no-extraneous-dependencies, node/no-unpublished-require -const image = require('@canvas/image'); // @canvas/image can decode jpeg, png, webp -const log = require('@vladmandic/pilogger'); +/** + * FaceAPI Demo for NodeJS + * - Uses external library [@canvas/image](https://www.npmjs.com/package/@canvas/image) to decode image + * - Loads image from provided param + * - Outputs results to console + */ -// eslint-disable-next-line import/no-extraneous-dependencies, no-unused-vars, @typescript-eslint/no-unused-vars +// @canvas/image can decode jpeg, png, webp +// must be installed manually as it just a demo dependency and not actual face-api dependency +const image = require('@canvas/image'); // eslint-disable-line node/no-missing-require +const fs = require('fs'); +const log = require('@vladmandic/pilogger'); const tf = require('@tensorflow/tfjs-node'); // in nodejs environments tfjs-node is required to be loaded before face-api -// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const faceapi = require('../dist/face-api.node.js'); // use this when using face-api in dev mode +// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const modelPath = 'model/'; const imageFile = 'demo/sample1.jpg'; diff --git a/demo/node-match.js b/demo/node-match.js index 6629df1..8f5df87 100644 --- a/demo/node-match.js +++ b/demo/node-match.js @@ -1,11 +1,16 @@ +/** + * FaceAPI Demo for NodeJS + * - Analyzes face descriptors from source (image file or folder containing multiple image files) + * - Analyzes face descriptor from target + * - Finds best match + */ + const fs = require('fs'); const path = require('path'); const log = require('@vladmandic/pilogger'); - -// eslint-disable-next-line import/no-extraneous-dependencies, no-unused-vars, @typescript-eslint/no-unused-vars const tf = require('@tensorflow/tfjs-node'); // in nodejs environments tfjs-node is required to be loaded before face-api -// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const faceapi = require('../dist/face-api.node.js'); // use this when using face-api in dev mode +// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) let optionsSSDMobileNet; const minConfidence = 0.1; @@ -33,6 +38,8 @@ async function getDescriptors(imageFile) { } async function registerImage(inputFile) { + if (!inputFile.toLowerCase().endsWith('jpg') && !inputFile.toLowerCase().endsWith('png') && !inputFile.toLowerCase().endsWith('gif')) return; + log.data('Registered:', inputFile); const descriptors = await getDescriptors(inputFile); for (const descriptor of descriptors) { const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(inputFile, [descriptor]); @@ -60,14 +67,18 @@ async function main() { await initFaceAPI(); log.info('Input:', process.argv[2]); if (fs.statSync(process.argv[2]).isFile()) { - await registerImage(process.argv[2]); + await registerImage(process.argv[2]); // register image } else if (fs.statSync(process.argv[2]).isDirectory()) { const dir = fs.readdirSync(process.argv[2]); - for (const f of dir) await registerImage(path.join(process.argv[2], f)); + for (const f of dir) await registerImage(path.join(process.argv[2], f)); // register all images in a folder + } + log.info('Comparing:', process.argv[3], 'Descriptors:', labeledFaceDescriptors.length); + if (labeledFaceDescriptors.length > 0) { + const bestMatch = await findBestMatch(process.argv[3]); // find best match to all registered images + log.data('Match:', bestMatch); + } else { + log.warn('No registered faces'); } - log.info('Descriptors:', labeledFaceDescriptors.length); - const bestMatch = await findBestMatch(process.argv[3]); - log.data('Match:', bestMatch); } main(); diff --git a/demo/node-multiprocess-worker.js b/demo/node-multiprocess-worker.js index 0837686..e72532d 100644 --- a/demo/node-multiprocess-worker.js +++ b/demo/node-multiprocess-worker.js @@ -1,14 +1,16 @@ -// @ts-nocheck +/** + * FaceAPI Demo for NodeJS + * - Used by `node-multiprocess.js` + */ const fs = require('fs'); const path = require('path'); const log = require('@vladmandic/pilogger'); // workers actual import tfjs and faceapi modules -// eslint-disable-next-line import/no-extraneous-dependencies, no-unused-vars, @typescript-eslint/no-unused-vars const tf = require('@tensorflow/tfjs-node'); // in nodejs environments tfjs-node is required to be loaded before face-api -// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const faceapi = require('../dist/face-api.node.js'); // use this when using face-api in dev mode +// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) // options used by faceapi const modelPathRoot = '../model'; diff --git a/demo/node-multiprocess.js b/demo/node-multiprocess.js index a8e2924..6e45cfe 100644 --- a/demo/node-multiprocess.js +++ b/demo/node-multiprocess.js @@ -1,3 +1,9 @@ +/** + * FaceAPI Demo for NodeJS + * - Starts multiple worker processes and uses them as worker pool to process all input images + * - Images are enumerated in main process and sent for processing to worker processes via ipc + */ + const fs = require('fs'); const path = require('path'); const log = require('@vladmandic/pilogger'); // this is my simple logger with few extra features diff --git a/demo/node-simple.js b/demo/node-simple.js index b9591d2..3d66237 100644 --- a/demo/node-simple.js +++ b/demo/node-simple.js @@ -1,7 +1,13 @@ +/** + * FaceAPI Demo for NodeJS + * - Loads image + * - Outputs results to console + */ + const fs = require('fs'); -// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const faceapi = require('../dist/face-api.node.js'); // use this when using face-api in dev mode +// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) async function main() { await faceapi.nets.ssdMobilenetv1.loadFromDisk('model'); // load models from a specific patch @@ -19,8 +25,7 @@ async function main() { .withFaceDescriptors() .withAgeAndGender(); faceapi.tf.dispose([decodeT, expandT]); // dispose tensors to avoid memory leaks - // eslint-disable-next-line no-console - console.log({ result }); // print results + console.log({ result }); // eslint-disable-line no-console } main(); diff --git a/demo/node.js b/demo/node.js index 099f86b..ff85248 100644 --- a/demo/node.js +++ b/demo/node.js @@ -1,12 +1,18 @@ +/** + * FaceAPI Demo for NodeJS + * - Uses external library [node-fetch](https://www.npmjs.com/package/node-fetch) to load images via http + * - Loads image from provided param + * - Outputs results to console + */ + const fs = require('fs'); const process = require('process'); const path = require('path'); const log = require('@vladmandic/pilogger'); -// eslint-disable-next-line import/no-extraneous-dependencies, no-unused-vars, @typescript-eslint/no-unused-vars const tf = require('@tensorflow/tfjs-node'); // in nodejs environments tfjs-node is required to be loaded before face-api -// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const faceapi = require('../dist/face-api.node.js'); // use this when using face-api in dev mode +// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases) const modelPathRoot = '../model'; const imgPathRoot = './demo'; // modify to include your sample images @@ -87,11 +93,9 @@ async function main() { log.header(); log.info('FaceAPI single-process test'); - fetch = (await import('node-fetch')).default; + fetch = (await import('node-fetch')).default; // eslint-disable-line node/no-missing-import await faceapi.tf.setBackend('tensorflow'); - 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} Backend: ${faceapi.tf?.getBackend()}`); diff --git a/demo/webcam.js b/demo/webcam.js index 9c8aa27..f2dad27 100644 --- a/demo/webcam.js +++ b/demo/webcam.js @@ -1,8 +1,14 @@ -import * as faceapi from '../dist/face-api.esm.js'; +/** + * FaceAPI Demo for Browsers + * Loaded via `webcam.html` + */ + +import * as faceapi from '../dist/face-api.esm.js'; // use when in dev mode +// import * as faceapi from '@vladmandic/face-api'; // use when downloading face-api as npm // configuration options const modelPath = '../model/'; // path to model folder that will be loaded using http -// const modelPath = 'https://vladmandic.github.io/face-api/model/'; // path to model folder that will be loaded using http +// const modelPath = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api/model/'; // path to model folder that will be loaded using http const minScore = 0.2; // minimum score const maxResults = 5; // maximum number of results to return let optionsSSDMobileNet; @@ -17,8 +23,7 @@ function str(json) { // helper function to print strings to html document as a log function log(...txt) { - // eslint-disable-next-line no-console - console.log(...txt); + console.log(...txt); // eslint-disable-line no-console const div = document.getElementById('log'); if (div) div.innerHTML += `
${txt}`; } diff --git a/package.json b/package.json index 0b63a02..03ecd2d 100644 --- a/package.json +++ b/package.json @@ -41,11 +41,6 @@ "tensorflowjs", "tfjs" ], - "optionalDependencies": { - "@canvas/image": "^1.0.1", - "canvas": "^2.9.3", - "node-fetch": "^3.2.10" - }, "devDependencies": { "@microsoft/api-extractor": "^7.29.3", "@tensorflow/tfjs": "^3.19.0", @@ -59,10 +54,10 @@ "@tensorflow/tfjs-layers": "^3.19.0", "@tensorflow/tfjs-node": "^3.19.0", "@tensorflow/tfjs-node-gpu": "^3.19.0", - "@types/node": "^18.7.9", + "@types/node": "^18.7.11", "@types/offscreencanvas": "^2019.7.0", - "@typescript-eslint/eslint-plugin": "^5.33.1", - "@typescript-eslint/parser": "^5.33.1", + "@typescript-eslint/eslint-plugin": "^5.34.0", + "@typescript-eslint/parser": "^5.34.0", "@vladmandic/build": "^0.7.10", "@vladmandic/pilogger": "^0.4.6", "@vladmandic/tfjs": "github:vladmandic/tfjs", diff --git a/src/tfjs/tf-node-cpu.ts b/src/tfjs/tf-node-cpu.ts index 3e4088d..4675a7c 100644 --- a/src/tfjs/tf-node-cpu.ts +++ b/src/tfjs/tf-node-cpu.ts @@ -1,4 +1 @@ -/* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable node/no-unpublished-import */ - export * from '@tensorflow/tfjs'; diff --git a/src/tfjs/tf-node-gpu.ts b/src/tfjs/tf-node-gpu.ts index 407d486..68781c3 100644 --- a/src/tfjs/tf-node-gpu.ts +++ b/src/tfjs/tf-node-gpu.ts @@ -1,4 +1 @@ -/* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable node/no-unpublished-import */ - export * from '@tensorflow/tfjs-node-gpu'; diff --git a/src/tfjs/tf-node-wasm.ts b/src/tfjs/tf-node-wasm.ts index 5be902b..79e5f49 100644 --- a/src/tfjs/tf-node-wasm.ts +++ b/src/tfjs/tf-node-wasm.ts @@ -1,5 +1,2 @@ -/* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable node/no-unpublished-import */ - export * from '@tensorflow/tfjs'; export * from '@tensorflow/tfjs-backend-wasm'; diff --git a/src/tfjs/tf-node.ts b/src/tfjs/tf-node.ts index 1df0c5d..c752d1b 100644 --- a/src/tfjs/tf-node.ts +++ b/src/tfjs/tf-node.ts @@ -1,4 +1 @@ -/* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable node/no-unpublished-import */ - export * from '@tensorflow/tfjs-node'; diff --git a/test/test-node.js b/test/test-node.js index 62b3643..10bf569 100644 --- a/test/test-node.js +++ b/test/test-node.js @@ -1,8 +1,6 @@ const fs = require('fs'); 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 const tf = require('@tensorflow/tfjs-node'); const faceapi = require('../dist/face-api.node.js'); // this is equivalent to '@vladmandic/faceapi'