import os import cv2 import dlib import mediapipe as mp def read_image(image_path): """ Read an image from the given path and convert it to RGB. """ image = cv2.imread(image_path) if image is None: raise FileNotFoundError(f"Image not found at path: {image_path}") return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) class LandmarksDetector: def __init__(self, predictor_model_path=f'{os.path.dirname(os.path.abspath(__file__))}/utils/shape_predictor_68_face_landmarks.dat'): """ :param predictor_model_path: path to shape_predictor_68_face_landmarks.dat file """ self.detector = dlib.get_frontal_face_detector() # cnn_face_detection_model_v1 also can be used self.shape_predictor = dlib.shape_predictor(predictor_model_path) def get_landmarks(self, image): img = dlib.load_rgb_image(image) dets = self.detector(img, 1) dets = [dets[0]] for detection in dets: try: face_landmarks = [(item.x, item.y) for item in self.shape_predictor(img, detection).parts()] yield face_landmarks except: print("Exception in get_landmarks()!") class DlibLandmarkDetector: def __init__(self, predictor_model_path=f'{os.path.dirname(os.path.abspath(__file__))}/utils/shape_predictor_68_face_landmarks.dat'): """ :param predictor_model_path: path to shape_predictor_68_face_landmarks.dat file """ self.detector = dlib.get_frontal_face_detector() # cnn_face_detection_model_v1 also can be used self.predictor = dlib.shape_predictor(predictor_model_path) def get_landmarks(self, image_path): # image = dlib.load_rgb_image(image_path) image = read_image(image_path) height, width, _ = image.shape # Detect the faces in the image dets = self.detector(image, 1) # 1 indicates to upsample the image 1 time. Higher values may give better results # Raise an exception if no face is detected if len(dets) == 0: raise Exception("No face detected in the image at path: ", image_path) # Get the landmarks of the first face detected face_landmarks = [(item.x, item.y) for item in self.predictor(image, dets[0]).parts()] # Add corner and edge midpoints as landmarks to include the background corner_landmarks = [(1, 1), (1, height - 1), (width - 1, 1), (width - 1, height - 1)] edge_landmarks = [(1, (height - 1)//2), ((width - 1)//2, 1), ((width - 1)//2, height - 1), (width - 1, (height - 1)//2)] # Concatenate the landmarks landmarks = face_landmarks + corner_landmarks + edge_landmarks return landmarks, image def show_landmarked_image(self, image_path, landmarks): image = read_image(image_path) for landmark in landmarks: x, y = landmark cv2.circle(image, (x, y), 1, (255, 255, 0), -1) # image, (x, y), radius, color, thickness (-1 to fill) cv2.imshow('image', image) cv2.waitKey(0) cv2.destroyAllWindows() class MediaPipeLandmarkDetector: def __init__(self): self.face_mesh = mp.solutions.face_mesh.FaceMesh( static_image_mode=True, max_num_faces=1, min_detection_confidence=0.5) def get_landmarks(self, image_path): image = read_image(image_path) height, width, _ = image.shape image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Process the image results = self.face_mesh.process(image_rgb) # Raise an exception if no face is detected if results.multi_face_landmarks is None: raise Exception("No face detected in the image at path: ", image_path) # Extract the face landmarks face_landmarks = results.multi_face_landmarks[0] face_landmarks_normalized = [[landmark.x , landmark.y] for landmark in face_landmarks.landmark] # Add corner and edge midpoints as landmarks to include the background corner_landmarks = [(0, 0), (0, 1), (1, 0), (1, 1)] edge_landmarks = [(0, 0.5), (0.5, 0), (0.5, 1), (1, 0.5)] # Concatenate the corner and edge landmarks landmarks = corner_landmarks + edge_landmarks + face_landmarks_normalized # Multiply the landmarks with the image dimensions landmarks = [(int(x * width) - 1, int(y * height) - 1) for x, y in landmarks] landmarks = [(max(1, x), max(1, y)) for x, y in landmarks] return landmarks, image def show_landmarked_image(self, image_path, landmarks): image = cv2.imread(image_path) for landmark in landmarks: x, y = landmark cv2.circle(image, (x, y), 1, (255, 255, 0), -1) cv2.imshow('image', image) cv2.waitKey(0) cv2.destroyAllWindows()