Skip to content

Commit

Permalink
adding expand percentage argument for detection
Browse files Browse the repository at this point in the history
  • Loading branch information
serengil committed Jan 31, 2024
1 parent 9494d47 commit 96d29ab
Show file tree
Hide file tree
Showing 17 changed files with 314 additions and 79 deletions.
20 changes: 20 additions & 0 deletions deepface/DeepFace.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def verify(
distance_metric: str = "cosine",
enforce_detection: bool = True,
align: bool = True,
expand_percentage: int = 0,
normalization: str = "base",
) -> Dict[str, Any]:
"""
Expand All @@ -83,6 +84,8 @@ def verify(
align (bool): Flag to enable face alignment (default is True).
expand_percentage (int): expand detected facial area with a percentage (default is 0).
normalization (string): Normalize the input image before feeding it to the model.
Options: base, raw, Facenet, Facenet2018, VGGFace, VGGFace2, ArcFace (default is base)
Expand Down Expand Up @@ -119,6 +122,7 @@ def verify(
distance_metric=distance_metric,
enforce_detection=enforce_detection,
align=align,
expand_percentage=expand_percentage,
normalization=normalization,
)

Expand All @@ -129,6 +133,7 @@ def analyze(
enforce_detection: bool = True,
detector_backend: str = "opencv",
align: bool = True,
expand_percentage: int = 0,
silent: bool = False,
) -> List[Dict[str, Any]]:
"""
Expand All @@ -152,6 +157,8 @@ def analyze(
align (boolean): Perform alignment based on the eye positions (default is True).
expand_percentage (int): expand detected facial area with a percentage (default is 0).
silent (boolean): Suppress or allow some log messages for a quieter analysis process
(default is False).
Expand Down Expand Up @@ -209,6 +216,7 @@ def analyze(
enforce_detection=enforce_detection,
detector_backend=detector_backend,
align=align,
expand_percentage=expand_percentage,
silent=silent,
)

Expand All @@ -221,6 +229,7 @@ def find(
enforce_detection: bool = True,
detector_backend: str = "opencv",
align: bool = True,
expand_percentage: int = 0,
threshold: Optional[float] = None,
normalization: str = "base",
silent: bool = False,
Expand Down Expand Up @@ -249,6 +258,8 @@ def find(
align (boolean): Perform alignment based on the eye positions (default is True).
expand_percentage (int): expand detected facial area with a percentage (default is 0).
threshold (float): Specify a threshold to determine whether a pair represents the same
person or different individuals. This threshold is used for comparing distances.
If left unset, default pre-tuned threshold values will be applied based on the specified
Expand Down Expand Up @@ -286,6 +297,7 @@ def find(
enforce_detection=enforce_detection,
detector_backend=detector_backend,
align=align,
expand_percentage=expand_percentage,
threshold=threshold,
normalization=normalization,
silent=silent,
Expand All @@ -298,6 +310,7 @@ def represent(
enforce_detection: bool = True,
detector_backend: str = "opencv",
align: bool = True,
expand_percentage: int = 0,
normalization: str = "base",
) -> List[Dict[str, Any]]:
"""
Expand All @@ -320,6 +333,8 @@ def represent(
align (boolean): Perform alignment based on the eye positions (default is True).
expand_percentage (int): expand detected facial area with a percentage (default is 0).
normalization (string): Normalize the input image before feeding it to the model.
Default is base. Options: base, raw, Facenet, Facenet2018, VGGFace, VGGFace2, ArcFace
(default is base).
Expand All @@ -346,6 +361,7 @@ def represent(
enforce_detection=enforce_detection,
detector_backend=detector_backend,
align=align,
expand_percentage=expand_percentage,
normalization=normalization,
)

Expand Down Expand Up @@ -409,6 +425,7 @@ def extract_faces(
detector_backend: str = "opencv",
enforce_detection: bool = True,
align: bool = True,
expand_percentage: int = 0,
grayscale: bool = False,
) -> List[Dict[str, Any]]:
"""
Expand All @@ -429,6 +446,8 @@ def extract_faces(
align (bool): Flag to enable face alignment (default is True).
expand_percentage (int): expand detected facial area with a percentage (default is 0).
grayscale (boolean): Flag to convert the image to grayscale before
processing (default is False).
Expand All @@ -448,6 +467,7 @@ def extract_faces(
detector_backend=detector_backend,
enforce_detection=enforce_detection,
align=align,
expand_percentage=expand_percentage,
grayscale=grayscale,
human_readable=True,
)
Expand Down
31 changes: 25 additions & 6 deletions deepface/detectors/DetectorWrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
Yolo,
YuNet,
)
from deepface.commons.logger import Logger

logger = Logger(module="deepface/detectors/DetectorWrapper.py")


def build_model(detector_backend: str) -> Any:
Expand Down Expand Up @@ -52,19 +55,35 @@ def build_model(detector_backend: str) -> Any:
return face_detector_obj[detector_backend]


def detect_faces(detector_backend: str, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
def detect_faces(
detector_backend: str, img: np.ndarray, align: bool = True, expand_percentage: int = 0
) -> List[DetectedFace]:
"""
Detect face(s) from a given image
Args:
detector_backend (str): detector name
img (np.ndarray): pre-loaded image
alig (bool): enable or disable alignment after detection
align (bool): enable or disable alignment after detection
expand_percentage (int): expand detected facial area with a percentage (default is 0).
Returns:
results (List[DetectedFace]): A list of DetectedFace objects
where each object contains:
- img (np.ndarray): The detected face as a NumPy array.
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
- confidence (float): The confidence score associated with the detected face.
- img (np.ndarray): The detected face as a NumPy array.
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
- confidence (float): The confidence score associated with the detected face.
"""
face_detector: Detector = build_model(detector_backend)
return face_detector.detect_faces(img=img, align=align)
if expand_percentage < 0:
logger.warn(
f"Expand percentage cannot be negative but you set it to {expand_percentage}."
"Overwritten it to 0."
)
expand_percentage = 0
return face_detector.detect_faces(img=img, align=align, expand_percentage=expand_percentage)
25 changes: 20 additions & 5 deletions deepface/detectors/Dlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,27 @@ def build_model(self) -> dict:
detector["sp"] = sp
return detector

def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
def detect_faces(
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
) -> List[DetectedFace]:
"""
Detect and align face with dlib
Args:
face_detector (Any): dlib face detector object
img (np.ndarray): pre-loaded image
align (bool): default is true
img (np.ndarray): pre-loaded image as numpy array
align (bool): flag to enable or disable alignment after detection (default is True)
expand_percentage (int): expand detected facial area with a percentage
Returns:
results (List[DetectedFace]): A list of DetectedFace objects
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
where each object contains:
- img (np.ndarray): The detected face as a NumPy array.
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
- confidence (float): The confidence score associated with the detected face.
"""
# this is not a must dependency. do not import it in the global level.
Expand All @@ -79,6 +88,12 @@ def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace
"Please install using 'pip install dlib' "
) from e

if expand_percentage != 0:
logger.warn(
f"You set expand_percentage argument to {expand_percentage},"
"but dlib hog handles detection by itself"
)

resp = []

sp = self.model["sp"]
Expand Down
29 changes: 24 additions & 5 deletions deepface/detectors/FastMtCnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,27 @@ class FastMtCnnClient(Detector):
def __init__(self):
self.model = self.build_model()

def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
def detect_faces(
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
) -> List[DetectedFace]:
"""
Detect and align face with mtcnn
Args:
img (np.ndarray): pre-loaded image
align (bool): default is true
img (np.ndarray): pre-loaded image as numpy array
align (bool): flag to enable or disable alignment after detection (default is True)
expand_percentage (int): expand detected facial area with a percentage
Returns:
results (List[DetectedFace]): A list of DetectedFace objects
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
where each object contains:
- img (np.ndarray): The detected face as a NumPy array.
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
- confidence (float): The confidence score associated with the detected face.
"""
resp = []
Expand All @@ -37,7 +47,16 @@ def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace

for current_detection in zip(*detections):
x, y, w, h = xyxy_to_xywh(current_detection[0])
detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]

# expand the facial area to be extracted and stay within img.shape limits
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom

# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]

img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)
confidence = current_detection[1]

Expand Down
29 changes: 24 additions & 5 deletions deepface/detectors/MediaPipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,27 @@ def build_model(self) -> Any:
face_detection = mp_face_detection.FaceDetection(min_detection_confidence=0.7)
return face_detection

def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
def detect_faces(
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
) -> List[DetectedFace]:
"""
Detect and align face with mediapipe
Args:
img (np.ndarray): pre-loaded image
align (bool): default is true
img (np.ndarray): pre-loaded image as numpy array
align (bool): flag to enable or disable alignment after detection (default is True)
expand_percentage (int): expand detected facial area with a percentage
Returns:
results (List[DetectedFace): A list of DetectedFace objects
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
where each object contains:
- img (np.ndarray): The detected face as a NumPy array.
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
- confidence (float): The confidence score associated with the detected face.
"""
resp = []
Expand Down Expand Up @@ -74,7 +84,16 @@ def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace
# left_ear = (int(landmarks[5].x * img_width), int(landmarks[5].y * img_height))

if x > 0 and y > 0:
detected_face = img[y : y + h, x : x + w]

# expand the facial area to be extracted and stay within img.shape limits
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom

# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]

img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)

if align:
Expand Down
29 changes: 24 additions & 5 deletions deepface/detectors/MtCnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,27 @@ class MtCnnClient(Detector):
def __init__(self):
self.model = MTCNN()

def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
def detect_faces(
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
) -> List[DetectedFace]:
"""
Detect and align face with mtcnn
Args:
img (np.ndarray): pre-loaded image
align (bool): default is true
img (np.ndarray): pre-loaded image as numpy array
align (bool): flag to enable or disable alignment after detection (default is True)
expand_percentage (int): expand detected facial area with a percentage
Returns:
results (List[DetectedFace]): A list of DetectedFace objects
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
where each object contains:
- img (np.ndarray): The detected face as a NumPy array.
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
- confidence (float): The confidence score associated with the detected face.
"""

Expand All @@ -40,7 +50,16 @@ def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace

for current_detection in detections:
x, y, w, h = current_detection["box"]
detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]

# expand the facial area to be extracted and stay within img.shape limits
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom

# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]

img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)
confidence = current_detection["confidence"]

Expand Down
Loading

0 comments on commit 96d29ab

Please sign in to comment.