node-image.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. /**
  2. * FaceAPI Demo for NodeJS
  3. * - Uses external library [@canvas/image](https://www.npmjs.com/package/@canvas/image) to decode image
  4. * - Loads image from provided param
  5. * - Outputs results to console
  6. */
  7. // @canvas/image can decode jpeg, png, webp
  8. // must be installed manually as it just a demo dependency and not actual face-api dependency
  9. const image = require('@canvas/image'); // eslint-disable-line node/no-missing-require
  10. const fs = require('fs');
  11. const log = require('@vladmandic/pilogger');
  12. const tf = require('@tensorflow/tfjs-node'); // in nodejs environments tfjs-node is required to be loaded before face-api
  13. const faceapi = require('../dist/face-api.node.js'); // use this when using face-api in dev mode
  14. // const faceapi = require('@vladmandic/face-api'); // use this when face-api is installed as module (majority of use cases)
  15. const modelPath = 'model/';
  16. const imageFile = 'demo/sample1.jpg';
  17. const ssdOptions = { minConfidence: 0.1, maxResults: 10 };
  18. async function main() {
  19. log.header();
  20. const buffer = fs.readFileSync(imageFile); // read image from disk
  21. const canvas = await image.imageFromBuffer(buffer); // decode to canvas
  22. const imageData = image.getImageData(canvas); // read decoded image data from canvas
  23. log.info('image:', imageFile, canvas.width, canvas.height);
  24. const tensor = tf.tidy(() => { // create tensor from image data
  25. 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
  26. const channels = tf.split(data, 4, 2); // split rgba to channels
  27. const rgb = tf.stack([channels[0], channels[1], channels[2]], 2); // stack channels back to rgb
  28. 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
  29. return reshape;
  30. });
  31. log.info('tensor:', tensor.shape, tensor.size);
  32. // load models
  33. await faceapi.nets.ssdMobilenetv1.loadFromDisk(modelPath);
  34. await faceapi.nets.ageGenderNet.loadFromDisk(modelPath);
  35. await faceapi.nets.faceLandmark68Net.loadFromDisk(modelPath);
  36. await faceapi.nets.faceRecognitionNet.loadFromDisk(modelPath);
  37. await faceapi.nets.faceExpressionNet.loadFromDisk(modelPath);
  38. const optionsSSDMobileNet = new faceapi.SsdMobilenetv1Options(ssdOptions); // create options object
  39. const result = await faceapi // run detection
  40. .detectAllFaces(tensor, optionsSSDMobileNet)
  41. .withFaceLandmarks()
  42. .withFaceExpressions()
  43. .withFaceDescriptors()
  44. .withAgeAndGender();
  45. log.data('results:', result.length);
  46. }
  47. main();