A photo of a flyer, a screenshot, an image someone sent you — and the QR code inside it just won't scan. It happens more often than you'd think. The good news: QR codes were designed from the start with a built-in "break-and-repair" mechanism (error correction), and in many cases a little image cleanup is all it takes to make the code readable again. This article explains, in plain language, why unreadable QR codes can be recovered — walking through error correction, enhancement, binarization, and deblurring — along with tuning tips for each parameter and an honest look at what cannot be fixed.
1. Why a damaged QR code can still be read — error correction
A QR code (ISO/IEC 18004) does not simply lay your data out as black and white squares (modules). Before encoding, it appends redundant recovery data generated with Reed–Solomon codes — essentially "hints for reconstructing the original data, embedded in advance". The same family of techniques protects CDs against scratches and satellite links against noise.
How much damage can be repaired is decided by the error correction level chosen when the code was generated.
| Level | Approx. recoverable | Typical use |
|---|---|---|
| L | ~7% | Clean on-screen display |
| M | ~15% | Standard; ordinary print |
| Q | ~25% | Outdoor or dirt-prone environments |
| H | ~30% | Design QR codes with logos |
So even if the QR in your photo is somewhat dirty, chipped, or partially covered, it can in theory be recovered perfectly — as long as the damage stays within the error correction budget. The catch: when the photo itself is poor, the reader misjudges "is this module black or white?" on a massive scale and burns through that budget instantly. The whole job of image processing is to reduce those misjudgements until error correction can take over. For the mathematics behind the correction itself, see "How QR Code Error Correction Works".
2. Enhancement — contrast and binarization
A QR reader ultimately sorts every module into one of two buckets: white or black. A dark photo, or one with uneven, grayish lighting, makes that sorting error-prone. Two treatments help.
Contrast adjustment
Push bright areas brighter and dark areas darker, widening the gap between white and black modules. This works well for faintly printed codes and backlit, washed-out photos. Overdo it and you amplify the lighting unevenness too, so nudge the slider while watching the preview.
Binarization (thresholding)
This mechanically forces each pixel to pure black or white: "darker than this brightness (the threshold) → black, otherwise → white". The threshold placement is everything — lower it for dark photos, raise it for bright ones. If hunting by hand feels tedious, a classic algorithm called Otsu's method estimates the optimal threshold automatically from the brightness distribution (histogram); our tool ships it as the "auto threshold" button.
3. Blur and misfocus — the unsharp mask
In shaky or out-of-focus photos, module edges smear into their neighbors. The classic remedy is the unsharp mask — despite the name, it sharpens. The recipe is simple:
- Make a slightly blurred copy of the image
- Subtract it from the original (the difference is exactly the edge content)
- Multiply that difference by a strength factor and add it back
There are two parameters. The radius is the blur size — match it to the width of the smearing; a large radius on fine smear looks unnatural. The strength controls how much edge is added back — more makes edges crisper but amplifies noise as well, so too much backfires. The basic procedure: "set the radius to the blur width first, then raise the strength little by little".
To be honest about it: an unsharp mask is not true deblurring (deconvolution). It cannot fully undo heavy blur; it is a symptomatic treatment that steepens boundaries to reduce black/white misjudgements. But that is often enough — once the misjudgements fall back under the error correction budget, the scan succeeds.
4. When all else fails — the parameter sweep (auto retry)
"Which threshold makes it readable?" differs photo by photo, and trying values one at a time is tedious. That is where a brute-force parameter sweep shines. Our tool automatically iterates through combinations of:
- Binarization threshold: automatic (Otsu's method) plus several fixed steps from 80 to 200
- Black/white inversion: handles inverted QR codes (light modules on a dark background)
- Rotation: 0/90/180/270° (insurance against mirrored or unusually oriented shots)
Each attempt is quick, but dozens of them add up, so the work is split into small chunks — one attempt per animation frame — keeping the page fully responsive throughout. The sweep stops the moment a decode succeeds and reports the winning parameters together with the error correction level.
Free Tool Try the QR Code Photo Restore tool Three modes: enhance, auto retry, and deblur. Images never leave your browser — everything is processed locally.5. What cannot be fixed — the limits of recovery
Error correction is not magic. The following cases cannot be recovered by image processing; retaking the photo or regenerating the code is the answer.
- A missing finder pattern (one of the three large corner squares): the reader cannot even locate or orient the code, so error correction never gets a chance.
- Damage or occlusion beyond the correction budget (about 30% at most): even level H tops out around 30%. A half-covered QR is unreadable.
- Absolute lack of resolution: if one module has collapsed below one pixel, the information itself is gone — upscaling cannot bring it back.
- Severe blur: smearing that spans several modules is beyond edge enhancement.
For diagnosing why a code fails to scan — and how to make codes that scan reliably in the first place — see "Why Your QR Code Won't Scan and How to Fix It".
Summary — quick parameter reference
| Symptom | Treatment | Tuning tip |
|---|---|---|
| Faint print / grayish overall | Contrast + binarization | Start from the auto threshold, then fine-tune |
| Small and mushy | Upscale + unsharp mask | Enlarge first, then crispen the edges |
| Camera shake / misfocus | Unsharp mask (radius & strength) | Match radius to blur width; raise strength gradually |
| Inverted black & white | Inversion + binarization | Included in the auto retry sweep |
| Dirt / small chips | Binarization + auto retry | Error correction restores the rest by itself |