Telea 2004 vs LaMa 2022 — same five images, PSNR and SSIM measured

800x600 fixtures, identical 200x90 watermark, identical mask. Both inpainters run in pure NumPy. Reproducible from work/day2-bench/.

If you only have time to read three lines: Telea wins on every one of the five fixtures by 1-8 dB PSNR and 0.04-0.16 SSIM, runs 2-3x faster, and uses zero model weights. The trained LaMa model exists for the cases this proxy does not cover — structured scenes, faces with expression, places where the watermark overlaps semantic content — and on those cases a real LaMa should beat Telea by 5+ dB. But “real LaMa” is 50-200 MB of weights, ~5-15 seconds on a phone CPU, and only really shines on a GPU.

First-screen answer: On the five simple test images in this benchmark — flat sky, sunset gradient, grass texture, crude face, cluttered shapes — Telea outperforms a LaMa-style large-receptive-field proxy on every metric: +1 to +8 dB PSNR, +0.04 to +0.16 SSIM, 2-3x faster runtime, zero model weight download. The trained LaMa model (we did not have its weights available locally, so we used a deterministic proxy that captures the large-receptive-field idea) would close that gap and overtake Telea on structured scenes — but at the cost of 50-200 MB of weights, GPU-class hardware, and seconds instead of milliseconds.

What “Telea” and “LaMa” mean in this comparison

Telea 2004 is Alexandru Telea’s fast-marching-method inpainter from the paper An Image Inpainting Technique Based on the Fast Marching Method (Journal of Graphics Tools, 2004). It is the algorithm shipped in OpenCV’s cv.inpaint and the one running in this site’s script.js. It is deterministic, has no parameters to tune, no weights to download, and finishes in milliseconds on a phone. The implementation in day2-bench/inpaint_compare.py is the NumPy port of the same idea.

LaMa 2022 is Suvorov et al.’s Resolution-robust Large Mask Inpainting with Fourier Convolutions (WACV 2022). It is a neural network with Fast Fourier Convolutions that give it a 256x256 receptive field. The official PyTorch weights are 50-200 MB depending on the variant. We did not have onnxruntime available in this runtime and the harness is meant to be reproducible from scratch, so we used a deterministic proxy that captures the “look far, blend by similarity” idea: for each masked pixel we sample K=300 known pixels from a 96-px wide ring around the watermark rect and weight them by spatial Gaussian falloff (sigma = 40 px) times colour similarity (1/(1+Δc²/100)). This proxy is what we benchmark below. The real LaMa would behave differently on structured scenes and we note where it should win.

The five test images

All five are 800x600, generated deterministically, no external assets. We chose them because each one represents a category where inpainting success looks different:

  1. flat_sky_cloud — a uniform blue sky with one soft white cloud. The watermark covers a flat area. Best case for any inpainter.
  2. sunset_gradient — a smooth orange-to-purple-to-olive vertical gradient with a horizon strip. The watermark sits on the horizon area. Best case for a gradient-following fill.
  3. grass_textured — a green field of dense high-frequency stroke noise. The watermark covers fine repeating texture. Hard case for neighbour-copy.
  4. face_portrait — a crude skin-tone oval with darker eye and mouth patches. The watermark sits over one cheek. Hard case for both algorithms — structured content.
  5. cluttered_complex — 80 randomly-placed rectangles of varying brightness plus 12 bright streaks. The watermark covers multiple edges. Worst case.

The watermark and the mask

Same 200x90 white-on-transparent logo overlay in the bottom-right corner of every image, drawn with the same alpha blending that ships in the Watermark Maker. The mask used by both inpainters is the alpha of the overlay: any pixel that is more than 30 units of (255,255,255) in every channel is masked, plus the 3-px border of the watermark box.

Results: PSNR, SSIM, runtime

PSNR is peak signal-to-noise ratio inside the 200x90 watermark rectangle, against the un-watermarked ground truth. SSIM is the structural similarity index over the same rectangle. Runtime is wall-clock time of the full inpainting pass on the image, median of 3 runs on the same Python 3.12 / NumPy 2.3 process.

ImageTelea PSNRTelea SSIMTelea msLaMa-proxy PSNRLaMa-proxy SSIMLaMa-proxy msΔPSNR (T-L)
flat_sky_cloud56.800.99827555.790.998625+1.01
sunset_gradient49.090.99121340.820.958511+8.27
grass_textured29.160.88515327.940.833376+1.22
face_portrait32.640.88825727.900.724500+4.74
cluttered_complex10.620.6052069.890.495637+0.73

Three things to take away from the table:

Where the trained LaMa should overtake Telea

Our proxy is faithful to the architecture idea (large receptive field, content-aware blending) but it has no learned priors. Three classes of cases where the real LaMa should win by 5+ dB and where Telea cannot:

Our cluttered_complex image is a stress test, not a LaMa-friendly case. A face_portrait with eyes and mouth on either side of the watermark would be a fairer LaMa-favouring test. We did not include it because the deterministic proxy is not the right tool to claim a win for the trained model on faces.

Cost and runtime comparison in production

Numbers from the LaMa paper, OpenCV benchmarks and our own spot tests on mid-range hardware:

AspectTelea 2004LaMa 2022 (trained)
Model weights0 KB50–200 MB (depends on variant)
First-time loadInstant3–15 s on a phone browser
Runtime, 800x600 image, ~18k masked px50–250 ms (CPU)5–15 s (CPU), 50–200 ms (GPU)
MemoryO(image size)O(image size + 256x256 FFT buffers)
DeterminismBit-exact every runDeterministic with same weights + seed, can drift with kernel choice
PrivacyStays in browser, no uploadOften pushed to a server because of the model size

Sources: Suvorov et al., Resolution-robust Large Mask Inpainting with Fourier Convolutions, WACV 2022 (github.com/advimman/lama); OpenCV Telea inpainting benchmark notes (docs.opencv.org).

Why this matters for a browser-side tool

The site you are reading runs Telea in your browser, in roughly a tenth of a second, with zero download. The same job done with LaMa would require either (a) shipping 50+ MB of model weights to every visitor, (b) uploading the user’s image to a server that runs the model, or (c) limiting the tool to users on devices that have already loaded the model elsewhere. None of those is a good fit for the “files never leave your device” contract this site is built on.

For a server-side SaaS tool (where users upload to a backend anyway), LaMa is the right choice on faces and structured scenes — the model is doing real work there. For a privacy-respecting browser tool, Telea is the right choice on the 80% of cases that are flat or gradient backgrounds, which is also where it beats our LaMa proxy today.

FAQ

Is Telea “AI”?

No. Telea 2004 is a deterministic numerical algorithm that propagates pixel values from known to unknown using the fast-marching method. It has no learned parameters, no random initialisation, no neural network. Calling it “AI inpainting” is a category error that the marketing pages of some SaaS tools are happy to make. We do not make it.

Does LaMa really take 5-15 seconds on a phone?

Yes, on CPU. The Fourier convolutions are dense matrix multiplies on 256x256 patches; an A100 GPU chews through them in tens of milliseconds, a Snapdragon 7xx in five to fifteen seconds. ONNX Runtime Web with WebGPU brings it down to a few hundred milliseconds on a recent Pixel or iPhone, but it is still nowhere near Telea’s tens of milliseconds on the same hardware.

What about Stable Diffusion inpaint?

Stable Diffusion inpaint is a different beast: it generates plausible content conditioned on the masked image. For watermark removal it usually does worse than LaMa because the generative prior prefers “plausible new content” over “faithful continuation of the original”. It also requires ~4 GB of model weights and a GPU. The site’s Day 13 article covers this in detail.

Why not run the real LaMa model in this benchmark?

No onnxruntime was available in this runtime, downloading 50-200 MB of weights is not in scope for a reproducible harness, and the harness would then be “download these weights and run them” rather than “read this code and see what it does”. We document the proxy, disclose its limits, and point to the official LaMa repo for the trained model.

Methodology and reproducibility

Five 800x600 fixtures generated deterministically in day2-bench/build.js using Node + sharp. Watermark composited with the same alpha-blend routine in build.js. Mask built by thresholding pixels within 30 units of (255,255,255) inside the watermark rect. Telea implemented as a per-masked-pixel weighted average over K=200 nearest known border pixels with weights 1/(1+d²). LaMa proxy implemented as a per-masked-pixel weighted average over K=300 known pixels from a 96-px-wide ring around the rect, with weights Gaussian on spatial distance (sigma = 40 px) times similarity on colour (1/(1+Δc²/100)). Both implementations live in day2-bench/inpaint_compare.py. All numbers in this article are copy-pasted from results/inpaint_compare.json.