mirror of
https://github.com/serengil/deepface.git
synced 2025-06-04 02:20:06 +00:00
240 lines
8.4 KiB
Python
240 lines
8.4 KiB
Python
# built-in dependencies
|
|
import io
|
|
import cv2
|
|
import pytest
|
|
import numpy as np
|
|
import pytest
|
|
|
|
# project dependencies
|
|
from deepface import DeepFace
|
|
from deepface.commons.logger import Logger
|
|
|
|
logger = Logger()
|
|
|
|
|
|
def test_standard_represent():
|
|
img_path = "dataset/img1.jpg"
|
|
embedding_objs = DeepFace.represent(img_path)
|
|
# type should be list of dict
|
|
assert isinstance(embedding_objs, list)
|
|
|
|
for embedding_obj in embedding_objs:
|
|
assert isinstance(embedding_obj, dict)
|
|
|
|
embedding = embedding_obj["embedding"]
|
|
logger.debug(f"Function returned {len(embedding)} dimensional vector")
|
|
assert len(embedding) == 4096
|
|
logger.info("✅ test standard represent function done")
|
|
|
|
|
|
def test_standard_represent_with_io_object():
|
|
img_path = "dataset/img1.jpg"
|
|
default_embedding_objs = DeepFace.represent(img_path)
|
|
io_embedding_objs = DeepFace.represent(open(img_path, "rb"))
|
|
assert default_embedding_objs == io_embedding_objs
|
|
|
|
# Confirm non-seekable io objects are handled properly
|
|
io_obj = io.BytesIO(open(img_path, "rb").read())
|
|
io_obj.seek = None
|
|
no_seek_io_embedding_objs = DeepFace.represent(io_obj)
|
|
assert default_embedding_objs == no_seek_io_embedding_objs
|
|
|
|
# Confirm non-image io objects raise exceptions
|
|
with pytest.raises(ValueError, match="Failed to decode image"):
|
|
DeepFace.represent(io.BytesIO(open(r"../requirements.txt", "rb").read()))
|
|
|
|
logger.info("✅ test standard represent with io object function done")
|
|
|
|
|
|
def test_represent_for_skipped_detector_backend_with_image_path():
|
|
face_img = "dataset/img5.jpg"
|
|
img_objs = DeepFace.represent(img_path=face_img, detector_backend="skip")
|
|
assert len(img_objs) >= 1
|
|
img_obj = img_objs[0]
|
|
assert "embedding" in img_obj.keys()
|
|
assert "facial_area" in img_obj.keys()
|
|
assert isinstance(img_obj["facial_area"], dict)
|
|
assert "x" in img_obj["facial_area"].keys()
|
|
assert "y" in img_obj["facial_area"].keys()
|
|
assert "w" in img_obj["facial_area"].keys()
|
|
assert "h" in img_obj["facial_area"].keys()
|
|
assert "face_confidence" in img_obj.keys()
|
|
logger.info("✅ test represent function for skipped detector and image path input backend done")
|
|
|
|
|
|
def test_represent_for_preloaded_image():
|
|
face_img = "dataset/img5.jpg"
|
|
img = cv2.imread(face_img)
|
|
img_objs = DeepFace.represent(img_path=img)
|
|
# type should be list of dict
|
|
assert isinstance(img_objs, list)
|
|
assert len(img_objs) >= 1
|
|
|
|
for img_obj in img_objs:
|
|
assert isinstance(img_obj, dict)
|
|
assert "embedding" in img_obj.keys()
|
|
assert "facial_area" in img_obj.keys()
|
|
assert isinstance(img_obj["facial_area"], dict)
|
|
assert "x" in img_obj["facial_area"].keys()
|
|
assert "y" in img_obj["facial_area"].keys()
|
|
assert "w" in img_obj["facial_area"].keys()
|
|
assert "h" in img_obj["facial_area"].keys()
|
|
assert "face_confidence" in img_obj.keys()
|
|
logger.info("✅ test represent function for skipped detector and preloaded image done")
|
|
|
|
|
|
def test_represent_for_skipped_detector_backend_with_preloaded_image():
|
|
face_img = "dataset/img5.jpg"
|
|
img = cv2.imread(face_img)
|
|
img_objs = DeepFace.represent(img_path=img, detector_backend="skip")
|
|
assert len(img_objs) >= 1
|
|
img_obj = img_objs[0]
|
|
assert "embedding" in img_obj.keys()
|
|
assert "facial_area" in img_obj.keys()
|
|
assert isinstance(img_obj["facial_area"], dict)
|
|
assert "x" in img_obj["facial_area"].keys()
|
|
assert "y" in img_obj["facial_area"].keys()
|
|
assert "w" in img_obj["facial_area"].keys()
|
|
assert "h" in img_obj["facial_area"].keys()
|
|
assert "face_confidence" in img_obj.keys()
|
|
logger.info("✅ test represent function for skipped detector and preloaded image done")
|
|
|
|
|
|
def test_max_faces():
|
|
# confirm that input image has more than one face
|
|
results = DeepFace.represent(img_path="dataset/couple.jpg")
|
|
assert len(results) > 1
|
|
|
|
# test it with max faces arg
|
|
max_faces = 1
|
|
results = DeepFace.represent(img_path="dataset/couple.jpg", max_faces=max_faces)
|
|
assert len(results) == max_faces
|
|
|
|
|
|
def test_represent_detector_backend():
|
|
# Results using a detection backend.
|
|
results_1 = DeepFace.represent(img_path="dataset/img1.jpg")
|
|
assert len(results_1) == 1
|
|
|
|
# Results performing face extraction first.
|
|
faces = DeepFace.extract_faces(img_path="dataset/img1.jpg", color_face='bgr')
|
|
assert len(faces) == 1
|
|
|
|
# Images sent into represent need to be in BGR format.
|
|
img = faces[0]['face']
|
|
results_2 = DeepFace.represent(img_path=img, detector_backend="skip")
|
|
assert len(results_2) == 1
|
|
|
|
# The embeddings should be the exact same for both cases.
|
|
embedding_1 = results_1[0]['embedding']
|
|
embedding_2 = results_2[0]['embedding']
|
|
assert embedding_1 == embedding_2
|
|
logger.info("✅ test represent function for consistent output.")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model_name",
|
|
[
|
|
"VGG-Face",
|
|
"Facenet",
|
|
"SFace",
|
|
],
|
|
)
|
|
def test_batched_represent_for_list_input(model_name):
|
|
img_paths = [
|
|
"dataset/img1.jpg",
|
|
"dataset/img2.jpg",
|
|
"dataset/img3.jpg",
|
|
"dataset/img4.jpg",
|
|
"dataset/img5.jpg",
|
|
"dataset/couple.jpg",
|
|
]
|
|
|
|
expected_faces = [1, 1, 1, 1, 1, 2]
|
|
|
|
batched_embedding_objs = DeepFace.represent(img_path=img_paths, model_name=model_name)
|
|
|
|
# type should be list of list of dict for batch input
|
|
assert isinstance(batched_embedding_objs, list)
|
|
|
|
assert len(batched_embedding_objs) == len(
|
|
img_paths
|
|
), f"Expected {len(img_paths)} embeddings, got {len(batched_embedding_objs)}"
|
|
|
|
# the last one has two faces
|
|
for idx, embedding_objs in enumerate(batched_embedding_objs):
|
|
# type should be list of list of dict for batch input
|
|
# batched_embedding_objs was list already, embedding_objs should be list of dict
|
|
assert isinstance(embedding_objs, list)
|
|
for embedding_obj in embedding_objs:
|
|
assert isinstance(embedding_obj, dict)
|
|
|
|
assert expected_faces[idx] == len(
|
|
embedding_objs
|
|
), f"{img_paths[idx]} has {expected_faces[idx]} faces, but got {len(embedding_objs)} embeddings!"
|
|
|
|
for idx, img_path in enumerate(img_paths):
|
|
single_embedding_objs = DeepFace.represent(img_path=img_path, model_name=model_name)
|
|
# type should be list of dict for single input
|
|
assert isinstance(single_embedding_objs, list)
|
|
for embedding_obj in single_embedding_objs:
|
|
assert isinstance(embedding_obj, dict)
|
|
|
|
assert len(single_embedding_objs) == len(batched_embedding_objs[idx])
|
|
|
|
for alpha, beta in zip(single_embedding_objs, batched_embedding_objs[idx]):
|
|
assert isinstance(alpha, dict)
|
|
assert isinstance(beta, dict)
|
|
assert np.allclose(
|
|
alpha["embedding"], beta["embedding"], rtol=1e-2, atol=1e-2
|
|
), "Embeddings do not match within tolerance"
|
|
|
|
logger.info(f"✅ test batch represent function with string input for model {model_name} done")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model_name",
|
|
[
|
|
"VGG-Face",
|
|
"Facenet",
|
|
"SFace",
|
|
],
|
|
)
|
|
def test_batched_represent_for_numpy_input(model_name):
|
|
img_paths = [
|
|
"dataset/img1.jpg",
|
|
"dataset/img2.jpg",
|
|
"dataset/img3.jpg",
|
|
"dataset/img4.jpg",
|
|
"dataset/img5.jpg",
|
|
"dataset/couple.jpg",
|
|
]
|
|
expected_faces = [1, 1, 1, 1, 1, 2]
|
|
|
|
imgs = []
|
|
for img_path in img_paths:
|
|
img = cv2.imread(img_path)
|
|
img = cv2.resize(img, (1000, 1000))
|
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
# print(img.shape)
|
|
imgs.append(img)
|
|
|
|
imgs = np.array(imgs)
|
|
assert imgs.ndim == 4 and imgs.shape[0] == len(img_paths)
|
|
|
|
batched_embedding_objs = DeepFace.represent(img_path=imgs, model_name=model_name)
|
|
|
|
# type should be list of list of dict for batch input
|
|
assert isinstance(batched_embedding_objs, list)
|
|
for idx, batched_embedding_obj in enumerate(batched_embedding_objs):
|
|
assert isinstance(batched_embedding_obj, list)
|
|
# it also has to have the expected number of faces
|
|
assert len(batched_embedding_obj) == expected_faces[idx]
|
|
for embedding_obj in batched_embedding_obj:
|
|
assert isinstance(embedding_obj, dict)
|
|
|
|
# we should have the same number of embeddings as the number of images
|
|
assert len(batched_embedding_objs) == len(img_paths)
|
|
|
|
logger.info(f"✅ test batch represent function with numpy input for model {model_name} done")
|