Skip to content

Quick start

pip install python-libphash

The wheel carries the C library and its decoders: nothing else is installed or needed.

Hash an image and compare

import libphash as ph

a = ph.hash("photo.jpg")                   # pHash, a 64-bit int
b = ph.hash("photo_copy.jpg")
ph.hamming_distance(a, b)                  # 0..64 bits differ
ph.similarity(a, b)                        # 1.0 for equal hashes, ~0.5 unrelated
print(ph.hash_to_hex(a))                   # 16 hex digits, for storage

A distance of a few bits means the same picture; how many is "a few" depends on the algorithm and on the edits your copies go through: Comparing hashes on libphash's site explains how to choose the threshold, and examples/threshold.py measures it on pairs you label.

Choose an algorithm

ph.hash() computes pHash unless told otherwise. Each algorithm is a member of Algorithm, and its libphash name works too:

from libphash import Algorithm

d = ph.hash("photo.jpg", Algorithm.DHASH)  # an int
r = ph.hash("photo.jpg", "radial")         # a Digest
r.similarity(ph.hash("photo_rotated.jpg", "radial"))
Algorithm Result Compare with
AHASH, DHASH, PHASH, WHASH 64-bit int hamming_distance(), similarity()
BMH, MHASH Digest of bits Digest.hamming_distance(), Digest.similarity()
RADIAL Digest of coefficients Digest.similarity() (peak correlation)
COLOR_HASH Digest, a histogram Digest.similarity() (histogram intersection)
COLOR_MOMENTS Digest, 16-bit features Digest.l2_distance()

A digest refuses a comparison that does not fit its kind with DigestKindError, rather than return a number that means nothing. Which algorithm suits which use is measured on libphash's Choosing an algorithm.

Several hashes of one image, many images

with ph.ImageContext() as ctx:
    ctx.load_file("photo.jpg")
    hashes = ctx.hashes(Algorithm.PHASH, Algorithm.DHASH, Algorithm.MHASH)
    print(ctx.width, ctx.height, hashes[Algorithm.PHASH])

results = ph.hash_files(["photo.jpg", "photo_copy.jpg", "missing.jpg"])
for r in results:
    print(r.source, r.hashes if r.ok else r.error)

A context decodes the image once for all its hashes, and keeps its buffers from one image to the next; hash_files() hashes a list of files on all CPUs, and a file that fails does not stop the others. Hashing many images has the details.

Next