Drop a JPEG/PNG here, or click to choose.
Tuned on a fast 1800 px preview — then export at native
resolution up to 16K (16,384 px per side), processed in tiles so memory stays bounded.
1 · Denoise
1b · Full-resolution export
2 · Sharpness map & crop assistant
Warm tiles are sharp, cool tiles are soft (variance of the Laplacian per tile). Drag the box over your subject — the score tells you whether the crop can hold up. Drag the bottom-right corner to resize.
3 · The story of this photograph
Prefer an AI-written story? (free — no key needed)
Click the button and a downscaled copy of your before/after is sent — only then, only for this one story — to be described by Gemini. It goes to a tiny relay on my own domain that holds the API key; the image is never stored or logged, and this site keeps no server-side copy of anything you load. Optionally paste your own Google AI Studio key to bypass the relay entirely.
How it works
Noise estimation. The noise level σ is measured from the image itself with Immerkær's fast method (1996): convolve with a Laplacian-difference mask that annihilates image structure, and average what survives. Both denoisers adapt to this estimate, so the same slider position behaves consistently from ISO 800 to ISO 12800.
Non-local means (Buades, Coll & Morel, 2005) exploits self-similarity:
a feather barb or fur strand recurs many times across the frame, so each pixel is restored
as a weighted average of pixels whose neighbourhoods look alike — weights
exp(−max(‖P(i)−P(j)‖² − 2σ², 0)/h²). This implementation uses the
offset/box-filter decomposition for O(N·|search|) complexity, computes patch distances on
luminance, and applies the weights to all three channels.
Wavelet BayesShrink (Chang, Yu & Vetterli, 2000) transforms the image
into a multi-level Haar wavelet basis, where noise spreads thinly across all coefficients
but edges concentrate in a few large ones. Each detail subband is soft-thresholded at
T = σ²/σx, the Bayes-optimal threshold under a generalised-Gaussian
prior — aggressive in noisy flat sky, gentle where feather texture lives.
Two-stage oracle-guided NLM borrows the key insight of modern collaborative filtering (Dabov et al. 2007): matching noisy patches against noisy patches is unreliable, so denoise once to get a pilot estimate, then recompute patch similarities on that clean pilot — where structure and grain are already separated — and re-aggregate the original pixels with a tighter bandwidth. Verified on a step edge: the gradient across a subject's eye is preserved exactly, while flat-region noise drops a further ~20% versus single-pass NLM.
The story engine. After each rescue, the page reads the photograph back to you: light level and colour cast from the luma/chroma statistics, subject placement from the sharpness map's centre of mass, an ISO estimate from the measured σ, and what the restoration changed. Optionally, bring your own Gemini API key for an AI-written narrative — the image goes straight from your browser to Google, never to us. There is no server here: nothing you load is ever uploaded, stored, or logged.
The residual check. A denoiser should remove noise, not detail. The residual view shows exactly what was subtracted, amplified 4×: if it looks like uniform grain, the algorithm behaved; if you can trace an eye or wing in it, dial the strength down.
Crop scoring. The focus measure is the classic variance-of-Laplacian, computed per tile. The crop score compares the 90th-percentile sharpness inside your crop to the sharpest region of the whole frame, discounted by crop magnification — because a 1:1 crop of slightly-soft pixels reads soft, while the same pixels downsampled read fine.