Skip to content

Commit fb4da39

Browse files
authored
Merge pull request #1175 from serengil/feat-task-0704-resizing-functionality
resize functionality moved to represent module
2 parents 42ee298 + ae5d5b9 commit fb4da39

12 files changed

+163
-179
lines changed

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ demographies = DeepFace.analyze(img_path = "img4.jpg",
237237

238238
#face detection and alignment
239239
face_objs = DeepFace.extract_faces(img_path = "img.jpg",
240-
target_size = (224, 224),
241240
detector_backend = backends[4]
242241
)
243242
```

deepface/DeepFace.py

+3-8
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
import os
33
import warnings
44
import logging
5-
from typing import Any, Dict, List, Tuple, Union, Optional
5+
from typing import Any, Dict, List, Union, Optional
66

77
# this has to be set before importing tensorflow
88
os.environ["TF_USE_LEGACY_KERAS"] = "1"
99

1010
# pylint: disable=wrong-import-position
1111

1212
# 3rd party dependencies
13+
import cv2
1314
import numpy as np
1415
import pandas as pd
1516
import tensorflow as tf
@@ -439,7 +440,6 @@ def stream(
439440

440441
def extract_faces(
441442
img_path: Union[str, np.ndarray],
442-
target_size: Optional[Tuple[int, int]] = (224, 224),
443443
detector_backend: str = "opencv",
444444
enforce_detection: bool = True,
445445
align: bool = True,
@@ -453,9 +453,6 @@ def extract_faces(
453453
img_path (str or np.ndarray): Path to the first image. Accepts exact image path
454454
as a string, numpy array (BGR), or base64 encoded images.
455455
456-
target_size (tuple): final shape of facial image. black pixels will be
457-
added to resize the image (default is (224, 224)).
458-
459456
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
460457
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8' (default is opencv).
461458
@@ -485,13 +482,11 @@ def extract_faces(
485482

486483
return detection.extract_faces(
487484
img_path=img_path,
488-
target_size=target_size,
489485
detector_backend=detector_backend,
490486
enforce_detection=enforce_detection,
491487
align=align,
492488
expand_percentage=expand_percentage,
493489
grayscale=grayscale,
494-
human_readable=True,
495490
)
496491

497492

@@ -538,7 +533,6 @@ def detectFace(
538533
logger.warn("Function detectFace is deprecated. Use extract_faces instead.")
539534
face_objs = extract_faces(
540535
img_path=img_path,
541-
target_size=target_size,
542536
detector_backend=detector_backend,
543537
enforce_detection=enforce_detection,
544538
align=align,
@@ -547,4 +541,5 @@ def detectFace(
547541
extracted_face = None
548542
if len(face_objs) > 0:
549543
extracted_face = face_objs[0]["face"]
544+
extracted_face = cv2.resize(extracted_face, target_size)
550545
return extracted_face

deepface/modules/demography.py

+64-57
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from tqdm import tqdm
77

88
# project dependencies
9-
from deepface.modules import modeling, detection
9+
from deepface.modules import modeling, detection, preprocessing
1010
from deepface.extendedmodels import Gender, Race, Emotion
1111

1212

@@ -118,7 +118,6 @@ def analyze(
118118

119119
img_objs = detection.extract_faces(
120120
img_path=img_path,
121-
target_size=(224, 224),
122121
detector_backend=detector_backend,
123122
grayscale=False,
124123
enforce_detection=enforce_detection,
@@ -130,60 +129,68 @@ def analyze(
130129
img_content = img_obj["face"]
131130
img_region = img_obj["facial_area"]
132131
img_confidence = img_obj["confidence"]
133-
if img_content.shape[0] > 0 and img_content.shape[1] > 0:
134-
obj = {}
135-
# facial attribute analysis
136-
pbar = tqdm(
137-
range(0, len(actions)),
138-
desc="Finding actions",
139-
disable=silent if len(actions) > 1 else True,
140-
)
141-
for index in pbar:
142-
action = actions[index]
143-
pbar.set_description(f"Action: {action}")
144-
145-
if action == "emotion":
146-
emotion_predictions = modeling.build_model("Emotion").predict(img_content)
147-
sum_of_predictions = emotion_predictions.sum()
148-
149-
obj["emotion"] = {}
150-
for i, emotion_label in enumerate(Emotion.labels):
151-
emotion_prediction = 100 * emotion_predictions[i] / sum_of_predictions
152-
obj["emotion"][emotion_label] = emotion_prediction
153-
154-
obj["dominant_emotion"] = Emotion.labels[np.argmax(emotion_predictions)]
155-
156-
elif action == "age":
157-
apparent_age = modeling.build_model("Age").predict(img_content)
158-
# int cast is for exception - object of type 'float32' is not JSON serializable
159-
obj["age"] = int(apparent_age)
160-
161-
elif action == "gender":
162-
gender_predictions = modeling.build_model("Gender").predict(img_content)
163-
obj["gender"] = {}
164-
for i, gender_label in enumerate(Gender.labels):
165-
gender_prediction = 100 * gender_predictions[i]
166-
obj["gender"][gender_label] = gender_prediction
167-
168-
obj["dominant_gender"] = Gender.labels[np.argmax(gender_predictions)]
169-
170-
elif action == "race":
171-
race_predictions = modeling.build_model("Race").predict(img_content)
172-
sum_of_predictions = race_predictions.sum()
173-
174-
obj["race"] = {}
175-
for i, race_label in enumerate(Race.labels):
176-
race_prediction = 100 * race_predictions[i] / sum_of_predictions
177-
obj["race"][race_label] = race_prediction
178-
179-
obj["dominant_race"] = Race.labels[np.argmax(race_predictions)]
180-
181-
# -----------------------------
182-
# mention facial areas
183-
obj["region"] = img_region
184-
# include image confidence
185-
obj["face_confidence"] = img_confidence
186-
187-
resp_objects.append(obj)
132+
if img_content.shape[0] == 0 or img_content.shape[1] == 0:
133+
continue
134+
135+
# rgb to bgr
136+
img_content = img_content[:, :, ::-1]
137+
138+
# resize input image
139+
img_content = preprocessing.resize_image(img=img_content, target_size=(224, 224))
140+
141+
obj = {}
142+
# facial attribute analysis
143+
pbar = tqdm(
144+
range(0, len(actions)),
145+
desc="Finding actions",
146+
disable=silent if len(actions) > 1 else True,
147+
)
148+
for index in pbar:
149+
action = actions[index]
150+
pbar.set_description(f"Action: {action}")
151+
152+
if action == "emotion":
153+
emotion_predictions = modeling.build_model("Emotion").predict(img_content)
154+
sum_of_predictions = emotion_predictions.sum()
155+
156+
obj["emotion"] = {}
157+
for i, emotion_label in enumerate(Emotion.labels):
158+
emotion_prediction = 100 * emotion_predictions[i] / sum_of_predictions
159+
obj["emotion"][emotion_label] = emotion_prediction
160+
161+
obj["dominant_emotion"] = Emotion.labels[np.argmax(emotion_predictions)]
162+
163+
elif action == "age":
164+
apparent_age = modeling.build_model("Age").predict(img_content)
165+
# int cast is for exception - object of type 'float32' is not JSON serializable
166+
obj["age"] = int(apparent_age)
167+
168+
elif action == "gender":
169+
gender_predictions = modeling.build_model("Gender").predict(img_content)
170+
obj["gender"] = {}
171+
for i, gender_label in enumerate(Gender.labels):
172+
gender_prediction = 100 * gender_predictions[i]
173+
obj["gender"][gender_label] = gender_prediction
174+
175+
obj["dominant_gender"] = Gender.labels[np.argmax(gender_predictions)]
176+
177+
elif action == "race":
178+
race_predictions = modeling.build_model("Race").predict(img_content)
179+
sum_of_predictions = race_predictions.sum()
180+
181+
obj["race"] = {}
182+
for i, race_label in enumerate(Race.labels):
183+
race_prediction = 100 * race_predictions[i] / sum_of_predictions
184+
obj["race"][race_label] = race_prediction
185+
186+
obj["dominant_race"] = Race.labels[np.argmax(race_predictions)]
187+
188+
# -----------------------------
189+
# mention facial areas
190+
obj["region"] = img_region
191+
# include image confidence
192+
obj["face_confidence"] = img_confidence
193+
194+
resp_objects.append(obj)
188195

189196
return resp_objects

deepface/modules/detection.py

+4-66
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# built-in dependencies
2-
from typing import Any, Dict, List, Tuple, Union, Optional
2+
from typing import Any, Dict, List, Tuple, Union
33

44
# 3rd part dependencies
55
import numpy as np
@@ -10,30 +10,20 @@
1010
from deepface.modules import preprocessing
1111
from deepface.models.Detector import DetectedFace, FacialAreaRegion
1212
from deepface.detectors import DetectorWrapper
13-
from deepface.commons import package_utils
1413
from deepface.commons.logger import Logger
1514

1615
logger = Logger(module="deepface/modules/detection.py")
1716

1817
# pylint: disable=no-else-raise
1918

2019

21-
tf_major_version = package_utils.get_tf_major_version()
22-
if tf_major_version == 1:
23-
from keras.preprocessing import image
24-
elif tf_major_version == 2:
25-
from tensorflow.keras.preprocessing import image
26-
27-
2820
def extract_faces(
2921
img_path: Union[str, np.ndarray],
30-
target_size: Optional[Tuple[int, int]] = (224, 224),
3122
detector_backend: str = "opencv",
3223
enforce_detection: bool = True,
3324
align: bool = True,
3425
expand_percentage: int = 0,
3526
grayscale: bool = False,
36-
human_readable=False,
3727
) -> List[Dict[str, Any]]:
3828
"""
3929
Extract faces from a given image
@@ -42,9 +32,6 @@ def extract_faces(
4232
img_path (str or np.ndarray): Path to the first image. Accepts exact image path
4333
as a string, numpy array (BGR), or base64 encoded images.
4434
45-
target_size (tuple): final shape of facial image. black pixels will be
46-
added to resize the image.
47-
4835
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
4936
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8' (default is opencv)
5037
@@ -58,13 +45,10 @@ def extract_faces(
5845
grayscale (boolean): Flag to convert the image to grayscale before
5946
processing (default is False).
6047
61-
human_readable (bool): Flag to make the image human readable. 3D RGB for human readable
62-
or 4D BGR for ML models (default is False).
63-
6448
Returns:
6549
results (List[Dict[str, Any]]): A list of dictionaries, where each dictionary contains:
6650
67-
- "face" (np.ndarray): The detected face as a NumPy array.
51+
- "face" (np.ndarray): The detected face as a NumPy array in RGB format.
6852
6953
- "facial_area" (Dict[str, Any]): The detected face's regions as a dictionary containing:
7054
- keys 'x', 'y', 'w', 'h' with int values
@@ -122,57 +106,11 @@ def extract_faces(
122106
if grayscale is True:
123107
current_img = cv2.cvtColor(current_img, cv2.COLOR_BGR2GRAY)
124108

125-
# resize and padding
126-
if target_size is not None:
127-
factor_0 = target_size[0] / current_img.shape[0]
128-
factor_1 = target_size[1] / current_img.shape[1]
129-
factor = min(factor_0, factor_1)
130-
131-
dsize = (
132-
int(current_img.shape[1] * factor),
133-
int(current_img.shape[0] * factor),
134-
)
135-
current_img = cv2.resize(current_img, dsize)
136-
137-
diff_0 = target_size[0] - current_img.shape[0]
138-
diff_1 = target_size[1] - current_img.shape[1]
139-
if grayscale is False:
140-
# Put the base image in the middle of the padded image
141-
current_img = np.pad(
142-
current_img,
143-
(
144-
(diff_0 // 2, diff_0 - diff_0 // 2),
145-
(diff_1 // 2, diff_1 - diff_1 // 2),
146-
(0, 0),
147-
),
148-
"constant",
149-
)
150-
else:
151-
current_img = np.pad(
152-
current_img,
153-
(
154-
(diff_0 // 2, diff_0 - diff_0 // 2),
155-
(diff_1 // 2, diff_1 - diff_1 // 2),
156-
),
157-
"constant",
158-
)
159-
160-
# double check: if target image is not still the same size with target.
161-
if current_img.shape[0:2] != target_size:
162-
current_img = cv2.resize(current_img, target_size)
163-
164-
# normalizing the image pixels
165-
# what this line doing? must?
166-
img_pixels = image.img_to_array(current_img)
167-
img_pixels = np.expand_dims(img_pixels, axis=0)
168-
img_pixels /= 255 # normalize input in [0, 1]
169-
# discard expanded dimension
170-
if human_readable is True and len(img_pixels.shape) == 4:
171-
img_pixels = img_pixels[0]
109+
current_img = current_img / 255 # normalize input in [0, 1]
172110

173111
resp_objs.append(
174112
{
175-
"face": img_pixels[:, :, ::-1] if human_readable is True else img_pixels,
113+
"face": current_img[:, :, ::-1],
176114
"facial_area": {
177115
"x": int(current_region.x),
178116
"y": int(current_region.y),

0 commit comments

Comments
 (0)