2022-08-23 14:21:20 +02:00
/ * *
* 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
* /
// @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
2021-04-15 22:59:35 +02:00
const fs = require ( 'fs' ) ;
2021-05-18 14:11:17 +02:00
const log = require ( '@vladmandic/pilogger' ) ;
2022-01-01 13:52:40 +01:00
const tf = require ( '@tensorflow/tfjs-node' ) ; // in nodejs environments tfjs-node is required to be loaded before face-api
const faceapi = require ( '../dist/face-api.node.js' ) ; // use this when using face-api in dev mode
2022-08-23 14:21:20 +02:00
// const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases)
2021-04-15 22:59:35 +02:00
const modelPath = 'model/' ;
const imageFile = 'demo/sample1.jpg' ;
const ssdOptions = { minConfidence : 0.1 , maxResults : 10 } ;
async function main ( ) {
2021-05-18 14:11:17 +02:00
log . header ( ) ;
2021-04-15 22:59:35 +02:00
const buffer = fs . readFileSync ( imageFile ) ; // read image from disk
const canvas = await image . imageFromBuffer ( buffer ) ; // decode to canvas
const imageData = image . getImageData ( canvas ) ; // read decoded image data from canvas
2021-05-18 14:11:17 +02:00
log . info ( 'image:' , imageFile , canvas . width , canvas . height ) ;
2021-04-15 22:59:35 +02:00
const tensor = tf . tidy ( ( ) => { // create tensor from image data
2021-05-18 14:11:17 +02:00
const data = tf . tensor ( Array . from ( imageData ? . data || [ ] ) , [ canvas . height , canvas . width , 4 ] , 'int32' ) ; // create rgba image tensor from flat array and flip to height x width
2021-04-15 22:59:35 +02:00
const channels = tf . split ( data , 4 , 2 ) ; // split rgba to channels
const rgb = tf . stack ( [ channels [ 0 ] , channels [ 1 ] , channels [ 2 ] ] , 2 ) ; // stack channels back to rgb
const reshape = tf . reshape ( rgb , [ 1 , canvas . height , canvas . width , 3 ] ) ; // move extra dim from the end of tensor and use it as batch number instead
return reshape ;
} ) ;
2021-05-18 14:11:17 +02:00
log . info ( 'tensor:' , tensor . shape , tensor . size ) ;
// load models
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 ) ;
2021-04-15 22:59:35 +02:00
const optionsSSDMobileNet = new faceapi . SsdMobilenetv1Options ( ssdOptions ) ; // create options object
2021-05-18 14:11:17 +02:00
const result = await faceapi // run detection
. detectAllFaces ( tensor , optionsSSDMobileNet )
. withFaceLandmarks ( )
. withFaceExpressions ( )
. withFaceDescriptors ( )
. withAgeAndGender ( ) ;
2021-09-08 19:51:28 +02:00
log . data ( 'results:' , result . length ) ;
2021-04-15 22:59:35 +02:00
}
main ( ) ;