File size: 7,588 Bytes
1f72938
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import cv2
import mediapipe as mp
from mediapipe import solutions
from mediapipe.framework.formats import landmark_pb2
import numpy as np
import math

# visualization libraries
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style

def draw_eyes_on_image(rgb_image, detection_result):
  
  # return rgb_image, 0, 0
  
  # canonical_face_model_uv_visualization in the below link
  # https://github.com/google/mediapipe/blob/a908d668c730da128dfa8d9f6bd25d519d006692/mediapipe/modules/face_geometry/data/canonical_face_model_uv_visualization.png
  left_eyes_bottom_list = [33, 7, 163, 144, 145, 153, 154, 155, 133]
  left_eyes_top_list = [246, 161, 160, 159, 158, 157, 173]
  right_eyes_bottom_list = [362, 382, 381, 380, 374, 373, 390, 249, 263]
  right_eyes_top_list = [398, 384, 385, 386, 387, 388, 466]
  
  face_landmarks_list = detection_result.face_landmarks
  annotated_image = np.copy(rgb_image)
  
  # We resize image to 640 * 360
  height, width, channels = rgb_image.shape
  
  # Loop through the detected faces to visualize. Actually, if we detect more than two faces, we will require user closer to the camera
  for idx in range(len(face_landmarks_list)):
    face_landmarks = face_landmarks_list[idx]

    mlist = []
    for landmark in face_landmarks:
      mlist.append([int(landmark.x * width), int(landmark.y * height), landmark.z])
      
    narray = np.copy(mlist)
    
    # Vertical line
    #
    #
    # Pick the largest difference (middle of the eyes)
    leftUp = narray[159]
    leftDown = narray[145]
    rightUp = narray[386]
    rightDown = narray[374]
    
    # compute left eye distance (vertical)
    leftUp_x = int(leftUp[0])
    leftUp_y = int(leftUp[1])
    leftDown_x = int(leftDown[0])
    leftDown_y = int(leftDown[1])
    leftVerDis = math.dist([leftUp_x, leftUp_y],[leftDown_x, leftDown_y])
    
    # compute right eye distance (vertical)
    rightUp_x = int(rightUp[0])
    rightUp_y = int(rightUp[1])
    rightDown_x = int(rightDown[0])
    rightDown_y = int(rightDown[1])
    rightVerDis = math.dist([rightUp_x, rightUp_y],[rightDown_x, rightDown_y])
    
    # print(f'leftVerDis: {leftVerDis} and rightVerDis: {rightVerDis}')
    
    # draw a line from left eye top to bottom
    annotated_image = cv2.line(rgb_image, (int(leftUp_x), int(leftUp_y)), (int(leftDown_x), int(leftDown_y)), (0, 200, 0), 1)
    
    # draw a line from right eye top to bottom
    annotated_image = cv2.line(rgb_image, (int(rightUp_x), int(rightUp_y)), (int(rightDown_x), int(rightDown_y)), (0, 200, 0), 1)
    #
    #
    # Horizontonal line
    #
    #
    # Pick the largest difference (middle of the eyes)
    leftLeft = narray[33]
    leftRight = narray[133]
    rightLeft = narray[362]
    rightRight = narray[263]
    
    # compute left eye distance (horizontal)
    leftLeft_x = int(leftLeft[0])
    leftLeft_y = int(leftLeft[1])
    leftRight_x = int(leftRight[0])
    leftRight_y = int(leftRight[1])
    leftHorDis = math.dist([leftLeft_x, leftLeft_y],[leftRight_x, leftRight_y])
    
    # compute right eye distance (horizontal)
    rightLeft_x = int(rightLeft[0])
    rightLeft_y = int(rightLeft[1])
    rightRight_x = int(rightRight[0])
    rightRight_y = int(rightRight[1])
    rightHorDis = math.dist([rightLeft_x, rightLeft_y],[rightRight_x, rightRight_y])
    
    # print(f'leftHorDis: {leftHorDis} and rightHorDis: {rightHorDis}')
    
    # draw a line from left eye top to bottom
    annotated_image = cv2.line(rgb_image, (int(leftLeft_x), int(leftLeft_y)), (int(leftRight_x), int(leftRight_y)), (0, 200, 0), 1)
    
    # draw a line from right eye top to bottom
    annotated_image = cv2.line(rgb_image, (int(rightLeft_x), int(rightLeft_y)), (int(rightRight_x), int(rightRight_y)), (0, 200, 0), 1)
    #
    #
    #
    #
    # print(f'leftRatio: {leftVerDis/leftHorDis} and rightRatio: {rightVerDis/rightHorDis}')
    
    leftRatio = leftVerDis/leftHorDis*100
    rightRatio = rightVerDis/rightHorDis*100

    
    # left_eyes_bottom = [narray[x] for x in left_eyes_bottom_list]
    # left_eyes_top = [narray[x] for x in left_eyes_top_list]
    # right_eyes_bottom = [narray[x] for x in right_eyes_bottom_list]
    # right_eyes_top = [narray[x] for x in right_eyes_top_list]
    
    # for p in left_eyes_bottom:
    #   annotated_image = cv2.circle(rgb_image, (int(p[0]), int(p[1])), radius=1, color=(0,0,255), thickness=1)
   
    # for p in left_eyes_top:
    #   annotated_image = cv2.circle(rgb_image, (int(p[0]), int(p[1])), radius=1, color=(0,0,255), thickness=1)
      
    # for p in right_eyes_bottom:
    #   annotated_image = cv2.circle(rgb_image, (int(p[0]), int(p[1])), radius=1, color=(0,0,255), thickness=1)
   
    # for p in right_eyes_top:
    #   annotated_image = cv2.circle(rgb_image, (int(p[0]), int(p[1])), radius=1, color=(0,0,255), thickness=1)
      
    
  return annotated_image, leftRatio, rightRatio

def draw_landmarks_on_image(rgb_image, detection_result):
  face_landmarks_list = detection_result.face_landmarks
  annotated_image = np.copy(rgb_image)

  # Loop through the detected faces to visualize. Actually, if we detect more than two faces, we will require user closer to the camera
  for idx in range(len(face_landmarks_list)):
    face_landmarks = face_landmarks_list[idx]

    # Draw the face landmarks.
    face_landmarks_proto = landmark_pb2.NormalizedLandmarkList()
    face_landmarks_proto.landmark.extend([
      landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z) for landmark in face_landmarks
    ])
    
    solutions.drawing_utils.draw_landmarks(
        image=annotated_image,
        landmark_list=face_landmarks_proto,
        connections=mp.solutions.face_mesh.FACEMESH_TESSELATION,
        landmark_drawing_spec=None,
        connection_drawing_spec=mp.solutions.drawing_styles
        .get_default_face_mesh_tesselation_style())
    solutions.drawing_utils.draw_landmarks(
        image=annotated_image,
        landmark_list=face_landmarks_proto,
        connections=mp.solutions.face_mesh.FACEMESH_CONTOURS,
        landmark_drawing_spec=None,
        connection_drawing_spec=mp.solutions.drawing_styles
        .get_default_face_mesh_contours_style())
    solutions.drawing_utils.draw_landmarks(
        image=annotated_image,
        landmark_list=face_landmarks_proto,
        connections=mp.solutions.face_mesh.FACEMESH_IRISES,
          landmark_drawing_spec=None,
          connection_drawing_spec=mp.solutions.drawing_styles
          .get_default_face_mesh_iris_connections_style())

  return annotated_image

def plot_face_blendshapes_bar_graph(face_blendshapes):
  # Extract the face blendshapes category names and scores.
  face_blendshapes_names = [face_blendshapes_category.category_name for face_blendshapes_category in face_blendshapes]
  face_blendshapes_scores = [face_blendshapes_category.score for face_blendshapes_category in face_blendshapes]
  # The blendshapes are ordered in decreasing score value.
  face_blendshapes_ranks = range(len(face_blendshapes_names))

  fig, ax = plt.subplots(figsize=(12, 12))
  bar = ax.barh(face_blendshapes_ranks, face_blendshapes_scores, label=[str(x) for x in face_blendshapes_ranks])
  ax.set_yticks(face_blendshapes_ranks, face_blendshapes_names)
  ax.invert_yaxis()

  # Label each bar with values
  for score, patch in zip(face_blendshapes_scores, bar.patches):
    plt.text(patch.get_x() + patch.get_width(), patch.get_y(), f"{score:.4f}", va="top")

  ax.set_xlabel('Score')
  ax.set_title("Face Blendshapes")
  plt.tight_layout()
  plt.show()