def test_crop_resistance(self): full_image = self.peppers width, height = full_image.size crop_10 = full_image.crop( (0.05 * width, 0.05 * height, 0.95 * width, 0.95 * height)) crop_40 = full_image.crop( (0.2 * width, 0.2 * height, 0.8 * width, 0.8 * height)) crop_asymmetric = full_image.crop( (0, 0.3 * height, 0.4 * width, 0.75 * height)) full_hash = imagehash.crop_resistant_hash(full_image, min_segment_size=200) crop_hash_10 = imagehash.crop_resistant_hash(crop_10) crop_hash_40 = imagehash.crop_resistant_hash(crop_40) crop_hash_asymmetric = imagehash.crop_resistant_hash(crop_asymmetric) self.assertEqual( crop_hash_10, full_hash, "Slightly cropped image hash should match full image hash") self.assertEqual( crop_hash_40, full_hash, "Heavily cropped image hash should match full image hash") self.assertEqual( crop_hash_asymmetric, full_hash, "Asymmetrically cropped image hash should match full image hash")
def test_segmented_hash__hash_func(self): segmented_ahash = imagehash.crop_resistant_hash( self.image, imagehash.average_hash) segmented_dhash = imagehash.crop_resistant_hash( self.image, imagehash.dhash) self.assertFalse( segmented_ahash.matches(segmented_dhash), "Segmented hash should not match when the underlying hashing method is not the same" )
def test_segmented_hash__segment_threshold(self): segmented_low_threshold = imagehash.crop_resistant_hash( self.image, segment_threshold=20) segmented_high_threshold = imagehash.crop_resistant_hash( self.image, segment_threshold=250) self.assertFalse( segmented_low_threshold.matches(segmented_high_threshold, region_cutoff=3), "Segmented hash should not match when segment threshold is changed" )
def test_segmented_hash__limit_segments(self): segmented_orig = imagehash.crop_resistant_hash(self.image) segmented_limit = imagehash.crop_resistant_hash(self.image, limit_segments=1) self.assertGreaterEqual( len(segmented_orig.segment_hashes), len(segmented_limit.segment_hashes), "Limit segments should mean there are fewer segments") self.assertEqual( len(segmented_limit.segment_hashes), 1, "Limit segments should correctly limit the segment count")
def test_segmentation_image_size(self): start_time = datetime.now() imagehash.crop_resistant_hash(self.image, segmentation_image_size=200) small_timed = datetime.now() - start_time start_time = datetime.now() imagehash.crop_resistant_hash(self.image, segmentation_image_size=400) large_timed = datetime.now() - start_time self.assertGreater( large_timed, small_timed, "Hashing should take longer when the segmentation image is larger")
def test_min_segment_size(self): small_segments_hash = imagehash.crop_resistant_hash( self.peppers, min_segment_size=100) big_segments_hash = imagehash.crop_resistant_hash( self.peppers, min_segment_size=1000) self.assertGreater( len(small_segments_hash.segment_hashes), len(big_segments_hash.segment_hashes), "Small segment size limit should lead to larger number of segments detected." ) self.assertEqual( small_segments_hash, big_segments_hash, "Hashes should still match, as large segments are present in both")
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 hash_func(self, x): ''''Hash one image and return hash''' x = self.process_for_hash(x) if self.hash_name == "AverageHash": hash_value = imagehash.average_hash(x, hash_size=8, mean=np.mean) elif self.hash_name == "Phash": hash_value = imagehash.phash(x, hash_size=8, highfreq_factor=4) elif self.hash_name == "PhashSimple": hash_value = imagehash.phash_simple(x, hash_size=8, highfreq_factor=4) elif self.hash_name == "DhashH": hash_value = imagehash.dhash(x) elif self.hash_name == "DhashV": hash_value = imagehash.dhash_vertical(x) elif self.hash_name == "Whash": hash_value = imagehash.whash(x, hash_size=8, image_scale=None, mode='haar', remove_max_haar_ll=True) elif self.hash_name == "ColorHash": hash_value = imagehash.colorhash(x, binbits=3) elif self.hash_name == "CropResistantHash": # does not work yet hash_value = imagehash.crop_resistant_hash(x, hash_func=None, limit_segments=None, segment_threshold=128, min_segment_size=500, segmentation_image_size=300 ) else: raise NotImplementedError(f"Hash Name -- {self.hash_name} -- Unknown") return str(hash_value)
def test_segmented_hash(self): original_hash = imagehash.crop_resistant_hash(self.image) rotate_image = self.image.rotate(-1) small_rotate_hash = imagehash.crop_resistant_hash(rotate_image) emsg = ('slightly rotated image should have ' 'similar hash {} {}'.format(original_hash, small_rotate_hash)) self.assertTrue(original_hash.matches(small_rotate_hash), emsg) rotate_image = self.image.rotate(-90) large_rotate_hash = imagehash.crop_resistant_hash(rotate_image) emsg = ('rotated image should have different ' 'hash {} {}'.format(original_hash, large_rotate_hash)) self.assertFalse(original_hash.matches(large_rotate_hash), emsg) other_hashes = [small_rotate_hash, large_rotate_hash] self.assertEqual( original_hash.best_match(other_hashes), small_rotate_hash, "Hash of the slightly rotated image should be a better match than for the more heavily rotated image." )
def main(path): masks = list(csv.DictReader(open("masks.csv"))) im = Image.open(path) sample = imagehash.crop_resistant_hash(im, imagehash.phash) for mask in masks: mask["phash"] = imagehash.ImageMultiHash( [imagehash.hex_to_hash(mask["phash"])]) mask["diff"] = mask["phash"] - sample min_diff = min(masks, key=lambda mask: mask["diff"])["diff"] for mask in masks: if mask["diff"] == min_diff: index = (16384 - 10141 + int(mask["index"])) % 16384 print(f"https://www.thehashmasks.com/detail/{index}")
def get_crop_resistant_hash(image): return imagehash.crop_resistant_hash(image)
def get_hash(image_name): image = get_image(image_name) return imagehash.crop_resistant_hash(image)
import imagehash from PIL import Image SAVE_IMAGES = False # Load image full_image = Image.open("../tests/data/peppers.png") width, height = full_image.size # Hash it full_hash = imagehash.crop_resistant_hash(full_image) # Crop it for x in range(5, 50, 5): start = x / 100 end = 1 - start crop_img = full_image.crop( (start * width, start * height, end * width, end * height)) crop_hash = imagehash.crop_resistant_hash(crop_img) if SAVE_IMAGES: crop_img.save("crop_{}.png".format(str(x).zfill(2))) crop_diff = full_hash.hash_diff(crop_hash) print( "Cropped {}% from each side. Hash has {} matching segments with {} total hamming distance" .format(x, crop_diff[0], crop_diff[1]))