Skip to content

Commit 96d29ab

Browse files
committed
adding expand percentage argument for detection
1 parent 9494d47 commit 96d29ab

17 files changed

+314
-79
lines changed

deepface/DeepFace.py

+20
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def verify(
5858
distance_metric: str = "cosine",
5959
enforce_detection: bool = True,
6060
align: bool = True,
61+
expand_percentage: int = 0,
6162
normalization: str = "base",
6263
) -> Dict[str, Any]:
6364
"""
@@ -83,6 +84,8 @@ def verify(
8384
8485
align (bool): Flag to enable face alignment (default is True).
8586
87+
expand_percentage (int): expand detected facial area with a percentage (default is 0).
88+
8689
normalization (string): Normalize the input image before feeding it to the model.
8790
Options: base, raw, Facenet, Facenet2018, VGGFace, VGGFace2, ArcFace (default is base)
8891
@@ -119,6 +122,7 @@ def verify(
119122
distance_metric=distance_metric,
120123
enforce_detection=enforce_detection,
121124
align=align,
125+
expand_percentage=expand_percentage,
122126
normalization=normalization,
123127
)
124128

@@ -129,6 +133,7 @@ def analyze(
129133
enforce_detection: bool = True,
130134
detector_backend: str = "opencv",
131135
align: bool = True,
136+
expand_percentage: int = 0,
132137
silent: bool = False,
133138
) -> List[Dict[str, Any]]:
134139
"""
@@ -152,6 +157,8 @@ def analyze(
152157
153158
align (boolean): Perform alignment based on the eye positions (default is True).
154159
160+
expand_percentage (int): expand detected facial area with a percentage (default is 0).
161+
155162
silent (boolean): Suppress or allow some log messages for a quieter analysis process
156163
(default is False).
157164
@@ -209,6 +216,7 @@ def analyze(
209216
enforce_detection=enforce_detection,
210217
detector_backend=detector_backend,
211218
align=align,
219+
expand_percentage=expand_percentage,
212220
silent=silent,
213221
)
214222

@@ -221,6 +229,7 @@ def find(
221229
enforce_detection: bool = True,
222230
detector_backend: str = "opencv",
223231
align: bool = True,
232+
expand_percentage: int = 0,
224233
threshold: Optional[float] = None,
225234
normalization: str = "base",
226235
silent: bool = False,
@@ -249,6 +258,8 @@ def find(
249258
250259
align (boolean): Perform alignment based on the eye positions (default is True).
251260
261+
expand_percentage (int): expand detected facial area with a percentage (default is 0).
262+
252263
threshold (float): Specify a threshold to determine whether a pair represents the same
253264
person or different individuals. This threshold is used for comparing distances.
254265
If left unset, default pre-tuned threshold values will be applied based on the specified
@@ -286,6 +297,7 @@ def find(
286297
enforce_detection=enforce_detection,
287298
detector_backend=detector_backend,
288299
align=align,
300+
expand_percentage=expand_percentage,
289301
threshold=threshold,
290302
normalization=normalization,
291303
silent=silent,
@@ -298,6 +310,7 @@ def represent(
298310
enforce_detection: bool = True,
299311
detector_backend: str = "opencv",
300312
align: bool = True,
313+
expand_percentage: int = 0,
301314
normalization: str = "base",
302315
) -> List[Dict[str, Any]]:
303316
"""
@@ -320,6 +333,8 @@ def represent(
320333
321334
align (boolean): Perform alignment based on the eye positions (default is True).
322335
336+
expand_percentage (int): expand detected facial area with a percentage (default is 0).
337+
323338
normalization (string): Normalize the input image before feeding it to the model.
324339
Default is base. Options: base, raw, Facenet, Facenet2018, VGGFace, VGGFace2, ArcFace
325340
(default is base).
@@ -346,6 +361,7 @@ def represent(
346361
enforce_detection=enforce_detection,
347362
detector_backend=detector_backend,
348363
align=align,
364+
expand_percentage=expand_percentage,
349365
normalization=normalization,
350366
)
351367

@@ -409,6 +425,7 @@ def extract_faces(
409425
detector_backend: str = "opencv",
410426
enforce_detection: bool = True,
411427
align: bool = True,
428+
expand_percentage: int = 0,
412429
grayscale: bool = False,
413430
) -> List[Dict[str, Any]]:
414431
"""
@@ -429,6 +446,8 @@ def extract_faces(
429446
430447
align (bool): Flag to enable face alignment (default is True).
431448
449+
expand_percentage (int): expand detected facial area with a percentage (default is 0).
450+
432451
grayscale (boolean): Flag to convert the image to grayscale before
433452
processing (default is False).
434453
@@ -448,6 +467,7 @@ def extract_faces(
448467
detector_backend=detector_backend,
449468
enforce_detection=enforce_detection,
450469
align=align,
470+
expand_percentage=expand_percentage,
451471
grayscale=grayscale,
452472
human_readable=True,
453473
)

deepface/detectors/DetectorWrapper.py

+25-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
Yolo,
1313
YuNet,
1414
)
15+
from deepface.commons.logger import Logger
16+
17+
logger = Logger(module="deepface/detectors/DetectorWrapper.py")
1518

1619

1720
def build_model(detector_backend: str) -> Any:
@@ -52,19 +55,35 @@ def build_model(detector_backend: str) -> Any:
5255
return face_detector_obj[detector_backend]
5356

5457

55-
def detect_faces(detector_backend: str, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
58+
def detect_faces(
59+
detector_backend: str, img: np.ndarray, align: bool = True, expand_percentage: int = 0
60+
) -> List[DetectedFace]:
5661
"""
5762
Detect face(s) from a given image
5863
Args:
5964
detector_backend (str): detector name
65+
6066
img (np.ndarray): pre-loaded image
61-
alig (bool): enable or disable alignment after detection
67+
68+
align (bool): enable or disable alignment after detection
69+
70+
expand_percentage (int): expand detected facial area with a percentage (default is 0).
71+
6272
Returns:
6373
results (List[DetectedFace]): A list of DetectedFace objects
6474
where each object contains:
65-
- img (np.ndarray): The detected face as a NumPy array.
66-
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
67-
- confidence (float): The confidence score associated with the detected face.
75+
76+
- img (np.ndarray): The detected face as a NumPy array.
77+
78+
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
79+
80+
- confidence (float): The confidence score associated with the detected face.
6881
"""
6982
face_detector: Detector = build_model(detector_backend)
70-
return face_detector.detect_faces(img=img, align=align)
83+
if expand_percentage < 0:
84+
logger.warn(
85+
f"Expand percentage cannot be negative but you set it to {expand_percentage}."
86+
"Overwritten it to 0."
87+
)
88+
expand_percentage = 0
89+
return face_detector.detect_faces(img=img, align=align, expand_percentage=expand_percentage)

deepface/detectors/Dlib.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,27 @@ def build_model(self) -> dict:
5656
detector["sp"] = sp
5757
return detector
5858

59-
def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
59+
def detect_faces(
60+
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
61+
) -> List[DetectedFace]:
6062
"""
6163
Detect and align face with dlib
64+
6265
Args:
63-
face_detector (Any): dlib face detector object
64-
img (np.ndarray): pre-loaded image
65-
align (bool): default is true
66+
img (np.ndarray): pre-loaded image as numpy array
67+
68+
align (bool): flag to enable or disable alignment after detection (default is True)
69+
70+
expand_percentage (int): expand detected facial area with a percentage
71+
6672
Returns:
67-
results (List[DetectedFace]): A list of DetectedFace objects
73+
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
6874
where each object contains:
75+
6976
- img (np.ndarray): The detected face as a NumPy array.
77+
7078
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
79+
7180
- confidence (float): The confidence score associated with the detected face.
7281
"""
7382
# this is not a must dependency. do not import it in the global level.
@@ -79,6 +88,12 @@ def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace
7988
"Please install using 'pip install dlib' "
8089
) from e
8190

91+
if expand_percentage != 0:
92+
logger.warn(
93+
f"You set expand_percentage argument to {expand_percentage},"
94+
"but dlib hog handles detection by itself"
95+
)
96+
8297
resp = []
8398

8499
sp = self.model["sp"]

deepface/detectors/FastMtCnn.py

+24-5
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,27 @@ class FastMtCnnClient(Detector):
1212
def __init__(self):
1313
self.model = self.build_model()
1414

15-
def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
15+
def detect_faces(
16+
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
17+
) -> List[DetectedFace]:
1618
"""
1719
Detect and align face with mtcnn
20+
1821
Args:
19-
img (np.ndarray): pre-loaded image
20-
align (bool): default is true
22+
img (np.ndarray): pre-loaded image as numpy array
23+
24+
align (bool): flag to enable or disable alignment after detection (default is True)
25+
26+
expand_percentage (int): expand detected facial area with a percentage
27+
2128
Returns:
22-
results (List[DetectedFace]): A list of DetectedFace objects
29+
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
2330
where each object contains:
31+
2432
- img (np.ndarray): The detected face as a NumPy array.
33+
2534
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
35+
2636
- confidence (float): The confidence score associated with the detected face.
2737
"""
2838
resp = []
@@ -37,7 +47,16 @@ def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace
3747

3848
for current_detection in zip(*detections):
3949
x, y, w, h = xyxy_to_xywh(current_detection[0])
40-
detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
50+
51+
# expand the facial area to be extracted and stay within img.shape limits
52+
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
53+
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
54+
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
55+
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom
56+
57+
# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
58+
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]
59+
4160
img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)
4261
confidence = current_detection[1]
4362

deepface/detectors/MediaPipe.py

+24-5
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,27 @@ def build_model(self) -> Any:
2929
face_detection = mp_face_detection.FaceDetection(min_detection_confidence=0.7)
3030
return face_detection
3131

32-
def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
32+
def detect_faces(
33+
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
34+
) -> List[DetectedFace]:
3335
"""
3436
Detect and align face with mediapipe
37+
3538
Args:
36-
img (np.ndarray): pre-loaded image
37-
align (bool): default is true
39+
img (np.ndarray): pre-loaded image as numpy array
40+
41+
align (bool): flag to enable or disable alignment after detection (default is True)
42+
43+
expand_percentage (int): expand detected facial area with a percentage
44+
3845
Returns:
39-
results (List[DetectedFace): A list of DetectedFace objects
46+
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
4047
where each object contains:
48+
4149
- img (np.ndarray): The detected face as a NumPy array.
50+
4251
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
52+
4353
- confidence (float): The confidence score associated with the detected face.
4454
"""
4555
resp = []
@@ -74,7 +84,16 @@ def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace
7484
# left_ear = (int(landmarks[5].x * img_width), int(landmarks[5].y * img_height))
7585

7686
if x > 0 and y > 0:
77-
detected_face = img[y : y + h, x : x + w]
87+
88+
# expand the facial area to be extracted and stay within img.shape limits
89+
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
90+
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
91+
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
92+
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom
93+
94+
# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
95+
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]
96+
7897
img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)
7998

8099
if align:

deepface/detectors/MtCnn.py

+24-5
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,27 @@ class MtCnnClient(Detector):
1313
def __init__(self):
1414
self.model = MTCNN()
1515

16-
def detect_faces(self, img: np.ndarray, align: bool = True) -> List[DetectedFace]:
16+
def detect_faces(
17+
self, img: np.ndarray, align: bool = True, expand_percentage: int = 0
18+
) -> List[DetectedFace]:
1719
"""
1820
Detect and align face with mtcnn
21+
1922
Args:
20-
img (np.ndarray): pre-loaded image
21-
align (bool): default is true
23+
img (np.ndarray): pre-loaded image as numpy array
24+
25+
align (bool): flag to enable or disable alignment after detection (default is True)
26+
27+
expand_percentage (int): expand detected facial area with a percentage
28+
2229
Returns:
23-
results (List[DetectedFace]): A list of DetectedFace objects
30+
results (List[Tuple[DetectedFace]): A list of DetectedFace objects
2431
where each object contains:
32+
2533
- img (np.ndarray): The detected face as a NumPy array.
34+
2635
- facial_area (FacialAreaRegion): The facial area region represented as x, y, w, h
36+
2737
- confidence (float): The confidence score associated with the detected face.
2838
"""
2939

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

4151
for current_detection in detections:
4252
x, y, w, h = current_detection["box"]
43-
detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
53+
54+
# expand the facial area to be extracted and stay within img.shape limits
55+
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
56+
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
57+
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
58+
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom
59+
60+
# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
61+
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]
62+
4463
img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)
4564
confidence = current_detection["confidence"]
4665

0 commit comments

Comments
 (0)