File size: 7,215 Bytes
f742815 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | """
Production Face Recognition Module for Attendr
This is the REAL implementation using the face_recognition library
Use this file after installing dlib and face_recognition
To activate:
1. Install dlib and face_recognition
2. Rename face_recognition_module.py to face_recognition_module_MOCK.py
3. Rename this file to face_recognition_module.py
4. Restart the Flask application
"""
import face_recognition
import numpy as np
from config import Config
import logging
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class FaceRecognitionModule:
"""Handles all face recognition operations using production library"""
def __init__(self, tolerance=None, model='hog'):
"""
Initialize face recognition module
Args:
tolerance: Face matching tolerance (lower = more strict)
model: Detection model ('hog' or 'cnn')
"""
self.tolerance = tolerance or Config.FACE_RECOGNITION_TOLERANCE
self.model = model or Config.FACE_DETECTION_MODEL
logger.info(f"PRODUCTION Face Recognition Module initialized with tolerance={self.tolerance}, model={self.model}")
def detect_faces(self, image_array):
"""
Detect faces in an image
Args:
image_array: numpy array of the image
Returns:
List of face locations [(top, right, bottom, left), ...]
"""
try:
face_locations = face_recognition.face_locations(image_array, model=self.model)
logger.info(f"Detected {len(face_locations)} face(s) in image")
return face_locations
except Exception as e:
logger.error(f"Face detection error: {str(e)}")
return []
def generate_face_encoding(self, image_array):
"""
Generate face encoding from an image
Implements: CapturedFace(x) - captures and encodes the face
Args:
image_array: numpy array of the image
Returns:
tuple: (success, encoding or error_message)
"""
try:
# Detect faces first
face_locations = self.detect_faces(image_array)
if len(face_locations) == 0:
return False, "No face detected in the image. Please ensure your face is clearly visible."
if len(face_locations) > 1:
return False, "Multiple faces detected. Please ensure only one person is in the frame."
# Generate encoding
encodings = face_recognition.face_encodings(image_array, face_locations)
if len(encodings) == 0:
return False, "Failed to generate face encoding. Please try again with better lighting."
encoding = encodings[0]
logger.info("Face encoding generated successfully")
return True, encoding
except Exception as e:
logger.error(f"Face encoding error: {str(e)}")
return False, f"Face encoding failed: {str(e)}"
def verify_face(self, captured_encoding, stored_encoding):
"""
Verify if captured face matches stored encoding
Implements: MatchStored(x) → FaceMatch(x)
Args:
captured_encoding: Face encoding from live capture
stored_encoding: Stored face encoding from database
Returns:
tuple: (is_match: bool, confidence: float)
"""
try:
if captured_encoding is None or stored_encoding is None:
logger.warning("One or both encodings are None")
return False, 0.0
# Convert to numpy arrays if needed
if not isinstance(captured_encoding, np.ndarray):
captured_encoding = np.array(captured_encoding)
if not isinstance(stored_encoding, np.ndarray):
stored_encoding = np.array(stored_encoding)
# Calculate face distance (lower = more similar)
face_distance = face_recognition.face_distance([stored_encoding], captured_encoding)[0]
# Convert distance to confidence percentage
confidence = (1 - face_distance) * 100
# Check if match is within tolerance
is_match = face_distance <= self.tolerance
logger.info(f"Face verification: match={is_match}, confidence={confidence:.2f}%, distance={face_distance:.4f}")
return is_match, confidence
except Exception as e:
logger.error(f"Face verification error: {str(e)}")
return False, 0.0
def register_face(self, image_array):
"""
Complete face registration process
Args:
image_array: numpy array of the image
Returns:
tuple: (success, encoding or error_message, face_location)
"""
try:
# Detect faces
face_locations = self.detect_faces(image_array)
if len(face_locations) == 0:
return False, "No face detected. Please ensure your face is clearly visible and well-lit.", None
if len(face_locations) > 1:
return False, "Multiple faces detected. Please ensure only one person is in the frame.", None
# Generate encoding
success, result = self.generate_face_encoding(image_array)
if success:
return True, result, face_locations[0]
else:
return False, result, None
except Exception as e:
logger.error(f"Face registration error: {str(e)}")
return False, f"Registration failed: {str(e)}", None
def compare_faces_batch(self, known_encodings, face_encoding_to_check):
"""
Compare a face encoding against multiple known encodings
Useful for identifying which student from a list
Args:
known_encodings: List of known face encodings
face_encoding_to_check: Face encoding to compare
Returns:
List of boolean matches
"""
try:
if not isinstance(face_encoding_to_check, np.ndarray):
face_encoding_to_check = np.array(face_encoding_to_check)
matches = face_recognition.compare_faces(
known_encodings,
face_encoding_to_check,
tolerance=self.tolerance
)
return matches
except Exception as e:
logger.error(f"Batch face comparison error: {str(e)}")
return []
# Singleton instance
face_recognition_module = FaceRecognitionModule()
|