|
import cv2 |
|
import numpy as np |
|
from ultralytics import YOLO |
|
from arcface import ArcFace |
|
import pickle |
|
import os |
|
from datetime import datetime |
|
|
|
class FaceRecognitionSystem: |
|
def __init__(self, database_path="face_database.pkl", confidence_threshold=0.5, similarity_threshold=2): |
|
|
|
self.yolo_model = YOLO('https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11s-face.pt') |
|
|
|
|
|
self.face_rec = ArcFace.ArcFace("model.tflite") |
|
|
|
|
|
self.confidence_threshold = confidence_threshold |
|
self.similarity_threshold = similarity_threshold |
|
|
|
|
|
self.database_path = database_path |
|
self.face_database = self.load_database() |
|
|
|
def load_database(self): |
|
if os.path.exists(self.database_path): |
|
with open(self.database_path, 'rb') as f: |
|
return pickle.load(f) |
|
return {} |
|
|
|
def save_database(self): |
|
with open(self.database_path, 'wb') as f: |
|
pickle.dump(self.face_database, f) |
|
|
|
def add_face_to_database(self, name, frame): |
|
"""Add a new face to the database""" |
|
try: |
|
embedding = self.face_rec.calc_emb(frame) |
|
self.face_database[name] = embedding |
|
self.save_database() |
|
return True |
|
except Exception as e: |
|
print(f"Error adding face to database: {e}") |
|
return False |
|
|
|
def find_closest_match(self, embedding): |
|
"""Find the closest matching face in the database""" |
|
if not self.face_database: |
|
return "Unknown", 1.0 |
|
|
|
min_distance = 10000 |
|
closest_name = "Unknown" |
|
|
|
for name, stored_embedding in self.face_database.items(): |
|
distance = self.face_rec.get_distance_embeddings(embedding, stored_embedding) |
|
if distance < min_distance: |
|
min_distance = distance |
|
closest_name = name |
|
|
|
return closest_name, min_distance |
|
|
|
def process_frame(self, frame): |
|
"""Process a single frame""" |
|
|
|
results = self.yolo_model(frame, verbose=False)[0] |
|
|
|
|
|
for detection in results.boxes.data: |
|
x1, y1, x2, y2, conf, _ = detection |
|
|
|
if conf < self.confidence_threshold: |
|
continue |
|
|
|
|
|
x1, y1, x2, y2 = map(int, [x1, y1, x2, y2]) |
|
|
|
|
|
face_region = frame[y1:y2, x1:x2] |
|
|
|
try: |
|
|
|
embedding = self.face_rec.calc_emb(face_region) |
|
|
|
|
|
name, distance = self.find_closest_match(embedding) |
|
|
|
|
|
if distance > self.similarity_threshold: |
|
name = "Unknown" |
|
|
|
|
|
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) |
|
cv2.putText(frame, f"{name} ({conf:.2f})", |
|
(x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, |
|
0.5, (0, 255, 0), 2) |
|
|
|
except Exception as e: |
|
print(f"Error processing face: {e}") |
|
|
|
return frame |
|
|
|
def run(self): |
|
"""Run the face recognition system on webcam feed""" |
|
cap = cv2.VideoCapture(0) |
|
|
|
while True: |
|
ret, frame = cap.read() |
|
if not ret: |
|
break |
|
|
|
|
|
processed_frame = self.process_frame(frame) |
|
|
|
|
|
cv2.imshow('Face Recognition', processed_frame) |
|
|
|
key = cv2.waitKey(1) |
|
if key == ord('q'): |
|
break |
|
elif key == ord('a'): |
|
|
|
name = input("Enter name for new face: ") |
|
if self.add_face_to_database(name, frame): |
|
print(f"Successfully added {name} to database") |
|
else: |
|
print("Failed to add face to database") |
|
|
|
cap.release() |
|
cv2.destroyAllWindows() |