Skip to content

Commit

Permalink
Close serengil#532, add docstring and some refactoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
Vincent-Stragier committed Mar 1, 2023
1 parent 3f3f26a commit 7b0f34c
Showing 1 changed file with 103 additions and 23 deletions.
126 changes: 103 additions & 23 deletions deepface/commons/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
# --------------------------------------------------


def initialize_folder():
def initialize_folder() -> None:
"""Initialize the folder for storing weights and models.
Raises:
OSError: if the folder cannot be created.
"""
home = get_deepface_home()

if not os.path.exists(home + "/.deepface"):
Expand All @@ -41,47 +46,66 @@ def initialize_folder():
print("Directory ", home, "/.deepface/weights created")


def get_deepface_home():
def get_deepface_home() -> str:
"""Get the home directory for storing weights and models.
Returns:
str: the home directory.
"""
return str(os.getenv("DEEPFACE_HOME", default=str(Path.home())))


# --------------------------------------------------


def loadBase64Img(uri):
"""Load image from base64 string.
Args:
uri: a base64 string.
Returns:
numpy array: the loaded image.
"""
encoded_data = uri.split(",")[1]
nparr = np.fromstring(base64.b64decode(encoded_data), np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
return img


def load_image(img):
"""Load image from path, url, base64 or numpy array.
Args:
img: a path, url, base64 or numpy array.
Raises:
ValueError: if the image path does not exist.
Returns:
numpy array: the loaded image.
"""
exact_image = False
base64_img = False
url_img = False

# The image is already a numpy array
if type(img).__module__ == np.__name__:
exact_image = True
# exact_image = True
return img

# The image is a base64 string
elif img.startswith("data:image/"):
base64_img = True
return loadBase64Img(img)

# The image is a url
elif img.startswith("http"):
url_img = True

# ---------------------------
return np.array(Image.open(requests.get(img, stream=True, timeout=60).raw).convert("RGB"))[:, :, ::-1]

if base64_img is True:
img = loadBase64Img(img)

elif url_img is True:
img = np.array(Image.open(requests.get(img, stream=True, timeout=60).raw).convert("RGB"))

elif exact_image is not True: # image path passed as input
# The image is a path
if exact_image is not True: # image path passed as input
if os.path.isfile(img) is not True:
raise ValueError(f"Confirm that {img} exists")

img = cv2.imread(img)
return cv2.imread(img)

return img

Expand All @@ -96,7 +120,23 @@ def extract_faces(
grayscale=False,
enforce_detection=True,
align=True,
):
) -> list:
"""Extract faces from an image.
Args:
img: a path, url, base64 or numpy array.
target_size (tuple, optional): the target size of the extracted faces. Defaults to (224, 224).
detector_backend (str, optional): the face detector backend. Defaults to "opencv".
grayscale (bool, optional): whether to convert the extracted faces to grayscale. Defaults to False.
enforce_detection (bool, optional): whether to enforce face detection. Defaults to True.
align (bool, optional): whether to align the extracted faces. Defaults to True.
Raises:
ValueError: if face could not be detected and enforce_detection is True.
Returns:
list: a list of extracted faces.
"""

# this is going to store a list of img itself (numpy), it region and confidence
extracted_faces = []
Expand All @@ -109,7 +149,8 @@ def extract_faces(
face_objs = [(img, img_region, 0)]
else:
face_detector = FaceDetector.build_model(detector_backend)
face_objs = FaceDetector.detect_faces(face_detector, detector_backend, img, align)
face_objs = FaceDetector.detect_faces(
face_detector, detector_backend, img, align)

# in case of no face found
if len(face_objs) == 0 and enforce_detection is True:
Expand All @@ -133,7 +174,8 @@ def extract_faces(
factor_1 = target_size[1] / current_img.shape[1]
factor = min(factor_0, factor_1)

dsize = (int(current_img.shape[1] * factor), int(current_img.shape[0] * factor))
dsize = (
int(current_img.shape[1] * factor), int(current_img.shape[0] * factor))
current_img = cv2.resize(current_img, dsize)

diff_0 = target_size[0] - current_img.shape[0]
Expand All @@ -152,7 +194,8 @@ def extract_faces(
else:
current_img = np.pad(
current_img,
((diff_0 // 2, diff_0 - diff_0 // 2), (diff_1 // 2, diff_1 - diff_1 // 2)),
((diff_0 // 2, diff_0 - diff_0 // 2),
(diff_1 // 2, diff_1 - diff_1 // 2)),
"constant",
)

Expand All @@ -161,7 +204,8 @@ def extract_faces(
current_img = cv2.resize(current_img, target_size)

# normalizing the image pixels
img_pixels = image.img_to_array(current_img) # what this line doing? must?
# what this line doing? must?
img_pixels = image.img_to_array(current_img)
img_pixels = np.expand_dims(img_pixels, axis=0)
img_pixels /= 255 # normalize input in [0, 1]

Expand All @@ -185,6 +229,15 @@ def extract_faces(


def normalize_input(img, normalization="base"):
"""Normalize input image.
Args:
img (numpy array): the input image.
normalization (str, optional): the normalization technique. Defaults to "base", for no normalization.
Returns:
numpy array: the normalized image.
"""

# issue 131 declares that some normalization techniques improves the accuracy

Expand Down Expand Up @@ -232,7 +285,15 @@ def normalize_input(img, normalization="base"):
return img


def find_target_size(model_name):
def find_target_size(model_name: str) -> tuple:
"""Find the target size of the model.
Args:
model_name (str): the model name.
Returns:
tuple: the target size.
"""

target_sizes = {
"VGG-Face": (224, 224),
Expand Down Expand Up @@ -267,6 +328,25 @@ def preprocess_face(
enforce_detection=True,
align=True,
):
"""Preprocess face.
Args:
img (numpy array): the input image.
target_size (tuple, optional): the target size. Defaults to (224, 224).
detector_backend (str, optional): the detector backend. Defaults to "opencv".
grayscale (bool, optional): whether to convert to grayscale. Defaults to False.
enforce_detection (bool, optional): whether to enforce face detection. Defaults to True.
align (bool, optional): whether to align the face. Defaults to True.
Returns:
numpy array: the preprocessed face.
Raises:
ValueError: if face is not detected and enforce_detection is True.
Deprecated:
0.0.78: Use extract_faces instead of preprocess_face.
"""
print("⚠️ Function preprocess_face is deprecated. Use extract_faces instead.")
result = None
img_objs = extract_faces(
Expand Down

0 comments on commit 7b0f34c

Please sign in to comment.