mirror of
https://github.com/serengil/deepface.git
synced 2025-07-21 09:20:02 +00:00
Merge pull request #1484 from RUTUPARNk/master
sanitized facial landmarks, and test for facial landmark sanitizaion
This commit is contained in:
commit
5057fbda18
@ -90,6 +90,22 @@ def extract_faces(
|
|||||||
|
|
||||||
height, width, _ = img.shape
|
height, width, _ = img.shape
|
||||||
|
|
||||||
|
def is_valid_landmark(coord: Optional[Union[tuple, list]]) -> bool:
|
||||||
|
"""
|
||||||
|
Check if a landmark coordinate is within valid image bounds.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
coord (tuple or list or None): (x, y) coordinate to check.
|
||||||
|
Returns:
|
||||||
|
bool: True if coordinate is valid and within bounds, False otherwise.
|
||||||
|
"""
|
||||||
|
if coord is None:
|
||||||
|
return False
|
||||||
|
if not (isinstance(coord, (tuple, list)) and len(coord) == 2):
|
||||||
|
return False
|
||||||
|
x, y = coord
|
||||||
|
return 0 <= x < width and 0 <= y < height
|
||||||
|
|
||||||
base_region = FacialAreaRegion(x=0, y=0, w=width, h=height, confidence=0)
|
base_region = FacialAreaRegion(x=0, y=0, w=width, h=height, confidence=0)
|
||||||
|
|
||||||
if detector_backend == "skip":
|
if detector_backend == "skip":
|
||||||
@ -149,22 +165,36 @@ def extract_faces(
|
|||||||
w = min(width - x - 1, int(current_region.w))
|
w = min(width - x - 1, int(current_region.w))
|
||||||
h = min(height - y - 1, int(current_region.h))
|
h = min(height - y - 1, int(current_region.h))
|
||||||
|
|
||||||
|
landmarks = {
|
||||||
|
"left_eye":current_region.left_eye,
|
||||||
|
"right_eye":current_region.right_eye,
|
||||||
|
"nose":current_region.nose,
|
||||||
|
"mouth_left":current_region.mouth_left,
|
||||||
|
"mouth_right":current_region.mouth_right
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sanitize landmarks - set invalid ones to None
|
||||||
|
for key, value in landmarks.items():
|
||||||
|
if not is_valid_landmark(value):
|
||||||
|
landmarks[key] = None
|
||||||
|
|
||||||
|
|
||||||
facial_area = {
|
facial_area = {
|
||||||
"x": x,
|
"x": x,
|
||||||
"y": y,
|
"y": y,
|
||||||
"w": w,
|
"w": w,
|
||||||
"h": h,
|
"h": h,
|
||||||
"left_eye": current_region.left_eye,
|
"left_eye": landmarks["left_eye"],
|
||||||
"right_eye": current_region.right_eye,
|
"right_eye": landmarks["right_eye"],
|
||||||
}
|
}
|
||||||
|
|
||||||
# optional nose, mouth_left and mouth_right fields are coming just for retinaface
|
# optional nose, mouth_left and mouth_right fields are coming just for retinaface
|
||||||
if current_region.nose is not None:
|
if current_region.nose is not None:
|
||||||
facial_area["nose"] = current_region.nose
|
facial_area["nose"] = landmarks["nose"]
|
||||||
if current_region.mouth_left is not None:
|
if current_region.mouth_left is not None:
|
||||||
facial_area["mouth_left"] = current_region.mouth_left
|
facial_area["mouth_left"] = landmarks["mouth_left"]
|
||||||
if current_region.mouth_right is not None:
|
if current_region.mouth_right is not None:
|
||||||
facial_area["mouth_right"] = current_region.mouth_right
|
facial_area["mouth_right"] = landmarks["mouth_right"]
|
||||||
|
|
||||||
resp_obj = {
|
resp_obj = {
|
||||||
"face": current_img,
|
"face": current_img,
|
||||||
|
70
tests/test_landmark_sanitization.py
Normal file
70
tests/test_landmark_sanitization.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
from deepface.modules.detection import extract_faces, DetectedFace, FacialAreaRegion
|
||||||
|
from deepface.commons.logger import Logger
|
||||||
|
|
||||||
|
logger = Logger()
|
||||||
|
|
||||||
|
def is_valid_landmark(coord, width, height):
|
||||||
|
if coord is None:
|
||||||
|
return False
|
||||||
|
if not (isinstance(coord, (tuple, list)) and len(coord) == 2):
|
||||||
|
return False
|
||||||
|
x, y = coord
|
||||||
|
return 0 <= x < width and 0 <= y < height
|
||||||
|
|
||||||
|
def sanitize_landmarks(region, width, height):
|
||||||
|
landmarks = {
|
||||||
|
"left_eye": region.left_eye,
|
||||||
|
"right_eye": region.right_eye,
|
||||||
|
"nose": region.nose,
|
||||||
|
"mouth_left": region.mouth_left,
|
||||||
|
"mouth_right": region.mouth_right,
|
||||||
|
}
|
||||||
|
for key, value in landmarks.items():
|
||||||
|
if not is_valid_landmark(value, width, height):
|
||||||
|
landmarks[key] = None
|
||||||
|
return landmarks
|
||||||
|
|
||||||
|
def test_sanitize_landmarks():
|
||||||
|
img = np.zeros((100, 100, 3), dtype=np.uint8)
|
||||||
|
height, width = img.shape[:2]
|
||||||
|
region = FacialAreaRegion(
|
||||||
|
x=10, y=10, w=50, h=50,
|
||||||
|
left_eye=(-5, 20), # invalid
|
||||||
|
right_eye=(20, 200), # invalid
|
||||||
|
nose=(30, 30), # valid
|
||||||
|
mouth_left=(150, 20), # invalid
|
||||||
|
mouth_right=(20, -10), # invalid
|
||||||
|
confidence=0.9
|
||||||
|
)
|
||||||
|
landmarks = sanitize_landmarks(region, width, height)
|
||||||
|
logger.info(f"Sanitized landmarks: {landmarks}")
|
||||||
|
assert landmarks["left_eye"] is None
|
||||||
|
assert landmarks["right_eye"] is None
|
||||||
|
assert landmarks["nose"] == (30, 30)
|
||||||
|
assert landmarks["mouth_left"] is None
|
||||||
|
assert landmarks["mouth_right"] is None
|
||||||
|
logger.info("Test passed: Invalid landmarks are sanitized to None.")
|
||||||
|
|
||||||
|
def test_extract_faces_sanitizes_landmarks(monkeypatch):
|
||||||
|
img = np.zeros((100, 100, 3), dtype=np.uint8)
|
||||||
|
facial_area = FacialAreaRegion(
|
||||||
|
x=10, y=10, w=50, h=50,
|
||||||
|
left_eye=(-5, 20), # invalid
|
||||||
|
right_eye=(20, 200), # invalid
|
||||||
|
nose=(30, 30), # valid
|
||||||
|
mouth_left=(150, 20), # invalid
|
||||||
|
mouth_right=(20, -10), # invalid
|
||||||
|
confidence=0.9
|
||||||
|
)
|
||||||
|
detected_face = DetectedFace(img=img, facial_area=facial_area, confidence=0.9)
|
||||||
|
monkeypatch.setattr("deepface.modules.detection.detect_faces", lambda *args, **kwargs: [detected_face])
|
||||||
|
result = extract_faces(img, detector_backend="opencv", enforce_detection=False)
|
||||||
|
facial_area_out = result[0]["facial_area"]
|
||||||
|
logger.info(f"Output facial_area: {facial_area_out}")
|
||||||
|
assert facial_area_out["left_eye"] is None
|
||||||
|
assert facial_area_out["right_eye"] is None
|
||||||
|
assert facial_area_out.get("nose") == (30, 30)
|
||||||
|
assert facial_area_out.get("mouth_left") is None
|
||||||
|
assert facial_area_out.get("mouth_right") is None
|
Loading…
x
Reference in New Issue
Block a user