When Watermark Removal Fails: Five Backgrounds, Measured Against Ground Truth

The watermark disappears every single time. The question is what replaces it. We painted one identical brush stroke over one identical watermark on five backgrounds we generated ourselves - smooth gradient, fine 4-pixel stripes, a hard two-tone edge, a periodic 25-pixel grid, and random grey noise - and compared the result pixel by pixel against the original we hid it under. Across all five runs the painted stroke covers the same 24,109 pixels in every run and not one pixel outside that stroke ever changes; 0 outside the stroke. So the tool stays in the box you painted, but inside that box it replaces everything, the clean background and the watermark together.

The clean background under the brush matters more than the watermark itself. On the smooth gradient (49.27 -> 2.83 RMSE on the watermark footprint, collateral 0 -> 2.42) the fill is near-perfect. On the fine stripes the same fill makes the result worse than the input (footprint 54.17 -> 66.18, gradient of the original was 60, of the result is 4) - the stripes vanish. On the hard edge (58.36 -> 15.62 footprint, but 27.57 -> 86.14 in the 9-pixel band straddling the edge) the boundary smears. On the periodic grid (37.25 -> 83.37) the lines stop dead where the stroke begins. On random noise (51.20 -> 53.64) the result is a smooth blob the size of the stroke.

Tested: the result is not 'what was under the watermark' - it is 'what was at the edge of the stroke, propagated inward until the stroke was filled'. The width of the stroke and the frequency of what's next to it set the ceiling on quality.

Results matrix: five backgrounds tested with the same brush stroke - only the smooth gradient filled clean; the stripes got worse than the input, the hard edge smeared, the grid lines stopped dead, and the noise became a smooth blob
One stroke, five backgrounds: the fill stays inside the stroke everywhere, but what it leaves behind depends entirely on the background. Measured against ground truth - full data below.

What we measured and how

All five 800x600 test images were generated in Python (Pillow), so we know exactly what was hidden under the watermark before the tool ever saw the image.

Because we generated the background ourselves, every number below is compared against a known ground truth, not against another tool or a guess.

The one number that frames everything: zero pixels outside the stroke

Before talking about quality, we answered the 'does it stay in the box' question. For every run, the exported PNG was compared pixel-by-pixel against the input PNG.

That property - the tool modifies exactly the painted pixels and nothing else - is checked in the code, not promised. It is also what the lossless, deterministic engine implies: app.js contains zero calls to Math.random (grep -c "Math.random" app.js = 0), and the brush is in image pixels (rad = brush.value / 2, verified), so the same input + the same mask produces the same output, byte for byte.

Smooth gradient - the case where it works

Input, output, and hidden original for a smooth gradient. Input shows a grey gradient with white WATERMARK text. Output shows a faintly streaky grey patch where the text was, very close to the original. Hidden original shows the clean gradient.

The fill is near-perfect here for a simple reason: the only "information" the fill needs to invent is "continue this gradient", and the gradient provides that information at every pixel on the boundary of the stroke.

Fine 4-pixel stripes - the result is worse than the input

Input, output, and hidden original for fine vertical stripes. Input shows vertical pinstripes under the WATERMARK text. Output shows a smooth grey capsule replacing the stripes entirely. Hidden original shows the same pinstripes continuing through the capsule.

This is the failure mode the page naming "works best on small to moderate overlays on relatively uniform backgrounds" (used by every competitor page) describes without quantifying. Here it is quantified: the fill averages nearby pixels, the stripes are smaller than the averaging radius, so they cannot survive propagation. If your real photo has anything finer than roughly a brush-width across it (fine fabric weave, hair, foliage, halftone, cross-hatching), expect the same.

Hard two-tone edge - the watermark goes, the edge smears

Input, output, and hidden original for a hard two-tone edge. Input shows the WATERMARK text crossing a dark/light vertical boundary. Output shows a smeared transition where the boundary used to be. Hidden original shows a crisp dark/light edge.

The error is not spread across the stroke; it is concentrated in a narrow band on the structural boundary. That is what propagation across a discontinuity looks like. If your real photo contains a watermark that straddles a strong edge - a logo over a wall corner, text over a horizon, a brand mark over a building edge - that edge will be softened where you pulled from both sides of it.

Periodic grid - the lines stop dead

Input, output, and hidden original for a periodic grid. Input shows a 25-pixel grid under the WATERMARK text. Output shows a vertical smear that does not continue the grid lines. Hidden original shows the grid running straight through.

Error map for the grid case. Red marks every pixel that differs between the tool output and the hidden original. The capsule is almost entirely red where the grid lines are cut.

Propagation cannot invent continuation. The grid line that arrived at the boundary of the stroke from the left at row y=200 stops at the stroke's edge; the fill line at row y=200 inside the stroke is whatever Telea produced by averaging nearby values, which is not a continuation of the original line. Real photos with regular structure (brick walls, tile floors, fences, window blinds, fabric weaves, horizontal siding) will show the same: the structure is gone wherever you paint.

Random noise - a smooth blob the size of the stroke

Input, output, and hidden original for random grey noise. Input shows grey speckle with WATERMARK text. Output shows a smooth grey capsule. Hidden original shows the speckle continuing through.

Noise is the unconditional worst case for any propagation fill: there is no pattern to propagate, so the fill averages whatever it finds at the boundary, and what you get back is a smooth grey patch the shape of your stroke. High-ISO photos, sensor grain on a flat surface, and JPEG-compressed photos (which carry DCT-block artefacts that are not predictable from one block to the next) sit close to this case.

What the ring numbers actually tell you

The ring decomposition splits the painted stroke into 24 bands by distance from the stroke boundary, 1 pixel thick on the outside, growing inward. For a propagating fill on smooth content, error should grow roughly linearly with distance: the fill is best where it has the most nearby boundary to sample from. The data:

Practical version: "make the brush a bit smaller and do multiple passes" only helps in the first case. On structured backgrounds the failure is structural, not a depth problem.

The four honest failure modes and what to do about each

How the run was verified to be honest

All five strip images on this page and the error map are the actual outputs from those five runs, not stock photos or competitor screenshots.