我正在开展一个大学项目,其中涉及与电子门集成的面部识别系统。我为人员创建了注册,现在我需要将接收到的面孔与存储的面孔进行比较。为此,我创建了两个包含相同照片的文件夹和两种检测方法:一种将图像 URL 存储在我的 Amazon S3 存储桶中,另一种从 to_compare 文件夹中获取图像。然而,即使图像相同,系统也不会将它们识别为同一个人。一种可能性是图像具有不同大小的数组,但我已经将数组过滤为只有 100 个元素。
const mongoose = require('mongoose');
const personSchema = new mongoose.Schema({
name: { type: String, required: true },
cpf: { type: String, required: true, unique: true },
birthDate: { type: Date, required: true },
photoUrl: { type: String },
biometrics: { type: Object }, // Dados biométricos processados da imagem
employee: { type: Boolean, required: true, default: false },
position: {
type: {
title: { type: String, required: true },
department: { type: String, required: true },
hireDate: { type: Date, required: true }
},
default: null,
validate: {
validator: function () {
return this.employee || this.position === null;
},
message: 'Position should be null if employee is false'
}
},
active: { type: Boolean, default: true } // Campo indicando se a pessoa está ativa
});
// Método para ativar a pessoa
personSchema.methods.activate = function () {
this.active = true;
return this.save();
};
// Método para desativar a pessoa
personSchema.methods.deactivate = function () {
this.active = false;
return this.save();
};
module.exports = mongoose.model('Person', personSchema);
// src/controller/personController.js
const Person = require('../model/personModel');
const { processBiometrics, compareBiometrics, compareWithRegisteredImages } = require('../util/biometricsUtils');
/**
* Creates a new person in the system with processed biometric data.
* @param {Object} req - Request object containing person data in the body.
* @param {Object} res - Response object.
*/
exports.createPerson = async (req, res) => {
try {
console.log("Creating person with data:", req.body);
const { name, cpf, birthDate, photoUrl, employee, position } = req.body;
// Processes biometrics if an image is provided
const biometrics = photoUrl ? await processBiometrics(photoUrl) : null;
console.log("Biometrics processed:", biometrics);
// Creates a new person
const person = new Person({
name,
cpf,
birthDate,
photoUrl,
biometrics,
employee,
position: employee ? position : null,
});
await person.save();
console.log("Person created successfully:", person);
res.status(201).json({ message: 'Person created successfully', person });
} catch (error) {
console.error("Error creating person:", error);
res.status(500).json({ error: 'Error creating person' });
}
};
/**
* Retrieves a person by ID.
* @param {Object} req - Request object containing the person's ID in the parameters.
* @param {Object} res - Response object.
*/
exports.getPersonById = async (req, res) => {
try {
console.log("Fetching person by ID:", req.params.id);
const person = await Person.findById(req.params.id);
if (!person) {
console.warn("Person not found with ID:", req.params.id);
return res.status(404).json({ error: 'Person not found' });
}
console.log("Person fetched:", person);
res.status(200).json(person);
} catch (error) {
console.error("Error fetching person:", error);
res.status(500).json({ error: 'Error fetching person' });
}
};
/**
* Updates a person's data by ID and reactivates them.
* @param {Object} req - Request object with the person's ID in the parameters and new data in the body.
* @param {Object} res - Response object.
*/
exports.updatePerson = async (req, res) => {
try {
console.log("Updating person with ID:", req.params.id);
const { name, cpf, birthDate, photoUrl, employee, position } = req.body;
const person = await Person.findById(req.params.id);
if (!person) {
console.warn("Person not found with ID:", req.params.id);
return res.status(404).json({ error: 'Person not found' });
}
person.name = name || person.name;
person.cpf = cpf || person.cpf;
person.birthDate = birthDate || person.birthDate;
person.photoUrl = photoUrl || person.photoUrl;
person.employee = employee !== undefined ? employee : person.employee;
person.position = employee ? position : null;
// Updates biometrics if a new photo is provided
if (photoUrl) {
console.log("Processing new biometrics for update...");
person.biometrics = await processBiometrics(photoUrl);
}
// Reactivates the person on update
await person.activate();
console.log("Person updated and activated successfully:", person);
res.status(200).json({ message: 'Person updated and activated successfully', person });
} catch (error) {
console.error("Error updating person:", error);
res.status(500).json({ error: 'Error updating person' });
}
};
/**
* Deactivates a person by ID, instead of deleting them from the database.
* @param {Object} req - Request object with the person's ID in the parameters.
* @param {Object} res - Response object.
*/
exports.deletePerson = async (req, res) => {
try {
console.log("Deactivating person with ID:", req.params.id);
const person = await Person.findById(req.params.id);
if (!person) {
console.warn("Person not found with ID:", req.params.id);
return res.status(404).json({ error: 'Person not found' });
}
await person.deactivate();
console.log("Person deactivated successfully:", person);
res.status(200).json({ message: 'Person deactivated successfully' });
} catch (error) {
console.error("Error deactivating person:", error);
res.status(500).json({ error: 'Error deactivating person' });
}
};
/**
* Lists all persons registered in the system.
* @param {Object} req - Request object.
* @param {Object} res - Response object.
*/
exports.getAllPersons = async (req, res) => {
try {
console.log("Fetching all persons...");
const persons = await Person.find();
console.log("Persons fetched:", persons);
res.status(200).json(persons);
} catch (error) {
console.error("Error fetching persons:", error);
res.status(500).json({ error: 'Error fetching persons' });
}
};
/**
* Verifies an image provided by URL and compares it with the biometrics of active persons.
* @param {Object} req - Request object containing the image URL in the body.
* @param {Object} res - Response object.
*/
exports.verifyPerson = async (req, res) => {
try {
console.log("Verifying person with photoUrl:", req.body.photoUrl);
const { photoUrl } = req.body;
// Processes the image to obtain biometric data
const biometrics = await processBiometrics(photoUrl);
if (!biometrics) {
console.warn("No biometric data found in provided image.");
return res.status(404).json({ match: false });
}
console.log("Processed biometrics for verification:", biometrics);
// Compares biometrics with registered persons
const persons = await Person.find({ active: true });
console.log("Comparing biometrics with active persons...");
for (let person of persons) {
if (person.biometrics && compareBiometrics(biometrics, person.biometrics)) {
console.log("Match found:", person);
return res.status(299).json({ match: true, person });
}
}
console.log("No match found.");
res.status(404).json({ match: false });
} catch (error) {
console.error("Error verifying person:", error);
res.status(500).json({ error: 'Error verifying person' });
}
};
/**
* Verifies a test image from the 'to_compare' folder by comparing it with registered images.
* Receives the image name and compares it with stored biometrics in the 'registered' folder.
* @param {Object} req - Request object containing the image name in the body.
* @param {Object} res - Response object.
*/
exports.verifyPersonWithImage = async (req, res) => {
try {
const { imageName } = req.body;
console.log("Verifying person with image:", imageName);
// Calls the comparison function with registered images
const result = await compareWithRegisteredImages(imageName);
// Responds with comparison results
if (result.match) {
res.status(299).json({ match: true, fileName: result.fileName });
} else {
res.status(404).json({ match: false });
}
} catch (error) {
console.error("Error verifying person:", error);
res.status(500).json({ error: 'Error verifying person' });
}
};
// src/util/biometricsUtils.js
const faceapi = require('face-api.js'); // Library for facial recognition
const tf = require('@tensorflow/tfjs-node'); // TensorFlow for data processing
const { Canvas, Image, ImageData } = require('canvas'); // Canvas for image manipulation
const canvas = require('canvas');
const path = require('path');
const fs = require('fs');
// Configures face-api.js to use canvas and manipulate images
faceapi.env.monkeyPatch({ Canvas, Image, ImageData });
/**
* Loads the necessary facial recognition models for detection,
* facial landmarks extraction, and facial descriptor.
*/
const loadModels = async () => {
const modelPath = './models'; // Path where models are stored
await faceapi.nets.ssdMobilenetv1.loadFromDisk(modelPath);
await faceapi.nets.faceLandmark68Net.loadFromDisk(modelPath);
await faceapi.nets.faceRecognitionNet.loadFromDisk(modelPath);
};
/**
* Processes a local image to extract biometric data with the first 100 elements.
* @param {string} imagePath - Path to the local image to be processed.
* @returns {Float32Array | null} Extracted biometric data (100 elements) or null if no face is detected.
*/
const processBiometrics = async (imagePath) => {
try {
console.log("Processing biometrics for image:", imagePath);
// Loads models if not already loaded
await loadModels();
// Loads the image from the specified path
const img = await canvas.loadImage(imagePath);
const detections = await faceapi.detectSingleFace(img)
.withFaceLandmarks()
.withFaceDescriptor();
if (!detections) {
console.warn("No face detected in image.");
return null;
}
// Returns only the first 100 elements of the facial descriptor
const biometrics = detections.descriptor.slice(0, 100);
if (biometrics && biometrics.length === 100) {
console.log("Biometric data loaded successfully with 100 elements.");
} else {
console.warn("Biometric data not loaded correctly or has an incorrect length.");
}
return biometrics;
} catch (error) {
console.error("Error processing biometrics:", error);
return null;
}
};
/**
* Compares two sets of biometric data to check for a match.
* @param {Float32Array} biometrics1 - First set of biometric data (100 points).
* @param {Float32Array} biometrics2 - Second set of biometric data (100 points).
* @returns {boolean} Returns true if data matches, false otherwise.
*/
const compareBiometrics = (biometrics1, biometrics2) => {
if (!biometrics1 || !biometrics2) {
console.warn("One of the biometric arrays is null.");
return false;
}
if (biometrics1.length !== 100 || biometrics2.length !== 100) {
console.warn("Biometric data length mismatch. Expected 100 elements.");
return false;
}
try {
// Calculates the Euclidean distance between the descriptors
const distance = faceapi.euclideanDistance(biometrics1, biometrics2);
const threshold = 0.7; // Adjusted threshold for more flexible matching
return distance < threshold;
} catch (error) {
console.error("Error comparing biometrics:", error);
return false;
}
};
/**
* Compares two sets of biometric data multiple times to check for match consistency.
* @param {Float32Array} biometrics1 - First set of biometric data.
* @param {Float32Array} biometrics2 - Second set of biometric data.
* @param {number} attempts - Number of verification attempts.
* @returns {boolean} Returns true if there is a match in all attempts, false otherwise.
*/
const verifyBiometricsMultipleAttempts = (biometrics1, biometrics2, attempts = 3) => {
let matches = 0;
for (let i = 0; i < attempts; i++) {
if (compareBiometrics(biometrics1, biometrics2)) {
matches++;
}
}
return matches >= attempts;
};
/**
* Loads and processes all images in the 'registered' folder for storing biometric data.
* @returns {Object} An object containing biometric data for each registered image.
*/
const loadRegisteredBiometrics = async () => {
const registeredPath = path.join(__dirname, '../../images/registered');
const registeredBiometrics = {};
const files = fs.readdirSync(registeredPath);
for (const file of files) {
const imagePath = path.join(registeredPath, file);
const biometricData = await processBiometrics(imagePath);
if (biometricData) {
registeredBiometrics[file] = biometricData;
}
}
return registeredBiometrics;
};
/**
* Compares an image from the 'to_compare' folder with all registered images in the 'registered' folder.
* Checks each comparison multiple times to ensure the match.
* @param {string} compareImageName - Name of the image to be compared.
* @returns {Object} An object indicating if there was a match and the name of the corresponding image.
*/
const compareWithRegisteredImages = async (compareImageName) => {
const registeredBiometrics = await loadRegisteredBiometrics();
const compareImagePath = path.join(__dirname, '../../images/to_compare', compareImageName);
const compareBiometricsData = await processBiometrics(compareImagePath);
if (!compareBiometricsData) {
console.warn("No biometric data found in comparison image.");
return { match: false };
}
for (const [fileName, registeredBiometricsData] of Object.entries(registeredBiometrics)) {
// Checks for a match with at least 3 attempts
if (verifyBiometricsMultipleAttempts(compareBiometricsData, registeredBiometricsData, 3)) {
console.log(`Match found with registered image: ${fileName}`);
return { match: true, fileName };
}
}
console.log("No match found.");
return { match: false };
};
module.exports = {
processBiometrics,
compareBiometrics,
loadRegisteredBiometrics,
compareWithRegisteredImages
};
// src/route/personRoutes.js
const express = require('express');
const personController = require('../controller/personController');
const router = express.Router();
/**
* Route to create a new person.
* Method: POST
* Endpoint: /persons
* Request Body: JSON with person data (name, cpf, birthDate, photoUrl, etc.)
*/
router.post('/', personController.createPerson);
/**
* Route to retrieve a person by ID.
* Method: GET
* Endpoint: /persons/:id
* Parameter: Person's ID in the URL.
*/
router.get('/:id', personController.getPersonById);
/**
* Route to update a person's data by ID.
* Method: PUT
* Endpoint: /persons/:id
* Parameter: Person's ID in the URL.
* Request Body: JSON with the data to be updated.
*/
router.put('/:id', personController.updatePerson);
/**
* Route to deactivate a person by ID.
* Method: DELETE
* Endpoint: /persons/:id
* Parameter: Person's ID in the URL.
*/
router.delete('/:id', personController.deletePerson);
/**
* Route to list all registered persons.
* Method: GET
* Endpoint: /persons
*/
router.get('/', personController.getAllPersons);
/**
* Route to verify a person's biometrics using an image URL.
* Method: POST
* Endpoint: /persons/verify
* Request Body: JSON with the image URL (photoUrl).
*/
router.post('/verify', personController.verifyPerson);
/**
* Route to verify a person's biometrics using a local image from the 'to_compare' folder.
* Method: POST
* Endpoint: /persons/verify-image
* Request Body: JSON with the name of the image to be compared (imageName).
*/
router.post('/verify-image', personController.verifyPersonWithImage);
module.exports = router;
我尝试使用 ChatGPT 进行检查,但我一直在绕圈子。
我使用 ChatGPT 在代码中添加注释以便更好地理解,我想知道我可能在哪里出错。如果有人可以提供帮助,我将非常感激。
我有“同样”的问题。 我上传了我的照片,但是不同的日子并没有认出我。
该软件给我的脸提供了另一个哈希值。
有关于face-api-js的discord服务器吗???