diff --git a/lib/Service/FaceClusterAnalyzer.php b/lib/Service/FaceClusterAnalyzer.php index ee08cd84..919121f9 100644 --- a/lib/Service/FaceClusterAnalyzer.php +++ b/lib/Service/FaceClusterAnalyzer.php @@ -19,7 +19,7 @@ class FaceClusterAnalyzer { public const MIN_DETECTION_SIZE = 0.03; public const MIN_CLUSTER_SEPARATION = 0.35; public const MAX_CLUSTER_EDGE_LENGTH = 0.5; - public const DIMENSIONS = 128; + public const DIMENSIONS = 1024; public const MAX_OVERLAP_NEW_CLUSTER = 0.1; public const MIN_OVERLAP_EXISTING_CLUSTER = 0.5; @@ -186,7 +186,7 @@ public function calculateClusters(string $userId, int $batchSize = 0): void { * @return list */ public static function calculateCentroidOfDetections(array $detections): array { - // init 128 dimensional vector + // init 1024 dimensional vector /** @var list $sum */ $sum = []; for ($i = 0; $i < self::DIMENSIONS; $i++) { diff --git a/package-lock.json b/package-lock.json index 89097724..78b92423 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@tensorflow/tfjs-backend-wasm": "4.x", "@tensorflow/tfjs-node": "4.x", "@tensorflow/tfjs-node-gpu": "4.x", - "@vladmandic/face-api": "^1.7.11", + "@vladmandic/human": "^3.3.4", "download": "^8.0.0", "execa": "^5.1.1", "exifer": "^1.0.0-beta.2", @@ -4213,10 +4213,10 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, - "node_modules/@vladmandic/face-api": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@vladmandic/face-api/-/face-api-1.7.11.tgz", - "integrity": "sha512-jEQRN5/HDrdIEcg6pembiRvU7hk0hhkZfGfN2gxBDG95BmFZEWT/85qUrZDBJMtH51nCtcw20SI+4EGYZfqvIg==", + "node_modules/@vladmandic/human": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-3.3.4.tgz", + "integrity": "sha512-olq1HsFVj/cxMXYh6MDI3IWUibMmTtQ8dCGLuldVLcbGrgBZjWPpW6PMW6xQWw1ImwffrenN/U4Gi7LA4Sk3dA==", "engines": { "node": ">=14.0.0" } diff --git a/package.json b/package.json index a618417e..57eb931e 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@tensorflow/tfjs-backend-wasm": "4.x", "@tensorflow/tfjs-node": "4.x", "@tensorflow/tfjs-node-gpu": "4.x", - "@vladmandic/face-api": "^1.7.11", + "@vladmandic/human": "^3.3.4", "download": "^8.0.0", "execa": "^5.1.1", "exifer": "^1.0.0-beta.2", diff --git a/src/classifier_faces.js b/src/classifier_faces.js index c573ec5a..c09061d3 100644 --- a/src/classifier_faces.js +++ b/src/classifier_faces.js @@ -1,36 +1,60 @@ const path = require('path') const fs = require('fs/promises') -let tf, faceapi, Jimp +let tf, Human, Jimp, wasm let PUREJS = false if (process.env.RECOGNIZE_PUREJS === 'true') { tf = require('@tensorflow/tfjs') - require('@tensorflow/tfjs-backend-wasm') - faceapi = require('@vladmandic/face-api/dist/face-api.node-wasm.js') + wasm = require('@tensorflow/tfjs-backend-wasm') + Human = require('@vladmandic/human/dist/human.node-wasm.js') Jimp = require('jimp') PUREJS = true } else { try { if (process.env.RECOGNIZE_GPU === 'true') { tf = require('@tensorflow/tfjs-node-gpu') - faceapi = require('@vladmandic/face-api/dist/face-api.node-gpu.js') + Human = require('@vladmandic/human/dist/human.node-gpu.js') } else { tf = require('@tensorflow/tfjs-node') - faceapi = require('@vladmandic/face-api/dist/face-api.node.js') + Human = require('@vladmandic/human/dist/human.node.js') } } catch (e) { console.error(e) console.error('Trying js-only mode') tf = require('@tensorflow/tfjs') - require('@tensorflow/tfjs-backend-wasm') - faceapi = require('@vladmandic/face-api/dist/face-api.node-wasm.js') + wasm = require('@tensorflow/tfjs-backend-wasm') + Human = require('@vladmandic/human/dist/human.node-wasm.js') Jimp = require('jimp') PUREJS = true } } - if (process.argv.length < 3) throw new Error('Incorrect arguments: node classifier_faces.js ... | node classify.js -') +const config = { + cacheSensitivity: 0.01, + //modelBasePath: 'file://node_modules/@vladmandic/human/models/', + modelBasePath: 'https://vladmandic.github.io/human-models/models/', + backend: PUREJS ? 'wasm' : 'tensorflow', + //wasmPath: 'file://node_modules/@tensorflow/tfjs-backend-wasm/dist/', + wasmPath: `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`, + debug: false, + async: false, + softwareKernels: true, + face: { + enabled: true, + detector: { rotation: false, maxDetected: 100 }, + iris: { enabled: true }, + description: { enabled: true }, + antispoof: { enabled: true }, + liveness: { enabled: true }, + }, + hand: { enabled: false }, + body: { enabled: false }, + object: { enabled: false }, + segmentation: { enabled: false }, + filter: { enabled: false }, +} + /** * */ @@ -43,9 +67,8 @@ async function main() { paths = process.argv.slice(2) } - await faceapi.nets.ssdMobilenetv1.loadFromDisk(path.resolve(__dirname, '..', 'node_modules/@vladmandic/face-api/model')) - await faceapi.nets.faceLandmark68Net.loadFromDisk(path.resolve(__dirname, '..', 'node_modules/@vladmandic/face-api/model')) - await faceapi.nets.faceRecognitionNet.loadFromDisk(path.resolve(__dirname, '..', 'node_modules/@vladmandic/face-api/model')) + Human.env.updateBackend(); + const human = new Human.Human(config) for (const path of paths) { try { @@ -55,19 +78,18 @@ async function main() { } else { tensor = await tf.node.decodeImage(await fs.readFile(path), 3) } - const results = await faceapi.detectAllFaces(tensor).withFaceLandmarks().withFaceDescriptors() + const results = await human.detect(tensor) tensor.dispose() - const vectors = results + const vectors = results.face .map(result => ({ - angle: result.angle, - vector: result.descriptor, - x: result.detection.relativeBox.x, - y: result.detection.relativeBox.y, - height: result.detection.relativeBox.height, - width: result.detection.relativeBox.width, - score: result.detection.score, + angle: result.rotation.angle, + vector: result.embedding, + x: result.boxRaw[0], + y: result.boxRaw[1], + height: result.boxRaw[3], + width: result.boxRaw[2], + score: result.score, })) - console.log(JSON.stringify(vectors)) } catch (e) { console.error(e) @@ -76,6 +98,9 @@ async function main() { } } +if (PUREJS) { + wasm.setWasmPaths(config.wasmPath, true); +} tf.setBackend(PUREJS ? 'wasm' : 'tensorflow') .then(() => main()) .catch(e => {