fkl100/Behavior_and_Emotion_Recognition
0
1# File: utils.py
2
3import math
4import numpy as np
5import cv2
6import mediapipe as mp
7
8mp_face_mesh = mp.solutions.face_mesh
9
10def norm_coordinates(normalized_x, normalized_y, image_width, image_height):
11 """
12 Converts normalized coordinates to pixel coordinates.
13
14 Args:
15 normalized_x: Normalized x-coordinate (between 0 and 1).
16 normalized_y: Normalized y-coordinate (between 0 and 1).
17 image_width: Width of the image.
18 image_height: Height of the image.
19
20 Returns:
21 Tuple of pixel coordinates (x, y).
22 """
23 x_px = min(math.floor(normalized_x * image_width), image_width - 1)
24 y_px = min(math.floor(normalized_y * image_height), image_height - 1)
25 return x_px, y_px
26
27def get_box(fl, w, h):
28 """
29 Calculates bounding box coordinates for the detected face.
30
31 Args:
32 fl: Face landmarks from MediaPipe.
33 w: Width of the image.
34 h: Height of the image.
35
36 Returns:
37 Tuple of bounding box coordinates (startX, startY, endX, endY).
38 """
39 idx_to_coors = {}
40 for idx, landmark in enumerate(fl.landmark):
41 landmark_px = norm_coordinates(landmark.x, landmark.y, w, h)
42 if landmark_px:
43 idx_to_coors[idx] = landmark_px
44
45 x_min = np.min(np.asarray(list(idx_to_coors.values()))[:, 0])
46 y_min = np.min(np.asarray(list(idx_to_coors.values()))[:, 1])
47 endX = np.max(np.asarray(list(idx_to_coors.values()))[:, 0])
48 endY = np.max(np.asarray(list(idx_to_coors.values()))[:, 1])
49
50 (startX, startY) = (max(0, x_min), max(0, y_min))
51 (endX, endY) = (min(w - 1, endX), min(h - 1, endY))
52 return startX, startY, endX, endY
53
54def display_EMO_PRED(img, box, label='', color=(128, 128, 128), txt_color=(255, 255, 255), line_width=2, font_scale=1):
55 """
56 Draws a bounding box and displays the predicted emotion on the image.
57
58 Args:
59 img: Input image.
60 box: Bounding box coordinates (startX, startY, endX, endY).
61 label: Predicted emotion label.
62 color: Color of the bounding box.
63 txt_color: Color of the text.
64 line_width: Width of the bounding box.
65 font_scale: Scale factor to adjust the font size.
66
67 Returns:
68 Image with bounding box and predicted emotion.
69 """
70 lw = line_width or max(round(sum(img.shape) / 2 * 0.003), 2)
71 text2_color = (255, 0, 255)
72 p1, p2 = (int(box[0]), int(box[1])), (int(box[2]), int(box[3]))
73 cv2.rectangle(img, p1, p2, text2_color, thickness=lw, lineType=cv2.LINE_AA)
74 font = cv2.FONT_HERSHEY_SIMPLEX
75
76 tf = max(lw - 1, 1)
77 text_fond = (0, 0, 0)
78 text_width_2, text_height_2 = cv2.getTextSize(label, font, font_scale, tf)
79 text_width_2 = text_width_2[0] + round(((p2[0] - p1[0]) * 10) / 360)
80 center_face = p1[0] + round((p2[0] - p1[0]) / 2)
81
82 # Use the larger font scale and draw the text
83 cv2.putText(img, label,
84 (center_face - round(text_width_2 / 2), p1[1] - round(((p2[0] - p1[0]) * 20) / 360)), font,
85 font_scale, text_fond, thickness=tf, lineType=cv2.LINE_AA)
86 cv2.putText(img, label,
87 (center_face - round(text_width_2 / 2), p1[1] - round(((p2[0] - p1[0]) * 20) / 360)), font,
88 font_scale, text2_color, thickness=tf, lineType=cv2.LINE_AA)
89 return img
90
91
92def display_FPS(img, text, margin=1.0, box_scale=1.0):
93 """
94 Displays the FPS on the image.
95
96 Args:
97 img: Input image.
98 text: FPS text.
99 margin: Margin around the FPS text.
100 box_scale: Scale factor for the FPS box.
101
102 Returns:
103 Image with displayed FPS.
104 """
105 img_h, img_w, _ = img.shape
106 line_width = int(min(img_h, img_w) * 0.001) # line width
107 thickness = max(int(line_width / 3), 1) # font thickness
108
109 font_face = cv2.FONT_HERSHEY_SIMPLEX
110 font_color = (0, 0, 0)
111 font_scale = thickness / 1.5
112
113 t_w, t_h = cv2.getTextSize(text, font_face, font_scale, None)[0]
114
115 margin_n = int(t_h * margin)
116 sub_img = img[0 + margin_n: 0 + margin_n + t_h + int(2 * t_h * box_scale),
117 img_w - t_w - margin_n - int(2 * t_h * box_scale): img_w - margin_n]
118
119 white_rect = np.ones(sub_img.shape, dtype=np.uint8) * 255
120
121 img[0 + margin_n: 0 + margin_n + t_h + int(2 * t_h * box_scale),
122 img_w - t_w - margin_n - int(2 * t_h * box_scale):img_w - margin_n] = cv2.addWeighted(sub_img, 0.5, white_rect, .5,
123 1.0)
124
125 cv2.putText(img=img,
126 text=text,
127 org=(img_w - t_w - margin_n - int(2 * t_h * box_scale) // 2,
128 0 + margin_n + t_h + int(2 * t_h * box_scale) // 2),
129 fontFace=font_face,
130 fontScale=font_scale,
131 color=font_color,
132 thickness=thickness,
133 lineType=cv2.LINE_AA,
134 bottomLeftOrigin=False)
135
136 return img