File size: 5,062 Bytes
cf27ba5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e425192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf27ba5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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()