faceverification / test /test_image_processor.py
leandrodevai's picture
Sync from GitHub via hub-sync
c628352 verified
Raw
History Blame Contribute Delete
3.95 kB
from unittest.mock import Mock
import pytest
import torch
from PIL import Image
from faceverification.core import image_processor
from faceverification.core.image_processor import FaceNotDetectedError, ImageProcessor
class FakeMTCNN:
instances = []
def __init__(self, **kwargs):
self.kwargs = kwargs
FakeMTCNN.instances.append(self)
class FakeFacenet:
instances = []
def __init__(self, pretrained):
self.pretrained = pretrained
self.eval_called = False
self.device = None
FakeFacenet.instances.append(self)
def eval(self):
self.eval_called = True
return self
def to(self, device):
self.device = device
return self
def test_init_uses_cpu_when_auto_and_cuda_is_unavailable(monkeypatch):
FakeMTCNN.instances = []
FakeFacenet.instances = []
monkeypatch.setattr(image_processor.torch.cuda, "is_available", lambda: False)
monkeypatch.setattr(image_processor, "MTCNN", FakeMTCNN)
monkeypatch.setattr(image_processor, "InceptionResnetV1", FakeFacenet)
processor = ImageProcessor(
device="auto",
mtcnn_thresholds=(0.1, 0.2, 0.3),
facenet_pretrained="test-weights",
)
assert processor.device == "cpu"
assert FakeMTCNN.instances[0].kwargs == {
"select_largest": False,
"device": "cpu",
"thresholds": [0.1, 0.2, 0.3],
}
assert FakeFacenet.instances[0].pretrained == "test-weights"
assert FakeFacenet.instances[0].eval_called is True
assert FakeFacenet.instances[0].device == "cpu"
def test_init_rejects_invalid_device():
with pytest.raises(ValueError, match="Device must be"):
ImageProcessor(device="gpu")
def test_get_embedding_returns_normalized_embedding():
processor = ImageProcessor.__new__(ImageProcessor)
processor.device = "cpu"
processor.mtcnn = Mock(return_value=torch.ones((3, 2, 2)))
processor.facenet = Mock(return_value=torch.tensor([[3.0, 4.0]]))
image = Image.new("RGB", (10, 10))
embedding = processor.get_embedding(image)
torch.testing.assert_close(embedding, torch.tensor([0.6, 0.8]))
processor.mtcnn.assert_called_once_with(image)
assert processor.facenet.call_args.args[0].shape == torch.Size([1, 3, 2, 2])
def test_get_embedding_keeps_batched_face_tensor_shape():
processor = ImageProcessor.__new__(ImageProcessor)
processor.device = "cpu"
processor.mtcnn = Mock(return_value=torch.ones((1, 3, 2, 2)))
processor.facenet = Mock(return_value=torch.tensor([[3.0, 4.0]]))
image = Image.new("RGB", (10, 10))
embedding = processor.get_embedding(image)
torch.testing.assert_close(embedding, torch.tensor([0.6, 0.8]))
assert processor.facenet.call_args.args[0].shape == torch.Size([1, 3, 2, 2])
def test_get_embedding_raises_when_no_face_is_detected():
processor = ImageProcessor.__new__(ImageProcessor)
processor.mtcnn = Mock(return_value=None)
with pytest.raises(FaceNotDetectedError, match="No face detected"):
processor.get_embedding(Image.new("RGB", (10, 10)))
def test_detect_faces_draws_boxes_and_returns_true():
processor = ImageProcessor.__new__(ImageProcessor)
processor.mtcnn = Mock()
processor.mtcnn.detect.return_value = (
[[1.0, 1.0, 8.0, 8.0]],
[0.98765],
)
image = Image.new("RGB", (10, 10), "white")
annotated_image, presence = processor.detect_faces(image)
assert annotated_image is image
assert presence is True
assert image.getpixel((1, 1)) == (255, 0, 0)
def test_detect_faces_returns_false_when_no_boxes_are_detected():
processor = ImageProcessor.__new__(ImageProcessor)
processor.mtcnn = Mock()
processor.mtcnn.detect.return_value = (None, None)
image = Image.new("RGB", (10, 10), "white")
annotated_image, presence = processor.detect_faces(image)
assert annotated_image is image
assert presence is False