Source code for dronebuddylib.atoms.facerecognition.face_recognition_impl
import cv2
import numpy as np
import pkg_resources
from dronebuddylib.atoms.facerecognition.i_face_recognition import IFaceRecognition
from dronebuddylib.models.engine_configurations import EngineConfigurations
from dronebuddylib.utils import FileWritingException, get_logger
logger = get_logger()
import face_recognition
[docs]
class FaceRecognitionImpl(IFaceRecognition):
"""
Implementation of the IFaceRecognition interface using face_recognition library.
"""
def __init__(self, engine_configurations: EngineConfigurations):
"""
Initialize the FaceRecognitionImpl class.
Args:
engine_configurations (EngineConfigurations): The configurations for the engine.
"""
super().__init__(engine_configurations)
[docs]
def recognize_face(self, image) -> list:
"""
Recognize faces in an image.
Args:
image: The image containing faces to be recognized.
Returns:
list: A list of recognized faces.
"""
processed_frame = self.process_frame_for_recognition(image)
# Find all the faces and face encodings in the current frame of video
face_locations = face_recognition.face_locations(processed_frame)
face_encodings = face_recognition.face_encodings(processed_frame, face_locations)
# load the user list from memory
face_names = self.load_known_face_names()
# load the encodings
known_face_encodings = self.load_known_face_encodings(face_names)
recognized_faces = []
for face_encoding in face_encodings:
# See if the face is a match for the known face(s)
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Unknown"
# If a match was found in known_face_encodings, just use the first one.
if True in matches:
first_match_index = matches.index(True)
# Or instead, use the known face with the smallest distance to the new face
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
name = face_names[best_match_index]
recognized_faces.append(name)
return recognized_faces
[docs]
def process_frame_for_recognition(self, frame):
"""
Pre-process the frame for face recognition.
Args:
frame: The frame to be processed.
Returns:
The processed frame.
"""
# Resize frame of video to 1/4 size for faster face recognition processing
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
# Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)
rgb_small_frame = np.ascontiguousarray(small_frame[:, :, ::-1])
logger.debug("Face Recognition : shape of the frame : ", rgb_small_frame.shape)
return rgb_small_frame
[docs]
def load_known_face_names(self):
"""
Load the known face names from a file.
Returns:
list: A list of known face names.
"""
path = pkg_resources.resource_filename(__name__, "resources/facerecognition/known_names.txt")
known_face_names = self.read_file_into_list(path)
return known_face_names
[docs]
def load_known_face_encodings(self, known_face_names):
"""
Load the known face encodings from files.
Args:
known_face_names: A list of known face names.
Returns:
list: A list of known face encodings.
"""
known_face_encodings = []
for name in known_face_names:
face_path = pkg_resources.resource_filename(__name__, "resources/facerecognition/images/" + name + ".jpg")
face_image = face_recognition.load_image_file(face_path)
face_encoding = face_recognition.face_encodings(face_image)[0]
known_face_encodings.append(face_encoding)
return known_face_encodings
[docs]
def read_file_into_list(self, filename):
"""
Read a file into a list.
Args:
filename: The path to the file.
Returns:
list: A list of lines from the file.
"""
field_list = []
try:
with open(filename, "r") as file:
lines = file.readlines()
lines_without_newline = [line.rstrip('\n') for line in lines]
return [line for line in lines_without_newline if line]
except FileNotFoundError as e:
raise FileNotFoundError("The specified file is not found.", e) from e
[docs]
def remember_face(self, image_path, name) -> bool:
"""
Associate a name with a face in an image.
Args:
image_path: The path to the image containing the face.
name: The name to be associated with the face.
Returns:
bool: True if the association was successful, False otherwise.
"""
try:
text_file_path = pkg_resources.resource_filename(__name__, "resources/facerecognition/known_names.txt")
with open(text_file_path, 'a') as file:
file.write(name + '\n')
except IOError:
logger.error("Error while writing to the file : ", name)
raise FileWritingException("Error while writing to the file : " + name)
try:
new_file_name = pkg_resources.resource_filename(__name__,
"resources/facerecognition/images/" + name + ".jpg")
loaded_image = cv2.imread(image_path)
cv2.imwrite(new_file_name, loaded_image)
except IOError:
raise FileWritingException("Error while writing to the file : ", new_file_name)
return True
[docs]
def get_required_params(self) -> list:
"""
Get the required parameters for the FaceRecognitionImpl class.
Returns:
list: A list of required parameters.
"""
pass
[docs]
def get_optional_params(self) -> list:
"""
Get the optional parameters for the FaceRecognitionImpl class.
Returns:
list: A list of optional parameters.
"""
pass
[docs]
def get_class_name(self) -> str:
"""
Get the class name of the FaceRecognitionImpl class.
Returns:
str: The class name.
"""
return 'FACE_RECOGNITION'
[docs]
def get_algorithm_name(self) -> str:
"""
Get the algorithm name of the FaceRecognitionImpl class.
Returns:
str: The algorithm name.
"""
return 'Face Recognition'