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
|
import hashlib
import numpy
import PIL
from packaging import version
from PIL import ImageFilter
import imagehash
from tests import TestImageHash
def _calculate_segment_properties(segment):
length = len(segment)
min_y = min(coord[0] for coord in segment)
min_x = min(coord[1] for coord in segment)
max_y = max(coord[0] for coord in segment)
max_x = max(coord[1] for coord in segment)
return {
'length': length,
'min_x': min_x,
'min_y': min_y,
'max_x': max_x,
'max_y': max_y
}
def _pillow_has_convert_fix():
"""
Pillow version 7.0.0 introduced a fix for a rounding error in Image.convert("L") which means that segmentation is
slightly different after this release.
The PR which fixed the rounding and caused this inconsistency is https://github.com/python-pillow/Pillow/pull/4320
"""
return version.parse(PIL.__version__) >= version.parse('7.0.0')
class Test(TestImageHash):
def setUp(self):
self.image = self.get_data_image()
self.peppers = self.get_data_image('peppers.png')
def test_average_hash(self):
result_hash = imagehash.average_hash(self.image)
known_hash = 'ffd7918181c9ffff'
self.assertEqual(str(result_hash), known_hash)
def test_phash(self):
result_hash = imagehash.phash(self.image)
known_hash = 'ba8c84536bd3c366'
self.assertEqual(str(result_hash), known_hash)
def test_dhash(self):
result_hash = imagehash.dhash(self.image)
known_hash = '0026273b2b19550e'
self.assertEqual(str(result_hash), known_hash)
def test_whash(self):
result_hash = imagehash.whash(self.image)
known_hash = 'ffd391818181a5e7'
self.assertEqual(str(result_hash), known_hash)
def test_color_hash(self):
result_hash = imagehash.colorhash(self.image)
known_hash = '07007000000'
self.assertEqual(str(result_hash), known_hash)
def test_crop_resistant_hash(self):
result_hash = imagehash.crop_resistant_hash(self.peppers)
if _pillow_has_convert_fix():
known_hash = (
'c4d9f3e3e1c18101,'
'706c6e66464c99b9,'
'98d8f1ecd8f0f0e1,'
'a082c0c49acc6dbd,'
'f1f39b99c1c1b1b1,'
'3a7ece1c9df4fcb9'
)
else:
known_hash = (
'c4d9f1e3e1c18101,'
'706c6e66464c99b9,'
'98d8f1ecd8f0f0e1,'
'a282c0c49acc6dbd,'
'b1f39b99e1c1b1b1,'
'3a7ece1c9df4fcb9'
)
self.assertEqual(str(result_hash), known_hash)
def test_crop_resistant_segmentation(self):
# Image pre-processing
image = self.peppers.convert('L')
if _pillow_has_convert_fix():
known_bw_md5 = '61db06218cc8b9aba14812d965869120'
else:
known_bw_md5 = '61442e74c83cfea67d182481c24c5f3e'
self.assertEqual(
hashlib.md5(image.tobytes()).hexdigest(),
known_bw_md5,
"This hash should match, unless pillow have changed Convert('L') again"
)
image = image.resize((300, 300), imagehash.ANTIALIAS)
# Add filters
image = image.filter(ImageFilter.GaussianBlur()).filter(ImageFilter.MedianFilter())
pixels = numpy.array(image).astype(numpy.float32)
# Segment
segments = imagehash._find_all_segments(pixels, 128, 500)
known_segment_count = 6
self.assertEqual(len(segments), known_segment_count)
if _pillow_has_convert_fix():
known_segments = sorted([
{'length': 595, 'min_x': 20, 'min_y': 0, 'max_x': 60, 'max_y': 31},
{'length': 1458, 'min_x': 61, 'min_y': 0, 'max_x': 156, 'max_y': 58},
{'length': 3505, 'min_x': 0, 'min_y': 111, 'max_x': 97, 'max_y': 191},
{'length': 8789, 'min_x': 112, 'min_y': 145, 'max_x': 299, 'max_y': 260},
{'length': 12153, 'min_x': 157, 'min_y': 0, 'max_x': 299, 'max_y': 148},
{'length': 60916, 'min_x': 0, 'min_y': 0, 'max_x': 299, 'max_y': 299}
], key=lambda x: (x['length'], x['min_x'], x['min_y'], x['max_x'], x['max_y']))
else:
known_segments = sorted([
{'length': 591, 'min_x': 20, 'min_y': 0, 'max_x': 60, 'max_y': 31},
{'length': 1451, 'min_x': 61, 'min_y': 0, 'max_x': 156, 'max_y': 58},
{'length': 12040, 'min_x': 157, 'min_y': 0, 'max_x': 299, 'max_y': 147},
{'length': 3452, 'min_x': 0, 'min_y': 111, 'max_x': 97, 'max_y': 191},
{'length': 8701, 'min_x': 112, 'min_y': 145, 'max_x': 299, 'max_y': 259},
{'length': 61179, 'min_x': 0, 'min_y': 0, 'max_x': 299, 'max_y': 299}
], key=lambda x: (x['length'], x['min_x'], x['min_y'], x['max_x'], x['max_y']))
segment_properties = sorted([
_calculate_segment_properties(segment) for segment in segments
], key=lambda x: (x['length'], x['min_x'], x['min_y'], x['max_x'], x['max_y']))
self.assertEqual(segment_properties, known_segments)
|