diff --git a/.gitignore b/.gitignore index 44ead8c..18c54e1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,12 @@ __pycache__/ *.py[cod] *$py.class +# Backups +*.bak + +# Test images +test_images + # C extensions *.so diff --git a/compare.py b/compare.py new file mode 100644 index 0000000..43ac766 --- /dev/null +++ b/compare.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" basic image compare """ + +import sys + +# Custom libphash bindings +import pyphash as phash + +# Helpers +def hamming_distance(string1, string2): + return sum(map(str.__ne__, string1, string2)) + +def get_image_hashes(imagename): + base_image_path = imagename + base_phash_digest = phash.image_digest(base_image_path) + base_phash_imagehash = phash.imagehash(base_image_path) + return (base_phash_digest, base_phash_imagehash) + +def test_image_correlations(image1, image2): + hashes1 = get_image_hashes(image1) + hashes2 = get_image_hashes(image2) + + print("{} pHash digest: {} and DCT: {}".format(image1, hashes1[0], hashes1[1])) + print("{} pHash digest: {} and DCT: {}".format(image2, hashes2[0], hashes2[1])) + + print("Cross-correlation: %5.2f%%" % ( + 100 * phash.cross_correlation(hashes1[0], hashes2[0]) + )) + +if __name__ == "__main__": + if len(sys.argv) < 3: + print("Please specify two images on the command-line") + sys.exit(1) + image1 = sys.argv[1] + image2 = sys.argv[2] + test_image_correlations(image1, image2) \ No newline at end of file diff --git a/generate_images.sh b/generate_images.sh index 4794793..74d61ed 100755 --- a/generate_images.sh +++ b/generate_images.sh @@ -4,22 +4,24 @@ set -eux mkdir -p test_images +SAMPLE_NAME=sample-city-park-400x300.jpg + cd test_images -wget http://s3.amazonaws.com/i.jpg.to/l/8453 -O tony.jpg +wget https://download.samplelib.com/jpeg/$SAMPLE_NAME -convert tony.jpg tony.png +convert $SAMPLE_NAME sample.png # Scaled -convert tony.png -resize 50% tony-scaled-50.png -convert tony.png -resize 75% tony-scaled-75.png -convert tony.png -resize 150% tony-scaled-150.png +convert sample.png -resize 50% sample-scaled-50.png +convert sample.png -resize 75% sample-scaled-75.png +convert sample.png -resize 150% sample-scaled-150.png # Blurs -convert tony.png -blur 2x2 tony-blur-2x2.png -convert tony.png -blur 5x2 tony-blur-5x2.png -convert tony.png -blur 0x4 tony-blur-0x4.png +convert sample.png -blur 2x2 sample-blur-2x2.png +convert sample.png -blur 5x2 sample-blur-5x2.png +convert sample.png -blur 0x4 sample-blur-0x4.png # Rotations -for i in $(seq 1 360); do - convert tony.png -rotate $i "tony-rotate-$i.png" +for i in $(seq 1 90); do + convert sample.png -rotate $i "sample-rotate-$i.png" done diff --git a/python_phash/__init__.py b/pyphash/__init__.py similarity index 100% rename from python_phash/__init__.py rename to pyphash/__init__.py diff --git a/python_phash/core.py b/pyphash/core.py similarity index 100% rename from python_phash/core.py rename to pyphash/core.py diff --git a/python_phash/exceptions.py b/pyphash/exceptions.py similarity index 100% rename from python_phash/exceptions.py rename to pyphash/exceptions.py diff --git a/python_phash/extensions.py b/pyphash/extensions.py similarity index 100% rename from python_phash/extensions.py rename to pyphash/extensions.py diff --git a/python_phash/helpers.py b/pyphash/helpers.py similarity index 100% rename from python_phash/helpers.py rename to pyphash/helpers.py diff --git a/python_phash/structs.py b/pyphash/structs.py similarity index 100% rename from python_phash/structs.py rename to pyphash/structs.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..91073b4 --- /dev/null +++ b/setup.py @@ -0,0 +1,13 @@ +# setup.py contributed by Faisal Puthuparackat + +from setuptools import setup + +setup(name='pyphash', + version='0.1', + description='A python ctypes wrapper for the pHash library', + url='https://github.com/paulkiernan/pyphash', + author='Paul Kiernan', + author_email='hi@paulynomial.com', + license='GPLv3', + packages=['pyphash'], + zip_safe=False) diff --git a/test_hashing.py b/test_hashing.py index b573efc..93a353b 100755 --- a/test_hashing.py +++ b/test_hashing.py @@ -4,74 +4,48 @@ """ phashlib Core C++ interface """ -# Future-proof -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -# Standard Library Imports -from hashlib import md5 -from itertools import imap - -# Third-party Libraries -import matplotlib.pyplot as plt -from IPython.display import Image, display - # Custom libphash bindings -import python_phash as phash +import pyphash as phash print(phash) print(dir(phash)) TEST_IMAGES = { - 'base': 'test_images/tony.png', + 'base': 'test_images/sample.png', 'blurs': { - '2x2': 'test_images/tony-blur-2x2.png', - '5x2': 'test_images/tony-blur-5x2.png', - '0x4': 'test_images/tony-blur-0x4.png', + '2x2': 'test_images/sample-blur-2x2.png', + '5x2': 'test_images/sample-blur-5x2.png', + '0x4': 'test_images/sample-blur-0x4.png', }, 'rotations': { - '10°': 'test_images/tony-rotate-10.png', - '30°': 'test_images/tony-rotate-30.png', - '90°': 'test_images/tony-rotate-90.png', - '180°': 'test_images/tony-rotate-180.png', + '10°': 'test_images/sample-rotate-10.png', + '30°': 'test_images/sample-rotate-30.png', + '70°': 'test_images/sample-rotate-70.png', + '90°': 'test_images/sample-rotate-90.png', }, 'scaled': { - '50%': 'test_images/tony-scaled-50.png', - '75%': 'test_images/tony-scaled-75.png', - '150%': 'test_images/tony-scaled-150.png', + '50%': 'test_images/sample-scaled-50.png', + '75%': 'test_images/sample-scaled-75.png', + '150%': 'test_images/sample-scaled-150.png', } } # Helpers def hamming_distance(string1, string2): - return sum(imap(str.__ne__, string1, string2)) + return sum(map(str.__ne__, string1, string2)) -def test_image_correlations(image_distortion_type, is_ipython_notebook=False): - +def test_image_correlations(image_distortion_type): base_image_path = TEST_IMAGES.get('base') - base_image = Image(filename=base_image_path) base_phash_digest = phash.image_digest(base_image_path) base_phash_imagehash = phash.imagehash(base_image_path) - base_md5_digest = md5(open(base_image_path).read()).hexdigest() - if is_ipython_notebook: - display(base_image) - print("md5 Digest: {0}".format(base_md5_digest)) print("pHash Digest: {0}".format(base_phash_digest)) print("pHash DCT Hash: {0}".format(base_phash_imagehash)) - for distortion_info, image_path in TEST_IMAGES.get(image_distortion_type).iteritems(): - _image = Image(filename=image_path) - if is_ipython_notebook: - display(_image) + for distortion_info, image_path in TEST_IMAGES.get(image_distortion_type).items(): _image_phash_digest = phash.image_digest(image_path) _image_phash_imagehash = phash.imagehash(image_path) - _image_md5_digest = md5(open(image_path).read()).hexdigest() - print("md5 Digest: {0}".format(_image_md5_digest)) - print("md5 Hamming Distance: {0}".format(hamming_distance(base_md5_digest, _image_md5_digest))) print("pHash Digest: {0}".format(_image_phash_digest)) print("pHash DCT Hash: {0}".format(_image_phash_imagehash)) print("pHash DCT Hash Hamming Distance: {0}".format( @@ -88,25 +62,21 @@ def test_image_correlations(image_distortion_type, is_ipython_notebook=False): def test_rotations(): - base_image_path = TEST_IMAGES.get('base') base_phash_digest = phash.image_digest(base_image_path) correlations = [] - for x in xrange(1, 361): - _image_path = "test_images/tony-rotate-{0}.png".format(x) + for x in range(1, 90): + _image_path = "test_images/sample-rotate-{0}.png".format(x) _image_phash_digest = phash.image_digest(_image_path) correlations.append(( x, phash.cross_correlation(base_phash_digest, _image_phash_digest) )) - return zip(*correlations) + return list(zip(*correlations)) -test_image_correlations('scaled', is_ipython_notebook=False) -test_image_correlations('blurs', is_ipython_notebook=False) -test_image_correlations('rotations', is_ipython_notebook=False) -xx, yy = test_rotations() -plt.plot(xx, yy) -plt.plot(xx[:10], yy[:10]) -plt.plot(xx[-10:], yy[-10:]) +if __name__ == "__main__": + test_image_correlations('scaled') + test_image_correlations('blurs') + test_image_correlations('rotations')