Projects > Image Matcher
Image Matcher: Match ~27K stripped social media images to ~609K source files using rotation-aware perceptual hashing and a 2.4M-row hash index.

Image Matcher

Match ~27K stripped social media images to ~609K source files using rotation-aware perceptual hashing and a 2.4M-row hash index.

Year
Jun 2026
Platforms
macOS · Home server
Type
Pipeline, AI/ML
Role
Sole developer

Thousands of my photos circulate online stripped of everything: names, dates, provenance. This finds their originals in a 609,000-file catalog and gives them their history back.

This tool takes photos that have been posted online (shrunk, stripped of all their names, dates, and captions, and given random filenames) and finds the original full-resolution file each one came from. It searches a personal photo library of about 609,000 images to match roughly 27,000 of these online copies back to their sources.

It works by giving every image a set of compact visual fingerprints, so two pictures that look the same can be recognized as a match even when one has been resized or rotated. It builds an index of these fingerprints for the whole library once, then compares each online copy against the index in a fraction of a second. Once a match is found, the tool hands back the original file's location along with its stored details (camera information, keywords, and ratings), so other programs can reunite each stripped photo with its history.

Features

  • Reunites stripped online copies with their originals: roughly 27,000 downloaded images matched against a 609,000-file personal library
  • Recognizes a photo even when the online copy has been shrunk, recompressed, or rotated
  • Each match hands back the original file's location plus its stored details (camera information, keywords, ratings), so the photo gets its history back
  • Searches the entire library in a fraction of a second per photo
  • Covers the whole catalog, including camera-raw and layered design files that ordinary image tools cannot read
  • Every match is graded by confidence (confident, worth a look, or unmatched), and unmatched photos are remembered so later runs focus on what is still missing
  • The library is fingerprinted once, then kept up to date incrementally; re-running is always safe
  • Other programs can submit photos in batches and receive matches back automatically

Under the hood

26Files
2,834Lines of code
3Commits
Jun 2026Dev window
StackPython 3 · imagehash · Pillow · pillow-heif · numpy · SQLite · click · rich · exiftool · PyYAML
InfraApple-silicon Mac (local); source files on NAS via SMB; Lightroom catalog read-only
Notable
  • Every source file is fingerprinted with three perceptual hash types (pHash, dHash, aHash) at 16-bit resolution in all four rotations, about 2.4 million hash rows for 609,000 files, so a resized, re-encoded, or rotated copy still lands within matching distance
  • The full index loads into memory and matching runs as vectorized XOR plus popcount in numpy: one query sweeps all 2.4 million rows in a fraction of a second
  • Scoring is a weighted Hamming distance across the three hash types, with per-type weights exposed in config so precision versus recall is tunable without code changes
  • Raw and layered formats Pillow cannot open (DNG, PSD, PSB) are fingerprinted from Lightroom's own .lrprev preview pyramids, read-only, so the catalog is never modified and no preview generation is triggered
  • Indexing runs 8 parallel workers against a SQLite database in WAL mode, so reads continue during writes; the job is idempotent, and re-runs skip files already hashed
  • Volume path remapping tracks a library spread across multiple NAS mounts and cloud-synced folders, so a match always resolves to the file's current live location