dupfind

How a computer sees two photos as one

sheet 01 · 12 jul 2026

Take a photo off your camera: 4MB, 4000 pixels wide. Send it to yourself on WhatsApp and save the result: 180KB, 1600 pixels wide, visibly softer if you squint. To you, obviously the same photograph. To a computer comparing the files, they have nothing whatsoever in common — not one byte in the same place, different dimensions, different compression, different everything. Any tool that finds duplicates by comparing file contents (which is how the honest, simple ones work) will swear these are unrelated images.

Solving that is the whole art, and it has a name: perceptual hashing. Instead of fingerprinting the bytes, you fingerprint what the photo looks like.

step one: destroy the detail on purpose

The first move feels wrong: throw almost everything away. Shrink the image to a tiny thumbnail — a few dozen pixels across — and convert it to grayscale. Colour, sharpness, resolution, compression artefacts: gone. What survives is the coarse structure, the arrangement of light and dark that makes the picture recognisable from across a room. And here's the point: the 4MB original and the mangled WhatsApp copy shrink to nearly identical thumbnails, because everything that differed between them was fine detail, and fine detail is what we just deleted.

step two: describe it in 64 bits

The gradient hash (dHash) is beautifully simple: walk the tiny image pixel by pixel and ask one question — is this pixel brighter than the one to its right? Yes writes a 1, no writes a 0. Sixty-four comparisons, sixty-four bits. Notice what this measures: not brightness, but the direction brightness changes. Make the whole photo lighter and every comparison gives the same answer; the fingerprint doesn't move.

The structural hash (pHash) takes a mathematical route to the same idea. It runs a discrete cosine transform — the same maths inside JPEG compression itself — which sorts the image into frequencies: coarse shapes in one corner, fine texture everywhere else. Keep only the coarse corner, throw away the rest, and record which values sit above the median. Also 64 bits, also blind to the details that copies mangle.

step three: count the disagreements

Two fingerprints, compared bit by bit. The number of positions where they differ is the Hamming distance: 0 means the pictures look identical; 3 or 4 means the same photo re-saved; 30 means two unrelated images. The table requires both hashes to agree closely before calling something a duplicate — the gradient hash is easily impressed by similar compositions, the structural hash forgives a bit too much, and demanding both keeps false matches genuinely rare.

the honest failure modes

Perceptual hashing is a judgement about appearance, so it fails exactly where appearance misleads. Two photos of the same wall taken seconds apart are, structurally, the same photo — which is why the "loose" setting is labelled as needing review rather than trust. Heavy crops change the composition enough to break the match, so a cropped copy may not be found. And a photo that's been rotated is, to these hashes, a completely different image. None of this is fixable by better thresholds; it's the shape of the idea, and the honest move is to say so, put you in front of the thumbnails, and let the human do the last, irreplaceable step.