|
1 | 1 | import os
|
2 | 2 | import warnings
|
3 | 3 | import logging
|
4 |
| -from typing import Union, Any, Optional, Dict |
| 4 | +from typing import Union, Any, Optional, Dict, Tuple |
5 | 5 |
|
6 | 6 | import numpy as np
|
7 | 7 | import tensorflow as tf
|
@@ -270,19 +270,62 @@ def extract_faces(
|
270 | 270 | nose = landmarks["nose"]
|
271 | 271 | # mouth_right = landmarks["mouth_right"]
|
272 | 272 | # mouth_left = landmarks["mouth_left"]
|
273 |
| - facial_img = postprocess.alignment_procedure(facial_img, right_eye, left_eye, nose) |
| 273 | + facial_img, rotate_angle, rotate_direction = postprocess.alignment_procedure( |
| 274 | + facial_img, right_eye, left_eye, nose |
| 275 | + ) |
274 | 276 |
|
275 | 277 | if align_first is True and len(obj) == 1:
|
276 |
| - facial_img = extract_faces( |
277 |
| - img_path=facial_img, |
278 |
| - threshold=threshold, |
279 |
| - model=model, |
280 |
| - allow_upscaling=allow_upscaling, |
281 |
| - expand_face_area=expand_face_area, |
282 |
| - align=False, |
283 |
| - align_first=False, |
284 |
| - )[0][:, :, ::-1] |
| 278 | + facial_area = rotate_facial_area( |
| 279 | + facial_area, rotate_angle, rotate_direction, img.shape |
| 280 | + ) |
| 281 | + # Expand the facial area to be extracted and stay within img.shape limits |
| 282 | + x1 = max(0, facial_area[0] - int((facial_area[2] * expand_face_area) / 100)) |
| 283 | + y1 = max(0, facial_area[1] - int((facial_area[3] * expand_face_area) / 100)) |
| 284 | + x2 = min( |
| 285 | + img.shape[1], facial_area[2] + int((facial_area[2] * expand_face_area) / 100) |
| 286 | + ) |
| 287 | + y2 = min( |
| 288 | + img.shape[0], facial_area[3] + int((facial_area[3] * expand_face_area) / 100) |
| 289 | + ) |
| 290 | + facial_img = facial_img[y1:y2, x1:x2] |
285 | 291 |
|
286 | 292 | resp.append(facial_img[:, :, ::-1])
|
287 | 293 |
|
288 | 294 | return resp
|
| 295 | + |
| 296 | +def rotate_facial_area(facial_area: Tuple[int, int, int, int], angle: float, direction: |
| 297 | + int, size: Tuple[int, int]) -> Tuple[int, int, int, int]: |
| 298 | + """ |
| 299 | + Rotate the facial area around its center. |
| 300 | +
|
| 301 | + Args: |
| 302 | + facial_area (tuple of int): Representing the (x1, y1, x2, y2) of the facial area. |
| 303 | + angle (float): Angle of rotation in degrees. |
| 304 | + direction (int): Direction of rotation (-1 for clockwise, 1 for counterclockwise). |
| 305 | + size (tuple of int): Tuple representing the size of the image (width, height). |
| 306 | +
|
| 307 | + Returns: |
| 308 | + tuple of int: Representing the new coordinates (x1, y1, x2, y2) of the rotated facial area. |
| 309 | + """ |
| 310 | + # Angle in radians |
| 311 | + angle = angle * np.pi / 180 |
| 312 | + |
| 313 | + # Translate the facial area to the center of the image |
| 314 | + x = (facial_area[0] + facial_area[2]) / 2 - size[1] / 2 |
| 315 | + y = (facial_area[1] + facial_area[3]) / 2 - size[0] / 2 |
| 316 | + |
| 317 | + # Rotate the facial area |
| 318 | + x_new = x * np.cos(angle) + y * direction * np.sin(angle) |
| 319 | + y_new = -x * direction * np.sin(angle) + y * np.cos(angle) |
| 320 | + |
| 321 | + # Translate the facial area back to the original position |
| 322 | + x_new = x_new + size[1] / 2 |
| 323 | + y_new = y_new + size[0] / 2 |
| 324 | + |
| 325 | + # Calculate the new facial area |
| 326 | + x1 = x_new - (facial_area[2] - facial_area[0]) / 2 |
| 327 | + y1 = y_new - (facial_area[3] - facial_area[1]) / 2 |
| 328 | + x2 = x_new + (facial_area[2] - facial_area[0]) / 2 |
| 329 | + y2 = y_new + (facial_area[3] - facial_area[1]) / 2 |
| 330 | + |
| 331 | + return (int(x1), int(y1), int(x2), int(y2)) |
0 commit comments