2021-04-15 22:59:35 +02:00
const fs = require ( 'fs' ) ;
2021-05-18 14:11:17 +02:00
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-unpublished-require
2021-04-15 22:59:35 +02:00
const image = require ( '@canvas/image' ) ; // @canvas/image can decode jpeg, png, webp
2021-05-18 14:11:17 +02:00
const log = require ( '@vladmandic/pilogger' ) ;
2022-01-01 13:52:40 +01:00
// 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
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 ( ) ;