ClearPix engineering series · Part 20
Watermark Removal Quality Day: Detection Recall on Real Photos, Backing Expansion, and the Spiral Detector We Switched Off
Today was a removal-quality deep dive on ClearPix's image watermark pipeline. Three things shipped, one thing deliberately did not, and the QA harness got ten real watermarks pulled from the open web so future changes are measured against reality instead of only synthetic tiles.
The numbers up front
| Measurement | Before | After |
|---|---|---|
| Huge solid text (synthetic cap cases) detected | 0 % | 93 % |
| Cursive/signature-style text detected | 0 % | 100 % |
| Tiled watermark text detected (hardest class) | 0 % | 5.4 % (partial, honest) |
| Badge-on-grass fill quality (bench metric, higher = better) | 8.1 | 28.4 |
| Badge-on-photo fill quality | 15.3 | 29.9 |
| Regressions on the existing 13-case acceptance set | — | 0 |
| Real-web watermarks in the permanent QA set | 0 | 10 (cases 1–10) |
| Baseline benchmark for future comparisons | — | batch-36-2026-11-02 |
| Concentric-ring / spiral-arc detector | proposed | switched off behind ?ring=1 |
Fix 1: double-cap text detection
The first gap showed up immediately once we benchmarked against real watermark photos (sourced from the open boomb0om/watermarks-validation set on Hugging Face): the detector simply did not fire on three entire classes of watermark — huge solid display text, cursive signatures, and tiled repeats. Recall on those classes was exactly zero, not "low".
Root cause was a double area cap: an absolute pixel cap and a relative-to-image cap, both sized for typical small corner stamps. A watermark that spans a third of the frame in 96 px capitals tripped both caps and was thrown away before shape detection ever ran. The fix keeps the caps but makes them aware of aspect and stroke density: boxes whose interior is dominated by actual stroke pixels (not bounding-box area) get a much larger allowance.
The result is in the table above. Tiled text remains nearly undetected (5.4 %) — that is not a threshold we can tune away today, and we would rather report 5.4 % than tune until a synthetic number looks good and real photos regress.
Fix 2: expanding masks to the backing, not just the glyphs
The second problem was not detection but masking. A text watermark printed on a badge, pill, or semi-opaque plate: selecting only the glyphs leaves the plate behind, and the inpainter then has to rebuild content across a visible rectangular scar. We now detect the uniform backing region a text box sits on and extend the removal mask to the backing's full connected domain.
The bench moved sharply: badge-on-grass fill quality went from 8.1 to 28.4, badge-on-photo from 15.3 to 29.9 (our internal region metric; higher is better, details in docs/). Along the way we fixed a unit bug — the ring-padding distance was being applied in downscaled grid units in one path and full-resolution pixels in another, so masks on large images were padded by 2–4× the intended margin.
Zero regressions on the pre-existing acceptance cases. The backing gate is conservative: it only fires when the region around a text box is genuinely uniform, so busy backgrounds are untouched.
What did not ship: the spiral detector, and why
The most instructive part of the day was a failure. One watermark family resists everything above: swirl/spiral arc signatures (the Photocase-style rotating arc). They are geometric — concentric curved strokes around a center — so we built a dedicated geometric detector: Sobel gradient candidates, radial histograms from a coarse center grid, then circle-sampling verification. Over roughly a dozen iterations we added seven discriminators: gradient polarity, radial histogram peaks, brightness, saturation, radius consistency, equal spacing between rings, and circular hit rate.
Every discriminator was calibrated offline against 8 images and looked clean. Every one of them was then defeated by real texture:
- The genuine spiral image (a real photo with a real watermark) was rejected — its arc polarity flips between 0.01 and 0.47 as it crosses bright snow and dark forest, so polarity gates kill the true positive.
- Six real photos with no spiral at all passed every gate — stone texture, tree bark, and water ripples all produce convincing concentric-arc signatures.
That is the classic shape-detector trap we wrote about in part 15: the model is not confused, it is confidently reporting structure that genuinely resembles the target. When six clean images pass and the one true positive fails, more threshold tuning is curve-fitting to noise. So we pulled the circuit breaker: the detector stays in the codebase, compiled and unit-tested, but it only runs when the URL explicitly sets ?ring=1. It affects zero production paths. Shipping it because we spent a day on it would have been the sunk-cost fallacy in its purest form.
QA: ten real web watermarks, permanently
The harness change matters more than any single fix. We pulled ten real watermarks from the open web (the Hugging Face boomb0om/watermarks-validation collection — Getty, Photocase, and similar stock-photo marks) and promoted them into the permanent QA set as cases 1–10, with a 36-case baseline batch (batch-36-2026-11-02) recorded for every future change to diff against. Synthetic tiles were moved out of the headline numbers; they stay as stress tests, not as the scoreboard.
Takeaways
- Zero recall is a bug class of its own. "Low detection" and "no detection" look the same in a demo and completely different in a diff. The area caps were invisible until real photos were in the harness.
- Mask quality is half of removal quality. The same inpainting model scored 8.1 → 28.4 purely from masking the backing plate instead of the glyphs.
- A calibrated-offline discriminator is a hypothesis, not a gate. Seven of them all failed on real data the same afternoon. Keep a switch that can turn a feature off completely, and use it.
- Measure against reality. Ten real watermarks in the QA set changed what we worked on today more than any metric did.
All numbers above are reproducible from the QA harness in the repo; nothing was measured on a demo image chosen after the fact.
ClearPix is free, unlimited and runs entirely in your browser. If this post saved you a debugging session, a coffee keeps the model hosting and bandwidth paid for — nothing here is locked behind it.
Buy me a coffee