7f55f360a3
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
65 lines
2.1 KiB
Python
65 lines
2.1 KiB
Python
import io
|
|
|
|
import imagehash
|
|
from PIL import Image
|
|
|
|
from backend.app.utils.phash import compute_phash, find_similar
|
|
|
|
|
|
def _img(color, size=(64, 64)):
|
|
return Image.new("RGB", size, color)
|
|
|
|
|
|
def _split(orient, size=64):
|
|
"""A structured image (half black / half white) so it has real DCT
|
|
content — solid colors all phash-collapse to the same value."""
|
|
im = Image.new("L", (size, size), 0)
|
|
px = im.load()
|
|
for y in range(size):
|
|
for x in range(size):
|
|
if (x if orient == "v" else y) >= size // 2:
|
|
px[x, y] = 255
|
|
return im.convert("RGB")
|
|
|
|
|
|
def test_compute_phash_stable_and_hex():
|
|
h1 = compute_phash(_img((10, 120, 200)))
|
|
h2 = compute_phash(_img((10, 120, 200)))
|
|
assert isinstance(h1, str) and len(h1) == 16 # hash_size=8 -> 64-bit -> 16 hex
|
|
assert h1 == h2
|
|
|
|
|
|
def test_compute_phash_none_for_non_image():
|
|
assert compute_phash(io.BytesIO(b"not an image")) is None
|
|
|
|
|
|
def test_find_similar_none_when_far():
|
|
# Vertical vs horizontal split = structurally orthogonal → far apart.
|
|
new = compute_phash(_split("v"))
|
|
cand = (compute_phash(_split("h")), 100, 100, 7)
|
|
rel, mid = find_similar(new, 50, 50, [cand], threshold=2)
|
|
assert rel == "none" and mid is None
|
|
|
|
|
|
def test_find_similar_larger_exists_skips_new():
|
|
h = compute_phash(_img((123, 50, 7)))
|
|
rel, mid = find_similar(h, 100, 100, [(h, 400, 400, 9)], threshold=2)
|
|
assert rel == "larger_exists" and mid == 9
|
|
|
|
|
|
def test_find_similar_smaller_exists_supersede():
|
|
h = compute_phash(_img((123, 50, 7)))
|
|
rel, mid = find_similar(h, 800, 800, [(h, 100, 100, 4)], threshold=2)
|
|
assert rel == "smaller_exists" and mid == 4
|
|
|
|
|
|
def test_find_similar_threshold_boundary_inclusive_and_first_match():
|
|
h = compute_phash(_img((10, 10, 10)))
|
|
far = compute_phash(_img((240, 240, 240)))
|
|
d = imagehash.hex_to_hash(h) - imagehash.hex_to_hash(far)
|
|
# at exactly the distance, it counts as similar (<=)
|
|
rel, _ = find_similar(h, 10, 10, [(far, 999, 999, 1)], threshold=d)
|
|
assert rel == "larger_exists"
|
|
rel2, _ = find_similar(h, 10, 10, [(far, 999, 999, 1)], threshold=d - 1)
|
|
assert rel2 == "none"
|