Image Fingerprinting with Perceptual Hashes (pHash)
Developer reference — updated October 2026. Based on Nadav Soferman's 19 February 2015 Cloudinary article, How to automatically identify similar images using pHash. This is a technical summary and update, not a reproduction of the original article.
1. The problem
The same underlying photograph can be uploaded or stored in several variants: resized, converted from JPEG to PNG or WebP, recompressed, made greyscale, recoloured, cropped or otherwise edited. Their file bytes may be completely different, even though a person recognises them as essentially the same picture.
Image fingerprinting helps applications find these near-duplicates, organise uploaded content and avoid showing multiple versions of essentially the same image. A travel site, for example, may want to select diverse photographs of a hotel room rather than display several slightly edited copies.
2. Exact hashes versus perceptual hashes
- Cryptographic/file hash (SHA-256, for example): identifies identical file bytes. Changing metadata, compression or a pixel will generally change the hash. Good for exact duplicate detection, not visual similarity.
- Perceptual hash (pHash): reduces the visual properties of an image to a compact fingerprint. Similar-looking images often have similar fingerprints, despite certain edits or file-format changes.
The original article uses a 64-bit fingerprint, conventionally written as 16 hexadecimal digits. A pHash is not an image checksum, proof of ownership, cryptographic signature or unique image identifier.
3. How pHash works
A common pHash implementation normalises an image (for example, resizing and converting to greyscale), applies a discrete cosine transform (DCT) and converts selected low-frequency coefficients into a binary fingerprint. This captures broad image structure rather than individual encoded file bytes.
Implementation detail: pHash is a family of related algorithms, not one universally interchangeable 64-bit format. Image normalisation, DCT selection, thresholding and bit ordering affect the result. Store the algorithm and version alongside the fingerprint, and compare values produced by compatible implementations.
4. Comparing fingerprints: Hamming distance
To compare two equal-length binary fingerprints, XOR their bits and count the set bits (the population count). This is their Hamming distance:
distance = popcount(hashA XOR hashB)
For 64-bit fingerprints, the result ranges from 0 to 64. Zero means identical fingerprints, not necessarily identical images. In a compatible pHash scheme, smaller distances generally indicate greater visual resemblance.
The original article expresses similarity as:
similarity = 1.0 - (distance / 64.0)
This converts distance into a convenient score between 0 and 1, although unrelated hashes typically score around 0.5 rather than zero. The score is not a calibrated probability that two pictures are the same. For troubleshooting and thresholding, the raw bit distance is often clearer.
5. Worked examples from the original article
The 2015 Cloudinary example used a koala photograph with fingerprint ba19c8ab5fa05a59. Other versions were compared against this original:
| Comparison | pHash | Distance / 64 | Original similarity score |
|---|---|---|---|
| Original koala | ba19c8ab5fa05a59 | 0 | 1.00000 |
| Greyscale version | ba19caab5f205a59 | 2 | 0.96875 |
| Cropped, increased saturation | ba3dcfabbc004a49 | 14 | 0.78125 |
| Cropped, more JPEG compression | 1b39ccea7d304a59 | 12 | 0.81250 |
| Different koala photograph | 3d419c23c42eb3db | 28 | 0.56250 |
| Different subject | f10773f1cd269246 | 32 | 0.50000 |
These figures illustrate the intended distinction: edits to the same photo scored more similarly than two different photographs. They are examples, not universal cut-offs.
6. What pHash handles well — and what it does not
- Often robust: ordinary resizing, format conversion, moderate JPEG recompression, small colour or brightness changes and greyscale conversion.
- Less reliable: heavy crops, rotations, reflections, large overlays, altered aspect ratios, major perspective changes and substantial image modifications. The result depends on the implementation and source images.
- False matches: different photos with similar broad composition, simple backgrounds or repeated graphical layouts can have close fingerprints.
- Missed matches: two pictures a person considers equivalent may have substantially different hashes after a strong edit.
Perceptual similarity is not semantic similarity. A conventional pHash does not generally recognise that two different photographs both depict a koala, nor does it establish that an edited photo contains the same object.
7. Practical de-duplication workflow
- Validate the upload. Decode the image safely and enforce file-size, dimensions and resource limits.
- Check exact duplicates first. Calculate a SHA-256 hash of the file bytes; optionally calculate a separate canonicalised-pixel hash if exact visual pixels matter.
- Calculate a perceptual fingerprint. Use a consistent, documented algorithm and image-normalisation process.
- Store metadata. Keep image ID, fingerprint, algorithm/version, dimensions, source and any other useful identifiers.
- Search candidate fingerprints. Calculate Hamming distances and return plausible nearest matches.
- Review before action. Use a distance threshold calibrated against representative images, then inspect thumbnails or ask a user to choose. Do not silently delete based on a pHash score alone.
- Apply the product decision. Flag potential duplicates, group variants, suppress repeated gallery entries or retain everything but link related assets.
For a small image collection, comparing each new hash with stored values may be sufficient. For large collections, use a suitable indexed nearest-neighbour search, prefilters or bit-distance search strategy; exhaustive comparisons become expensive as the collection grows.
8. Implementation notes
64-bit storage and bit counting
Represent a 64-bit pHash as an unsigned 64-bit value or a fixed-width, 16-character hexadecimal string. Do not accidentally treat the most significant bit as a sign bit, drop leading zeros or compare hexadecimal text lexically as though it measured similarity.
// Algorithm-neutral pseudocode
function HammingDistance(hashA, hashB): Integer
x = hashA XOR hashB
return PopCount(x)
end
For a Delphi/Windows application, UInt64 is a convenient in-memory type. The XOR/popcount calculation can be implemented with a small bit-count routine or an appropriate platform intrinsic; the hash-generation algorithm itself is a separate concern.
Choosing a matching threshold
There is no safe universal rule such as “distance below 10 means duplicate”. Sample genuine variants and unrelated images from your own collection, examine the false-positive/false-negative trade-off, and set a conservative candidate threshold. Treat near matches as recommendations or review items.
When another technique is better
- aHash/dHash: simpler perceptual fingerprints with different sensitivity and speed trade-offs.
- Crop-resistant or local-feature matching: can be more suitable when substantial cropping or repositioning is common.
- Image embeddings: more appropriate for searches based on subject or meaning, such as different photos of the same kind of object. They are not direct substitutes for exact duplicate detection.
9. Cloudinary: original approach and current status
The source article used Cloudinary's upload API with phash: true to return a perceptual fingerprint in the upload response. Cloudinary's documentation still describes this parameter in 2026. An example fingerprint returned by the source article was ba19c8ab5fa05a59.
Cloudinary also documents that its image-normalisation process can produce a different value from a third-party pHash library; do not assume fingerprints are cross-provider compatible. The original article's free-tier availability and roadmap claims were statements made in 2015 and should not be treated as current pricing or feature guarantees.
You do not need Cloudinary to implement this technique: pHash calculation and comparison can be performed locally or on your own server.
10. Takeaway
Use exact hashes to find identical bytes; use perceptual hashes to find visually similar candidates. Compare compatible fingerprints using Hamming distance, test thresholds against real data and make the final duplicate decision with additional evidence when mistakes would matter.
Sources and further reading
- Nadav Soferman, “How-to automatically identify similar images using pHash” (Cloudinary, 19 February 2015; archived copy) — source article and koala examples.
- Cloudinary: Semantic data extraction — current pHash behaviour and implementation caveats.
- Cloudinary: Upload API reference —
phashupload parameter. - Beyond Hamming Distance: Exploring spatial encoding in perceptual hashes (2025) — research into limitations of simple bit-distance comparison.