Skip to content

Commit

Permalink
add ! validate image size
Browse files Browse the repository at this point in the history
  • Loading branch information
vitali-yanushchyk-valor committed Oct 25, 2024
1 parent 77e832e commit cfc6a78
Show file tree
Hide file tree
Showing 18 changed files with 39 additions and 31 deletions.
3 changes: 0 additions & 3 deletions src/hope_dedup_engine/apps/api/admin/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,3 @@ def has_add_permission(self, request):

def has_change_permission(self, request, obj=None):
return False

def has_delete_permission(self, request, obj=None):
return obj is not None
7 changes: 4 additions & 3 deletions src/hope_dedup_engine/apps/api/deduplication/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,11 @@ def find_duplicates(deduplication_set_id: str, serialized_lock: str) -> None:
deduplication_set.state = deduplication_set.State.CLEAN
deduplication_set.save()

if lock_enabled:
lock.release()

except Exception:
deduplication_set.state = DeduplicationSet.State.ERROR
deduplication_set.save()
raise

finally:
if lock_enabled:
lock.release()
9 changes: 9 additions & 0 deletions src/hope_dedup_engine/apps/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,12 @@ class DownloaderKeyError(Exception):
def __init__(self, key: str) -> None:
self.key = key
super().__init__(f"Downloader key '{key}' does not exist.")


class NotCompliantImageError(Exception):
"""
Exception raised when an image is not compliant with the expected parameters.
"""

def __init__(self, message: str) -> None:
super().__init__(message)
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,14 @@ def find_duplicates(self) -> Generator[tuple[str, str, float], None, None]:
min_distance = None
for encoding1 in encodings1:
distances = face_recognition.face_distance(encodings2, encoding1)
current_min = min(distances) if np.any(distances) else float("inf")
current_min = min(distances) if np.any(distances) else 0
if min_distance is None or current_min < min_distance:
min_distance = current_min

if min_distance is not None:
print(
f"Minimum distance between {path1} and {path2}: {min_distance}"
)

if min_distance < self.face_distance_threshold:
if (
min_distance is not None
and min_distance < self.face_distance_threshold
):
yield (path1, path2, round(min_distance, 5))

except Exception as e:
Expand Down
27 changes: 15 additions & 12 deletions src/hope_dedup_engine/apps/faces/services/image_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import numpy as np
from constance import config

from hope_dedup_engine.apps.core.exceptions import NotCompliantImageError
from hope_dedup_engine.apps.faces.managers import DNNInferenceManager, StorageManager


Expand Down Expand Up @@ -97,19 +98,19 @@ def _get_face_detections_dnn(
# Decode image from binary buffer to 3D numpy array (height, width, channels of BlueGreeRed color space)
image = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
(h, w) = image.shape[:2]
_h, _w = (
self.blob_from_image_cfg.shape["height"],
self.blob_from_image_cfg.shape["width"],
)
if h < _h or w < _w:
raise NotCompliantImageError(
f"Image {filename} too small: '{h}x{w}'. It needs to be at least '{_h}x{_w}'."
)

# Create a blob (4D tensor) from the image
blob = cv2.dnn.blobFromImage(
image=cv2.resize(
image,
dsize=(
self.blob_from_image_cfg.shape["height"],
self.blob_from_image_cfg.shape["width"],
),
),
size=(
self.blob_from_image_cfg.shape["height"],
self.blob_from_image_cfg.shape["width"],
),
image=cv2.resize(image, dsize=(_h, _w)),
size=(_h, _w),
scalefactor=self.blob_from_image_cfg.scale_factor,
mean=self.blob_from_image_cfg.mean_values,
)
Expand Down Expand Up @@ -161,7 +162,9 @@ def encode_face(self, filename: str, encodings_filename: str) -> None:
encodings: list[np.ndarray[np.float32, Any]] = []
face_regions = self._get_face_detections_dnn(filename)
if not face_regions:
self.logger.warning("No face regions detected in image %s", filename)
raise NotCompliantImageError(
f"No face regions detected in image '{filename}'."
)
else:

for region in face_regions:
Expand Down
2 changes: 1 addition & 1 deletion src/hope_dedup_engine/config/fragments/constance.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
int,
),
"FACE_ENCODINGS_MODEL": (
"small",
"large",
"""
Specifies the model type used for encoding face landmarks. It can be either 'small' which is faster and
detects only 5 key facial landmarks, or 'large' which is more precise and identifies 68 key facial landmarks
Expand Down
Binary file modified tests/extras/demoapp/demo_images/Aaron_Eckhart_0001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/Aaron_Guiel_0001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/Aaron_Peirsol_0001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/Aaron_Peirsol_0002.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/Cathy_Freeman_0001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/Cathy_Freeman_0002.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/Ziwang_Xu_0001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/Zoe_Ball_0001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/extras/demoapp/demo_images/too_small.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/extras/demoapp/demo_images/without_face.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests/faces/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def mock_image_processor(
@pytest.fixture
def image_bytes_io():
img_byte_arr = BytesIO()
image = Image.new("RGB", (100, 100), color="red")
image = Image.new("RGB", (300, 300), color="red")
image.save(img_byte_arr, format="JPEG")
img_byte_arr.seek(0)
img_byte_arr.fake_open = lambda *_: BytesIO(img_byte_arr.getvalue())
Expand Down
8 changes: 4 additions & 4 deletions tests/faces/faces_const.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
}
FACE_REGIONS_INVALID: Final[list[list[tuple[int, int, int, int]]]] = [[], [(0, 0, 10)]]
FACE_REGIONS_VALID: Final[list[tuple[int, int, int, int]]] = [
(10, 10, 20, 20),
(30, 30, 40, 40),
(40, 40, 80, 80),
(120, 120, 160, 160),
]
BLOB_FROM_IMAGE_SCALE_FACTOR: Final[float] = 1.0
BLOB_FROM_IMAGE_MEAN_VALUES: Final[tuple[float, float, float]] = (104.0, 177.0, 123.0)
Expand All @@ -56,8 +56,8 @@
(0, 0, 0.15, 0.1, 0.1, 0.2, 0.2), # with confidence 0.15 -> invalid detection
]
IMAGE_SIZE: Final[tuple[int, int, int]] = (
100,
100,
400,
400,
3,
) # Size of the image after decoding (h, w, number of channels)
RESIZED_IMAGE_SIZE: Final[tuple[int, int, int]] = (
Expand Down

0 comments on commit cfc6a78

Please sign in to comment.