Spaces:
Running on Zero
Running on Zero
File size: 7,243 Bytes
819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 db79f31 819c9a2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | import base64
import sys
from io import BytesIO
from unittest.mock import MagicMock
import numpy as np
import pytest
from PIL import Image
sys.path.insert(0, ".")
from image_utils import (
_b64_to_pil,
_pil_to_cv2,
_cv2_to_pil,
_crop_face_thumb,
_pil_thumb_to_b64,
_sort_faces_left_to_right,
_face_to_dict,
_collect_source_pils,
)
# ββ Shared fixtures ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
@pytest.fixture
def small_rgb_pil():
return Image.new("RGB", (4, 4), color=(255, 0, 0))
@pytest.fixture
def small_rgb_b64(small_rgb_pil):
buf = BytesIO()
small_rgb_pil.save(buf, format="JPEG")
raw = base64.b64encode(buf.getvalue()).decode()
return f"data:image/jpeg;base64,{raw}"
@pytest.fixture
def small_cv2_bgr():
return np.zeros((4, 4, 3), dtype=np.uint8)
@pytest.fixture
def large_rgb_pil():
return Image.new("RGB", (200, 200), color=(255, 0, 0))
@pytest.fixture
def fake_face():
face = MagicMock()
face.bbox = [40.0, 40.0, 120.0, 120.0]
face.det_score = 0.987654
return face
# ββ _b64_to_pil βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestB64ToPil:
def test_with_data_header(self, small_rgb_b64):
pil = _b64_to_pil(small_rgb_b64)
assert isinstance(pil, Image.Image)
assert pil.mode == "RGB"
def test_without_data_header(self, small_rgb_pil):
buf = BytesIO()
small_rgb_pil.save(buf, format="JPEG")
raw = base64.b64encode(buf.getvalue()).decode()
pil = _b64_to_pil(raw)
assert isinstance(pil, Image.Image)
def test_invalid_raises(self):
with pytest.raises(Exception):
_b64_to_pil("data:image/jpeg;base64,not_valid_base64!!")
# ββ _pil_to_cv2 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestPilToCv2:
def test_returns_numpy_array(self, small_rgb_pil):
arr = _pil_to_cv2(small_rgb_pil)
assert isinstance(arr, np.ndarray)
def test_shape_preserved(self, small_rgb_pil):
arr = _pil_to_cv2(small_rgb_pil)
assert arr.shape == (small_rgb_pil.height, small_rgb_pil.width, 3)
def test_channel_order_is_bgr(self, small_rgb_pil):
arr = _pil_to_cv2(small_rgb_pil)
assert arr[0, 0, 2] == 255 # R in BGR
assert arr[0, 0, 0] == 0 # B in BGR
# ββ _cv2_to_pil βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestCv2ToPil:
def test_returns_pil_image(self, small_cv2_bgr):
assert isinstance(_cv2_to_pil(small_cv2_bgr), Image.Image)
def test_mode_is_rgb(self, small_cv2_bgr):
assert _cv2_to_pil(small_cv2_bgr).mode == "RGB"
def test_roundtrip(self, small_rgb_pil):
back = _cv2_to_pil(_pil_to_cv2(small_rgb_pil))
assert back.size == small_rgb_pil.size
# ββ _crop_face_thumb ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestCropFaceThumb:
def test_output_is_given_size(self, small_rgb_pil):
assert _crop_face_thumb(small_rgb_pil, [1, 1, 3, 3], size=64).size == (64, 64)
def test_bbox_near_edge_clamped(self):
img = Image.new("RGB", (20, 20), color=(128, 128, 128))
assert _crop_face_thumb(img, [0, 0, 5, 5], size=32).size == (32, 32)
def test_bbox_near_right_edge_clamped(self):
img = Image.new("RGB", (20, 20))
assert _crop_face_thumb(img, [15, 15, 20, 20], size=32).size == (32, 32)
# ββ _pil_thumb_to_b64 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestPilThumbToB64:
def test_has_data_header(self, small_rgb_pil):
assert _pil_thumb_to_b64(small_rgb_pil).startswith("data:image/jpeg;base64,")
def test_is_decodable_base64(self, small_rgb_pil):
_, encoded = _pil_thumb_to_b64(small_rgb_pil).split(",", 1)
assert base64.b64decode(encoded)[:2] == b"\xff\xd8" # JPEG magic bytes
# ββ _sort_faces_left_to_right βββββββββββββββββββββββββββββββββββββββββββββββββ
class TestSortFaces:
def _make_face(self, x1):
f = MagicMock()
f.bbox = [float(x1), 0.0, float(x1 + 10), 10.0]
return f
def test_sorted_ascending(self):
faces = [self._make_face(50), self._make_face(10), self._make_face(30)]
result = _sort_faces_left_to_right(faces)
assert [f.bbox[0] for f in result] == sorted(f.bbox[0] for f in faces)
def test_empty_list(self):
assert _sort_faces_left_to_right([]) == []
def test_single_face(self):
face = self._make_face(5)
assert _sort_faces_left_to_right([face]) == [face]
# ββ _face_to_dict βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestFaceToDict:
def test_has_required_keys(self, large_rgb_pil, fake_face):
assert {"idx", "thumbnail", "bbox", "det_score"} <= _face_to_dict(
0, fake_face, large_rgb_pil
).keys()
def test_idx_matches(self, large_rgb_pil, fake_face):
assert _face_to_dict(3, fake_face, large_rgb_pil)["idx"] == 3
def test_bbox_is_list_of_ints(self, large_rgb_pil, fake_face):
bbox = _face_to_dict(0, fake_face, large_rgb_pil)["bbox"]
assert isinstance(bbox, list)
assert all(isinstance(v, int) for v in bbox)
def test_det_score_rounded_to_3dp(self, large_rgb_pil, fake_face):
assert _face_to_dict(0, fake_face, large_rgb_pil)["det_score"] == round(
fake_face.det_score, 3
)
def test_thumbnail_has_header(self, large_rgb_pil, fake_face):
assert _face_to_dict(0, fake_face, large_rgb_pil)["thumbnail"].startswith(
"data:image/jpeg;base64,"
)
# ββ _collect_source_pils ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestCollectSourcePils:
def test_returns_pil_list(self, small_rgb_b64):
result = _collect_source_pils([0, 1], {"0": small_rgb_b64, "1": small_rgb_b64})
assert len(result) == 2
assert all(isinstance(p, Image.Image) for p in result)
def test_skips_missing_indices(self, small_rgb_b64):
result = _collect_source_pils([0, 1], {"0": small_rgb_b64})
assert len(result) == 1
|