Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 18 additions & 29 deletions retinaface/RetinaFace.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,16 +245,20 @@ def extract_faces(

x = facial_area[0]
y = facial_area[1]
w = facial_area[2]
h = facial_area[3]
w = facial_area[2] - x
h = facial_area[3] - y
Comment on lines +248 to +249
Copy link

@LilianBoulard LilianBoulard Mar 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a typo? I don't understand why that would be minus, and re-implementing with + instead of - works on my environment (with retina-face 0.0.15).

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because 3rd and 4th points are x and y coordinates of right down area. We can find width and height by subtracting them to left up area coordinates.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use plus, then you will have greater facial area. But it may exceeds the image coordinates and throw an exception. Correct calculation should be minus.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks for the clarification!


# expand the facial area to be extracted and stay within img.shape limits
x1 = max(0, x - int((w * expand_face_area) / 100)) # expand left
y1 = max(0, y - int((h * expand_face_area) / 100)) # expand top
x2 = min(img.shape[1], w + int((w * expand_face_area) / 100)) # expand right
y2 = min(img.shape[0], h + int((h * expand_face_area) / 100)) # expand bottom
if expand_face_area > 0:
expanded_w = w + int(w * expand_face_area / 100)
expanded_h = h + int(h * expand_face_area / 100)

facial_img = img[y1:y2, x1:x2]
# overwrite facial area
x = max(0, x - int((expanded_w - w) / 2))
y = max(0, y - int((expanded_h - h) / 2))
w = min(img.shape[1] - x, expanded_w)
h = min(img.shape[0] - y, expanded_h)

facial_img = img[y : y + h, x : x + w]

if align is True:
landmarks = identity["landmarks"]
Expand All @@ -265,32 +269,17 @@ def extract_faces(
# mouth_left = landmarks["mouth_left"]

# notice that left eye of one is seen on the right from your perspective
facial_img, rotate_angle, rotate_direction = postprocess.alignment_procedure(
aligned_img, rotate_angle, rotate_direction = postprocess.alignment_procedure(
img=img, left_eye=right_eye, right_eye=left_eye, nose=nose
)

# find new facial area coordinates after alignment
projected_facial_area = postprocess.rotate_facial_area(
facial_area, rotate_angle, rotate_direction, img.shape
)
# Expand the facial area to be extracted and stay within img.shape limits
x1 = max(
0,
projected_facial_area[0] - int((projected_facial_area[2] * expand_face_area) / 100),
)
y1 = max(
0,
projected_facial_area[1] - int((projected_facial_area[3] * expand_face_area) / 100),
)
x2 = min(
img.shape[1],
projected_facial_area[2] + int((projected_facial_area[2] * expand_face_area) / 100),
)
y2 = min(
img.shape[0],
projected_facial_area[3] + int((projected_facial_area[3] * expand_face_area) / 100),
rotated_x1, rotated_y1, rotated_x2, rotated_y2 = postprocess.rotate_facial_area(
(x, y, x + w, y + h), rotate_angle, rotate_direction, img.shape
)
facial_img = facial_img[y1:y2, x1:x2]
facial_img = aligned_img[
int(rotated_y1) : int(rotated_y2), int(rotated_x1) : int(rotated_x2)
]

resp.append(facial_img[:, :, ::-1])

Expand Down
18 changes: 16 additions & 2 deletions tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_analyze_crowded_photo():
plt.imshow(img[:, :, ::-1])
plt.axis("off")
plt.show()
cv2.imwrite("outputs/" + img_path.split("/")[1], img)
# cv2.imwrite("outputs/" + img_path.split("/")[1], img)

logger.info("✅ Crowded photo analysis test done")

Expand All @@ -75,7 +75,7 @@ def test_alignment_for_clock_way():


def do_alignment_checks(img: np.ndarray, expected_faces: int) -> None:
faces = RetinaFace.extract_faces(img_path=img, align=True, expand_face_area=10)
faces = RetinaFace.extract_faces(img_path=img, align=True, expand_face_area=25)

# it has one clear face
assert len(faces) == expected_faces
Expand All @@ -93,3 +93,17 @@ def do_alignment_checks(img: np.ndarray, expected_faces: int) -> None:

# check eyes are on same horizantal
assert abs(right_eye[1] - left_eye[1]) < 10


def test_different_expanding_ratios():
expand_ratios = [0, 25, 50]

for expand_ratio in expand_ratios:
faces = RetinaFace.extract_faces(
img_path="tests/dataset/img11.jpg", align=True, expand_face_area=expand_ratio
)
for face in faces:
if do_plotting is True:
plt.imshow(face)
plt.axis("off")
plt.show()