# 2: | |
import cv2 | |
import numpy as np | |
import insightface | |
from insightface.app import FaceAnalysis | |
from insightface.utils import download_onnx | |
from pathlib import Path | |
from typing import Dict, List, Tuple | |
import pickle | |
import logging | |
import os | |
class FaceRecognitionSystem: | |
def __init__(self, | |
model_name: str = "buffalo_l", | |
model_root: str = "./models"): | |
# Set up logging | |
logging.basicConfig(level=logging.INFO) | |
self.logger = logging.getLogger(__name__) | |
# Create model directory if it doesn't exist | |
self.model_root = Path(model_root) | |
self.model_root.mkdir(parents=True, exist_ok=True) | |
# Set InsightFace model root | |
# insightface.utils.set_download_root(str(self.model_root)) | |
# insightface.utils.download(root='./models_x', sub_dir='downloads', name='file') | |
# Initialize the face analysis model | |
try: | |
self.face_analyzer = FaceAnalysis( | |
name=model_name, | |
root=str(self.model_root), | |
download=True # Allow downloading if model doesn't exist | |
) | |
self.face_analyzer.prepare(ctx_id=-1, det_size=(640, 640)) # Using CPU | |
self.logger.info(f"Face analyzer initialized successfully in {self.model_root}") | |
except Exception as e: | |
self.logger.error(f"Error initializing face analyzer: {e}") | |
raise | |
# Dictionary to store known face embeddings | |
self.known_face_embeddings: Dict[str, np.ndarray] = {} | |
def process_known_faces(self, people_folder_path: str) -> None: | |
"""Process and store embeddings of known faces from a folder.""" | |
embeddings_file = self.model_root / "known_faces_embeddings.pkl" | |
try: | |
# Load existing embeddings if available | |
if embeddings_file.exists(): | |
with open(embeddings_file, 'rb') as f: | |
self.known_face_embeddings = pickle.load(f) | |
self.logger.info("Loaded existing face embeddings") | |
return | |
self.logger.info("Processing known faces...") | |
people_path = Path(people_folder_path) | |
if not people_path.exists(): | |
self.logger.warning(f"Directory not found: {people_folder_path}") | |
return | |
for person_path in people_path.glob("*"): | |
if person_path.is_dir(): | |
person_name = person_path.name | |
embeddings_list = [] | |
for img_path in person_path.glob("*"): | |
if img_path.suffix.lower() in ['.jpg', '.jpeg', '.png']: | |
img = cv2.imread(str(img_path)) | |
if img is None: | |
self.logger.warning(f"Could not read image: {img_path}") | |
continue | |
faces = self.face_analyzer.get(img) | |
if faces: | |
embeddings_list.append(faces[0].embedding) | |
else: | |
self.logger.warning(f"No face detected in {img_path}") | |
if embeddings_list: | |
self.known_face_embeddings[person_name] = np.mean(embeddings_list, axis=0) | |
self.logger.info(f"Processed {person_name}'s faces") | |
else: | |
self.logger.warning(f"No valid faces found for {person_name}") | |
# Save embeddings in model directory | |
with open(embeddings_file, 'wb') as f: | |
pickle.dump(self.known_face_embeddings, f) | |
self.logger.info(f"Face embeddings saved to {embeddings_file}") | |
except Exception as e: | |
self.logger.error(f"Error processing known faces: {e}") | |
raise | |
def identify_face(self, face_embedding: np.ndarray, threshold: float = 0.6) -> Tuple[str, float]: | |
"""Identify a face by comparing its embedding with known faces.""" | |
try: | |
best_match = "Unknown" | |
best_score = float('inf') | |
for person_name, known_embedding in self.known_face_embeddings.items(): | |
similarity = np.dot(face_embedding, known_embedding) / ( | |
np.linalg.norm(face_embedding) * np.linalg.norm(known_embedding) | |
) | |
distance = 1 - similarity | |
if distance < best_score: | |
best_score = distance | |
best_match = person_name | |
return (best_match, best_score) if best_score < threshold else ("Unknown", best_score) | |
except Exception as e: | |
self.logger.error(f"Error in face identification: {e}") | |
return ("Error", 1.0) | |
def detect_and_identify(self, image_input) -> np.ndarray: | |
"""Detect and identify faces in an input image.""" | |
try: | |
# Handle both string paths and numpy arrays | |
if isinstance(image_input, str): | |
img = cv2.imread(image_input) | |
else: | |
img = image_input | |
if img is None: | |
raise ValueError("Could not read input image") | |
faces = self.face_analyzer.get(img) | |
for face in faces: | |
bbox = face.bbox.astype(int) | |
embedding = face.embedding | |
name, score = self.identify_face(embedding) | |
cv2.rectangle(img, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2) | |
label = f"{name} ({1-score:.2f})" | |
cv2.putText(img, label.upper(), (bbox[0], bbox[1]-10), | |
cv2.FONT_HERSHEY_PLAIN, 2.0, (0, 255, 0), 2) | |
return img | |
except Exception as e: | |
self.logger.error(f"Error in detection and identification: {e}") | |
raise | |
# 1: | |
# import cv2 | |
# import numpy as np | |
# import insightface | |
# from insightface.app import FaceAnalysis | |
# from pathlib import Path | |
# from typing import Dict, List, Tuple | |
# import pickle | |
# import logging | |
# class FaceRecognitionSystem: | |
# def __init__(self, model_name: str = "buffalo_l"): | |
# # Set up logging | |
# logging.basicConfig(level=logging.INFO) | |
# self.logger = logging.getLogger(__name__) | |
# # Initialize the face analysis model | |
# try: | |
# self.face_analyzer = FaceAnalysis(name=model_name) | |
# self.face_analyzer.prepare(ctx_id=-1, det_size=(640, 640)) # Using CPU | |
# self.logger.info("Face analyzer initialized successfully") | |
# except Exception as e: | |
# self.logger.error(f"Error initializing face analyzer: {e}") | |
# raise | |
# # Dictionary to store known face embeddings | |
# self.known_face_embeddings: Dict[str, np.ndarray] = {} | |
# def process_known_faces(self, people_folder_path: str) -> None: | |
# """Process and store embeddings of known faces from a folder.""" | |
# embeddings_file = Path("known_faces_embeddings.pkl") | |
# try: | |
# # Load existing embeddings if available | |
# if embeddings_file.exists(): | |
# with open(embeddings_file, 'rb') as f: | |
# self.known_face_embeddings = pickle.load(f) | |
# self.logger.info("Loaded existing face embeddings") | |
# return | |
# self.logger.info("Processing known faces...") | |
# people_path = Path(people_folder_path) | |
# if not people_path.exists(): | |
# self.logger.warning(f"Directory not found: {people_folder_path}") | |
# return | |
# for person_path in people_path.glob("*"): | |
# if person_path.is_dir(): | |
# person_name = person_path.name | |
# embeddings_list = [] | |
# for img_path in person_path.glob("*"): | |
# if img_path.suffix.lower() in ['.jpg', '.jpeg', '.png']: | |
# img = cv2.imread(str(img_path)) | |
# if img is None: | |
# self.logger.warning(f"Could not read image: {img_path}") | |
# continue | |
# faces = self.face_analyzer.get(img) | |
# if faces: | |
# embeddings_list.append(faces[0].embedding) | |
# else: | |
# self.logger.warning(f"No face detected in {img_path}") | |
# if embeddings_list: | |
# self.known_face_embeddings[person_name] = np.mean(embeddings_list, axis=0) | |
# self.logger.info(f"Processed {person_name}'s faces") | |
# else: | |
# self.logger.warning(f"No valid faces found for {person_name}") | |
# # Save embeddings | |
# with open(embeddings_file, 'wb') as f: | |
# pickle.dump(self.known_face_embeddings, f) | |
# self.logger.info("Face processing complete") | |
# except Exception as e: | |
# self.logger.error(f"Error processing known faces: {e}") | |
# raise | |
# def identify_face(self, face_embedding: np.ndarray, threshold: float = 0.6) -> Tuple[str, float]: | |
# """Identify a face by comparing its embedding with known faces.""" | |
# try: | |
# best_match = "Unknown" | |
# best_score = float('inf') | |
# for person_name, known_embedding in self.known_face_embeddings.items(): | |
# similarity = np.dot(face_embedding, known_embedding) / ( | |
# np.linalg.norm(face_embedding) * np.linalg.norm(known_embedding) | |
# ) | |
# distance = 1 - similarity | |
# if distance < best_score: | |
# best_score = distance | |
# best_match = person_name | |
# return (best_match, best_score) if best_score < threshold else ("Unknown", best_score) | |
# except Exception as e: | |
# self.logger.error(f"Error in face identification: {e}") | |
# return ("Error", 1.0) | |
# def detect_and_identify(self, image_input) -> np.ndarray: | |
# """Detect and identify faces in an input image.""" | |
# try: | |
# # Handle both string paths and numpy arrays | |
# if isinstance(image_input, str): | |
# img = cv2.imread(image_input) | |
# else: | |
# img = image_input | |
# if img is None: | |
# raise ValueError("Could not read input image") | |
# faces = self.face_analyzer.get(img) | |
# for face in faces: | |
# bbox = face.bbox.astype(int) | |
# embedding = face.embedding | |
# name, score = self.identify_face(embedding) | |
# cv2.rectangle(img, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2) | |
# label = f"{name} ({1-score:.2f})" | |
# cv2.putText(img, label.upper(), (bbox[0], bbox[1]-10), | |
# cv2.FONT_HERSHEY_PLAIN, 2.0, (0, 255, 0), 2) | |
# return img | |
# except Exception as e: | |
# self.logger.error(f"Error in detection and identification: {e}") | |
# raise | |
# OLD: | |
# import cv2 | |
# import numpy as np | |
# import insightface | |
# from insightface.app import FaceAnalysis | |
# from insightface.data import get_image as ins_get_image | |
# import os | |
# from pathlib import Path | |
# from typing import Dict, List, Tuple | |
# import pickle | |
# class FaceRecognitionSystem: | |
# def __init__(self, model_name: str = "buffalo_l"): | |
# # Initialize the face analysis model | |
# self.face_analyzer = FaceAnalysis(name=model_name) | |
# self.face_analyzer.prepare(ctx_id=0, det_size=(640, 640)) | |
# # Dictionary to store known face embeddings | |
# self.known_face_embeddings: Dict[str, np.ndarray] = {} | |
# def process_known_faces(self, people_folder_path: str) -> None: | |
# """Process and store embeddings of known faces from a folder.""" | |
# # Create embeddings file path | |
# # embeddings_file = Path("known_face_embeddings copy2.pkl") | |
# embeddings_file = Path("data/model/known_faces_embeddings.pkl") | |
# # Load existing embeddings if available | |
# if embeddings_file.exists(): | |
# with open(embeddings_file, 'rb') as f: | |
# self.known_face_embeddings = pickle.load(f) | |
# print("Loaded existing face embeddings.") | |
# return | |
# print("Processing known faces...") | |
# for person_path in Path(people_folder_path).glob("*"): | |
# if person_path.is_dir(): | |
# person_name = person_path.name | |
# embeddings_list = [] | |
# # Process each image in person's folder | |
# for img_path in person_path.glob("*"): | |
# if img_path.suffix.lower() in ['.jpg', '.jpeg', '.png']: | |
# img = cv2.imread(str(img_path)) | |
# if img is None: | |
# continue | |
# # Get face embedding | |
# faces = self.face_analyzer.get(img) | |
# if faces: | |
# embeddings_list.append(faces[0].embedding) | |
# if embeddings_list: | |
# # Average all embeddings for this person | |
# self.known_face_embeddings[person_name] = np.mean(embeddings_list, axis=0) | |
# print(f"Processed {person_name}'s faces") | |
# # Save embeddings for future use | |
# with open(embeddings_file, 'wb') as f: | |
# pickle.dump(self.known_face_embeddings, f) | |
# print("Face processing complete.") | |
# # OLD: | |
# def identify_face(self, face_embedding: np.ndarray, threshold: float = 0.6) -> Tuple[str, float]: | |
# """Identify a face by comparing its embedding with known faces.""" | |
# best_match = "Unknown" | |
# best_score = float('inf') | |
# for person_name, known_embedding in self.known_face_embeddings.items(): | |
# # Calculate cosine similarity | |
# similarity = np.dot(face_embedding, known_embedding) / ( | |
# np.linalg.norm(face_embedding) * np.linalg.norm(known_embedding) | |
# ) | |
# distance = 1 - similarity | |
# if distance < best_score: | |
# best_score = distance | |
# best_match = person_name | |
# return (best_match, best_score) if best_score < threshold else ("Unknown", best_score) | |
# def detect_and_identify(self, image_input, output_path: str = None) -> np.ndarray: | |
# """Detect and identify faces in an input image.""" | |
# # Handle both string paths and numpy arrays | |
# if isinstance(image_input, str): | |
# img = cv2.imread(image_input) | |
# else: | |
# img = image_input | |
# if img is None: | |
# raise ValueError("Could not read input image") | |
# # Rest of the code remains the same | |
# faces = self.face_analyzer.get(img) | |
# for face in faces: | |
# bbox = face.bbox.astype(int) | |
# embedding = face.embedding | |
# name, score = self.identify_face(embedding) | |
# cv2.rectangle(img, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2) | |
# label = f"{name} ({1-score:.2f})" | |
# cv2.putText(img, label.upper(), (bbox[0], bbox[1]-10), | |
# cv2.FONT_HERSHEY_PLAIN, 4.2, (0, 255, 0), 2) | |
# # cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) | |
# if output_path: | |
# cv2.imwrite(output_path, img) | |
# return img | |
# # def detect_and_identify(self, image_path: str, output_path: str = None) -> np.ndarray: | |
# # """Detect and identify faces in an input image.""" | |
# # # Read input image | |
# # img = cv2.imread(image_path) | |
# # if img is None: | |
# # raise ValueError("Could not read input image") | |
# # # Detect faces | |
# # faces = self.face_analyzer.get(img) | |
# # # Draw results on image | |
# # for face in faces: | |
# # bbox = face.bbox.astype(int) | |
# # embedding = face.embedding | |
# # name, score = self.identify_face(embedding) | |
# # # Draw rectangle around face | |
# # cv2.rectangle(img, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2) | |
# # # Add name and confidence score | |
# # label = f"{name} ({1-score:.2f})" | |
# # cv2.putText(img, label, (bbox[0], bbox[1]-10), | |
# # cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0), 2) | |
# # # Save output image if path provided | |
# # if output_path: | |
# # cv2.imwrite(output_path, img) | |
# # return img |