add node-match demo
parent
1b4580dd6e
commit
c7b2c65c97
|
@ -0,0 +1,68 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const tf = require('@tensorflow/tfjs-node');
|
||||||
|
const log = require('@vladmandic/pilogger');
|
||||||
|
const faceapi = require('../dist/face-api.node.js');
|
||||||
|
|
||||||
|
let optionsSSDMobileNet;
|
||||||
|
const minConfidence = 0.1;
|
||||||
|
const distanceThreshold = 0.5;
|
||||||
|
const modelPath = 'model';
|
||||||
|
const labeledFaceDescriptors = [];
|
||||||
|
|
||||||
|
async function initFaceAPI() {
|
||||||
|
await faceapi.nets.ssdMobilenetv1.loadFromDisk(modelPath);
|
||||||
|
await faceapi.nets.faceLandmark68Net.loadFromDisk(modelPath);
|
||||||
|
await faceapi.nets.faceRecognitionNet.loadFromDisk(modelPath);
|
||||||
|
optionsSSDMobileNet = new faceapi.SsdMobilenetv1Options({ minConfidence, maxResults: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDescriptors(imageFile) {
|
||||||
|
const buffer = fs.readFileSync(imageFile);
|
||||||
|
const tensor = tf.node.decodeImage(buffer, 3);
|
||||||
|
const faces = await faceapi.detectAllFaces(tensor, optionsSSDMobileNet)
|
||||||
|
.withFaceLandmarks()
|
||||||
|
.withFaceDescriptors();
|
||||||
|
tf.dispose(tensor);
|
||||||
|
return faces.map((face) => face.descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerImage(inputFile) {
|
||||||
|
const descriptors = await getDescriptors(inputFile);
|
||||||
|
for (const descriptor of descriptors) {
|
||||||
|
const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(inputFile, [descriptor]);
|
||||||
|
labeledFaceDescriptors.push(labeledFaceDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findBestMatch(inputFile) {
|
||||||
|
const matcher = new faceapi.FaceMatcher(labeledFaceDescriptors, distanceThreshold);
|
||||||
|
const descriptors = await getDescriptors(inputFile);
|
||||||
|
const matches = [];
|
||||||
|
for (const descriptor of descriptors) {
|
||||||
|
const match = await matcher.findBestMatch(descriptor);
|
||||||
|
matches.push(match);
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
log.header();
|
||||||
|
if (process.argv.length !== 4) {
|
||||||
|
log.error(process.argv[1], 'Expected <source image or folder> <target image>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
await initFaceAPI();
|
||||||
|
log.info('Input:', process.argv[2]);
|
||||||
|
if (fs.statSync(process.argv[2]).isFile()) {
|
||||||
|
await registerImage(process.argv[2]);
|
||||||
|
} 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));
|
||||||
|
}
|
||||||
|
log.info('Descriptors:', labeledFaceDescriptors.length);
|
||||||
|
const bestMatch = await findBestMatch(process.argv[3]);
|
||||||
|
log.data('Match:', bestMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
|
@ -106,7 +106,7 @@ async function main() {
|
||||||
await faceapi.nets.faceExpressionNet.loadFromDisk(modelPath);
|
await faceapi.nets.faceExpressionNet.loadFromDisk(modelPath);
|
||||||
optionsSSDMobileNet = new faceapi.SsdMobilenetv1Options({ minConfidence, maxResults });
|
optionsSSDMobileNet = new faceapi.SsdMobilenetv1Options({ minConfidence, maxResults });
|
||||||
|
|
||||||
if (process.argv.length !== 3) {
|
if (process.argv.length !== 4) {
|
||||||
const t0 = process.hrtime.bigint();
|
const t0 = process.hrtime.bigint();
|
||||||
const dir = fs.readdirSync(imgPathRoot);
|
const dir = fs.readdirSync(imgPathRoot);
|
||||||
for (const img of dir) {
|
for (const img of dir) {
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -39,7 +39,7 @@ export class FaceMatcher {
|
||||||
|
|
||||||
public findBestMatch(queryDescriptor: Float32Array): FaceMatch {
|
public findBestMatch(queryDescriptor: Float32Array): FaceMatch {
|
||||||
const bestMatch = this.matchDescriptor(queryDescriptor);
|
const bestMatch = this.matchDescriptor(queryDescriptor);
|
||||||
return bestMatch.distance < this._distanceThreshold ? bestMatch : new FaceMatch('unknown', bestMatch.distance);
|
return (bestMatch.distance < this._distanceThreshold) ? bestMatch : new FaceMatch('unknown', bestMatch.distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON(): any {
|
public toJSON(): any {
|
||||||
|
|
Loading…
Reference in New Issue