Post

Earning the rectangle, seven attempts deep

This is part three of four. Part two ended with a new goal and three acceptance criteria: deterministic, auditable, honest. The watermark becomes one uniform translucent rectangle carrying its own color and opacity, and nothing is invented.

What follows is every attempt in the order I tried it, each with why it was tried, what it produced, and where it fell short. A shorter telling of this stretch appeared in the first rectangle post.

The blend model everything stands on

A semi transparent watermark does not sit on top of a photo. It is blended into it, per pixel:

1
observed = alpha * color + (1 - alpha) * background

For the main siteโ€™s mark, measurement put alpha near 0.28 with white text. Two consequences drive the whole recipe. First, the markโ€™s own appearance is computable, so a replacement can match it exactly. Second, the background survives dimmed inside every marked pixel, which is both a temptation and a trap that attempt five falls into.

Attempt 1. The opaque sticker

Why: simplest thing that could work. Median color of all masked pixels, fill the bounding box.

Result: text gone completely. The recipe ran at detection speed with no model in sight.

Shortcoming: zero transparency. On a brown floor the panel was a flat tan sticker. The output failed the โ€œhonestโ€ criterion immediately: it looked like an edit hiding something.

Attempt 2. Measured transparency

Why: the blend model makes opacity measurable rather than guessable. Lift over headroom:

1
alpha = (observed - background) / (255 - background)

I computed this over masked pixels across 40 real images and rendered ladders of candidate opacities side by side.

alpha bandverdict from the ladder
0.40 to 0.70original text clearly traceable
0.71 to 0.89traceable if you know where to look
0.90 to 0.93gone at a glance, faint structure on close inspection
0.94completely unreadable, still reads as a watermark band

Measured opacity clustered between 0.26 and 0.31, matching how faint the real marks look, and 0.94 locked as the paint value.

Shortcoming: two images in the batch broke it, each differently, and both failures taught more than the successes.

Attempt 3. Sample the text, not the badge

Why it failed before fixing: one site uses two layer marks, a solid purple badge with white text inside. Taking the median of all masked pixels lands on the badge because badges out area letters. Painting purple under white text leaves the letters ghosting through, brighter than their surroundings.

Fix: the glyphs are the brightest set under the mask. Sample only them:

1
2
bright = px[mask][np.argsort(px[mask].sum(1))[-k:]]
text_color = np.median(bright, axis=0)

On the badge image the sampled color moved from purple to near white and the panel stopped fighting the text.

Attempt 4. Neutralize the strokes before painting

Why: painting the text color over pixels containing the text is a no-op. White veil over white strokes is still white. The readable ghost survived until this existed.

Method: replace glyph pixels with the median of their 21 pixel neighborhood, guarded so the patch cannot eat the photo:

1
2
3
4
med = cv2.medianBlur(img, 21)
delta = np.abs(luma(med) - luma(img))
patch = (delta > 15) & (luma(img) < 210)   # skip noise, skip bright windows
img[mask & patch] = med[mask & patch]

Flat surfaces give flat medians. Wood gives the local grain tone. Bright saturated areas are skipped because the veil alone already hides anything there.

Attempt 5. Exact inversion, the elegant dead end

Why: the blend equation rearranges. If per pixel alpha were known, the true background comes back exactly, grain included, no reconstruction:

1
background = (observed - alpha * 255) / (1 - alpha)

Result: dark streaks and amplified noise. Division by (1 - alpha) magnifies any error in alpha by up to about 30 times. A 0.03 error becomes a visible gouge, and JPEG compression guarantees such errors.

Shortcoming: exact math on estimated inputs produces confidently wrong pixels. Dropped without regret; it later earned a second life as a benchmark challenger.

Attempt 6. Rotations for vertical marks

Why: one site stamps vertically down furniture and plain detection caught half of it.

Method: detect on the image rotated 90 degrees each way, map masks back, union everything:

flowchart TB
    A[Image] --> B[Detect at 0 deg]
    A --> C[Rotate CW, detect]
    A --> D[Rotate CCW, detect]
    B --> E[Map back]
    C --> E
    D --> E
    E --> F[Union masks]
    F --> G[One bounding box]

The union covers the full strip. This step exists entirely because of one wardrobe photo.

Attempt 7. Locking the recipe

Everything above assembled into five steps: detect three times and union, dilate by 5 for the box plus 8 padding, sample text color from the brightest 20 percent, neutralize strokes with the guarded patch, paint one constant rectangle at 0.94. Every parameter traces to a specific failure. Nothing is a default someone picked.

Porting it into the production tool surfaced four bugs worth naming because each produced wrong output that looked right:

  1. Silent CPU fallback. Models loaded onto CPU through an unresolved device string. Everything worked at one eighth speed.
  2. Channel swap. OpenCV BGR arrays saved through an RGB assuming path. Red and blue exchanged everywhere, invisible on beige interiors, fatal for blue skies.
  3. The pool that hangs. One multiprocessing worker died quietly and the pool waited forever. Detection now runs in-process.
  4. Dilated mask leak. Color sampled from the dilated mask instead of the raw one shifted results on most test images.

Every attempt side by side

Every directory in the repository is its own attempt here, forty five of them, each trying something slightly different. Every hardware cell reads the same way: throughput in images per second, then wall clock ETA for the full 700K corpus on that machine, then what that run would cost. Own hardware costs nothing beyond pennies of electricity; rented silicon is priced at typical market rates of about $0.5 per hour for a 4090 or 5090, $0.4 for a 7900 XTX, $1.2 for an L40S, $2 for an A100, and $3 for an H100. Plain numbers are measured, from the run logs (pp_run.jsonl, faint_run.log) and the August sessions; tilde prefixed cells are honest estimates because no run of that attempt ever touched that machine. The anchors: v14 at 2.34 img/s, the CPU fallback incident at 0.25, and BrushNet at 9.5 seconds per image.

S/Niterationnamewhat it triedresult on the imageissue that killed itCPU 20cRTX 4070 8GRX 7900XT 24GRTX 4090 24GL40S 48GA100 80GH100 80GRTX 5090 32Gย 
1clean_v5LaMa Generationfifth threshold generation for faint markssome photos partly cleaned, residue stayedmarks below detection threshold survived~0.05 ยท 162 d ยท $00.94 ยท 8.6 d ยท $0~1.1 ยท 7.4 d ยท $71~1.15 ยท 7.0 d ยท $85~1.2 ยท 6.8 d ยท $194~1.2 ยท 6.8 d ยท $324~1.2 ยท 6.8 d ยท $486~1.2 ยท 6.8 d ยท $81~207 h (8.6 d)
2clean_v1LaMa Generationbaseline: detect then LaMa fillwalls clean, windows filled with invented smudgesinvented content unverifiable without originals~0.05 ยท 162 d ยท $01.11 ยท 7.3 d ยท $0~1.2 ยท 6.8 d ยท $65~1.2 ยท 6.8 d ยท $81~1.25 ยท 6.5 d ยท $187~1.25 ยท 6.5 d ยท $311~1.25 ยท 6.5 d ยท $467~1.25 ยท 6.5 d ยท $78~175 h (7.3 d)
3clean_v2LaMa Generationraised OCR corroboration thresholdfewer false hits, real faint marks skippedtuning one knob opened coverage holes~0.05 ยท 162 d ยท $01.19 ยท 6.8 d ยท $0~1.2 ยท 6.8 d ยท $65~1.2 ยท 6.8 d ยท $81~1.25 ยท 6.5 d ยท $187~1.25 ยท 6.5 d ยท $311~1.25 ยท 6.5 d ยท $467~1.25 ยท 6.5 d ยท $78~163 h (6.8 d)
4clean_v4LaMa Generationwider mask dilation for glyph edgeswood and brick blurred where masks grewbigger masks meant worse fills~0.05 ยท 162 d ยท $01.24 ยท 6.5 d ยท $0~1.25 ยท 6.5 d ยท $62~1.25 ยท 6.5 d ยท $78~1.3 ยท 6.2 d ยท $179~1.3 ยท 6.2 d ยท $299~1.3 ยท 6.2 d ยท $449~1.3 ยท 6.2 d ยท $75~157 h (6.5 d)
5morphThe ProbeOpenCV morphology alone finds marksmasks covered marks plus noise blobs, ragged edgesno clean path from ragged masks to panels~5 ยท 39 h ยท $05 ยท 39 h ยท $05 ยท 39 h ยท $165 ยท 39 h ยท $195 ยท 39 h ยท $475 ยท 39 h ยท $785 ยท 39 h ยท $1175 ยท 39 h ยท $19~39 h
6morph_v2The Probe, Second Cuttighter kernels and structure filtersfaster, glyph edges still raggedsame dead end, cheaper~6 ยท 32 h ยท $06 ยท 32 h ยท $06 ยท 32 h ยท $136 ยท 32 h ยท $166 ยท 32 h ยท $396 ยท 32 h ยท $656 ยท 32 h ยท $976 ยท 32 h ยท $16~32 h
7morph_simpleThe Simple Probeminimal erode dilate set onlythin strokes dropped entirelyrecall far too low~7 ยท 28 h ยท $07 ยท 28 h ยท $07 ยท 28 h ยท $117 ยท 28 h ยท $147 ยท 28 h ยท $337 ยท 28 h ยท $567 ยท 28 h ยท $837 ยท 28 h ยท $14~28 h
8morph_transparentTransparent Probesoft alpha edges on morph maskshalos ringed every panel edgebad masks make soft edges worse~5 ยท 39 h ยท $05 ยท 39 h ยท $05 ยท 39 h ยท $165 ยท 39 h ยท $195 ยท 39 h ยท $475 ยท 39 h ยท $785 ยท 39 h ยท $1175 ยท 39 h ยท $19~39 h
9replicateTemplate Checkalpha template reused across sibling shotstemplates matched nothing reliablyper shot brightness shifts kill shared templates~1 ยท 8.1 d ยท $01 ยท 8.1 d ยท $01 ยท 8.1 d ยท $781 ยท 8.1 d ยท $971 ยท 8.1 d ยท $2331 ยท 8.1 d ยท $3891 ยท 8.1 d ยท $5831 ยท 8.1 d ยท $97~194 h (8.1 d)
10unmixDecomposition Tryunmix mark as separable layerJPEG blocks broke separation, colored fringessource compression too high for decomposition~2 ยท 4.1 d ยท $02 ยท 4.1 d ยท $02 ยท 4.1 d ยท $392 ยท 4.1 d ยท $492 ยท 4.1 d ยท $1172 ยท 4.1 d ยท $1942 ยท 4.1 d ยท $2922 ยท 4.1 d ยท $49~97 h (4.0 d)
11rect_algo/v01Geometry Sketch 1fixed offset placement rulesboxes drifted off marks across aspect ratiosfixed rules cannot generalize~3 ยท 65 h ยท $0~3.2 ยท 61 h ยท $0~3.2 ยท 61 h ยท $24~3.4 ยท 57 h ยท $29~3.4 ยท 57 h ยท $69~3.4 ยท 57 h ยท $114~3.4 ยท 57 h ยท $172~3.4 ยท 57 h ยท $29~61 h (2.5 d)
12rect_algo/v02Geometry Sketch 2aspect ratio priors addedcommon shapes better, others still offpriors are guesses in disguise~3 ยท 65 h ยท $0~3.2 ยท 61 h ยท $0~3.2 ยท 61 h ยท $24~3.4 ยท 57 h ยท $29~3.4 ยท 57 h ยท $69~3.4 ยท 57 h ยท $114~3.4 ยท 57 h ยท $172~3.4 ยท 57 h ยท $29~61 h (2.5 d)
13rect_algo/v03Geometry Sketch 3snap box edges to scene edgessnapped to window frames instead of marksedge ambiguity unsolvable locally~3 ยท 65 h ยท $0~3.2 ยท 61 h ยท $0~3.2 ยท 61 h ยท $24~3.4 ยท 57 h ยท $29~3.4 ยท 57 h ยท $69~3.4 ยท 57 h ยท $114~3.4 ยท 57 h ยท $172~3.4 ยท 57 h ยท $29~61 h (2.5 d)
14rect_algo/v04_triTriangle Ruletriangular coverage heuristicsmarks covered along with half the wallovercoverage destroys the photo~3 ยท 65 h ยท $0~3.2 ยท 61 h ยท $0~3.2 ยท 61 h ยท $24~3.4 ยท 57 h ยท $29~3.4 ยท 57 h ยท $69~3.4 ยท 57 h ยท $114~3.4 ยท 57 h ยท $172~3.4 ยท 57 h ยท $29~61 h (2.5 d)
15rect_algo/v05_roundRounded Panelrounded corner aestheticslooked nice, verticals missed entirelycosmetics cannot fix coverage~3 ยท 65 h ยท $0~3.2 ยท 61 h ยท $0~3.2 ยท 61 h ยท $24~3.4 ยท 57 h ยท $29~3.4 ยท 57 h ยท $69~3.4 ยท 57 h ยท $114~3.4 ยท 57 h ยท $172~3.4 ยท 57 h ยท $29~61 h (2.5 d)
16rect_algo/v06_user_scriptBorrowed Scriptcommunity removal script geometrypanel colors came from background not textits color model assumes different watermarks~4 ยท 49 h ยท $04 ยท 49 h ยท $04 ยท 49 h ยท $194 ยท 49 h ยท $244 ยท 49 h ยท $584 ยท 49 h ยท $974 ยท 49 h ยท $1464 ยท 49 h ยท $24~49 h (2.0 d)
17rect_algo/v07_glyph_masksGlyph Firstper glyph boxes instead of one unionvisible seams between letter panelsglyph sized units make patchwork~2.7 ยท 3.0 d ยท $0~2.9 ยท 67 h ยท $0~2.9 ยท 67 h ยท $27~3.1 ยท 63 h ยท $31~3.1 ยท 63 h ยท $75~3.1 ยท 63 h ยท $125~3.1 ยท 63 h ยท $188~3.1 ยท 63 h ยท $31~67 h (2.8 d)
18simple_morph_t/v01Sticker Round 1first median fill over union boxletters gone, flat opaque tan stickerzero transparency fails the honesty goal~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
19simple_morph_t/v02Sticker Round 2sampling region tightened inside masksame sticker lookopacity was never about sampling region~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
20simple_morph_t/v03Sticker Round 3percentile based color samplingslightly warmer panel, still opaquesampling tweaks cannot add transparency~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
21simple_morph_t/v04Sticker Round 4padding sweep around the boxpadding clipped neighbor glyphs into panelsgeometry knob, wrong problem~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
22simple_morph_t/v05Sticker Round 5merge rules for twin stampsdouble boxes whenever marks sat closemerge logic required regardless~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
23simple_morph_t/v06Sticker Round 6union strategy stabilizedone stable box per mark at laststill fully opaque~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
24simple_morph_t/v07Sticker Round 7final opaque era tuningbest sticker achievabletransparency still zero~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
25simple_morph_t/v08_simple_transparentFirst Transparencyblend equation replaces fill, alpha 0.29surface showed through, color roughdirection right, color sampling crude~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
26exact_invert/v01_flatFlat Alpha Inversioninvert blend with one global alphadark streaks at anti aliased stroke edgesone alpha cannot fit edge gradients~30 ยท 6 h ยท $030 ยท 6 h ยท $030 ยท 6 h ยท $330 ยท 6 h ยท $330 ยท 6 h ยท $830 ยท 6 h ยท $1330 ยท 6 h ยท $1930 ยท 6 h ยท $3~7 h
27exact_invert/v02_perpixelPer Pixel Inversionper pixel alpha map from templatenoise amplified up to 30 timesestimator dominated by background pixels~25 ยท 8 h ยท $025 ยท 8 h ยท $025 ยท 8 h ยท $325 ยท 8 h ยท $425 ยท 8 h ยท $925 ยท 8 h ยท $1625 ยท 8 h ยท $2325 ยท 8 h ยท $4~8 h
28template_match_lama/v01Hybrid First Passtemplate match locate, LaMa fill strokesflat marks clean, textured ones poorLaMa cost paid for narrow gains~0.04 ยท 203 d ยท $0~0.45 ยท 18 d ยท $0~0.5 ยท 16 d ยท $156~0.55 ยท 15 d ยท $177~0.55 ยท 15 d ยท $424~0.55 ยท 15 d ยท $707~0.55 ยท 15 d ยท $1,061~0.55 ยท 15 d ยท $177~432 h (18 d)
29simple_morph_t/v09_one_colorOne Color Panelsingle constant color per whole markuniform panels achieved at lastwhich alpha remained unknown~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
30simple_morph_t/v10_alpha_ladderLadder Part Oneopacities 0.40 to 0.85 rendered side by sideevery panel traceable below 0.90lower half of ladder ruled out~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
31simple_morph_t/v11_alpha_ladderLadder Part Twoopacities 0.86 to 1.00 rendered0.94 unreadable yet still reads as watermarknone, this run produced the lock~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
32simple_morph_t/v12_batch40_a94The Fortyfirst full 40 image batch at 0.94purple badge text ghosted through, wardrobe strip half coveredtwo concrete failure classes exposed~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
33simple_morph_t/v13_batch40_a94_v2Glyph Samplertext color from brightest 20 percent of maskbadge became a clean white panelvertical strips untouched by this fix~0.33 ยท 25 d ยท $0~2.8 ยท 69 h ยท $0~2.8 ยท 69 h ยท $28~3 ยท 65 h ยท $32~3 ยท 65 h ยท $78~3 ยท 65 h ยท $130~3 ยท 65 h ยท $194~3 ยท 65 h ยท $32~69 h (2.9 d)
34simple_morph_t/v14_batch40_a94_v2 โ˜…The Locked Reciperotations times three unioned, sampler, median patch, 0.94all 40 clean: badge gone, strip covered, text unreadablenone, locked as production default0.25 ยท 32 d ยท $02.34 ยท 3.5 d ยท $0~2.6 ยท 3.1 d ยท $30~2.8 ยท 69 h ยท $35~2.8 ยท 69 h ยท $83~2.8 ยท 69 h ยท $139~2.8 ยท 69 h ยท $208~2.8 ยท 69 h ยท $3583 h (3.5 d)
35simple_morph_t/v15_fast3_a94The Shortcut That Backfiredrotated passes YOLO only, OCR veto droppedhard case panel bled over the door edge, bbox x 165 to 24slower than v14, 470 vs 427 ms per image, and looser0.25 ยท 32 d ยท $02.13 ยท 3.8 d ยท $0~2.6 ยท 3.1 d ยท $30~2.8 ยท 69 h ยท $35~2.8 ยท 69 h ยท $83~2.8 ยท 69 h ยท $139~2.8 ยท 69 h ยท $208~2.8 ยท 69 h ยท $3591 h (3.8 d)
36manual_clean/v01Hand Build 1badge color fix built by hand on one imagebrightest 20 percent sampling killed the ghostmanual proof, single image~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
37manual_clean/v02Hand Build 2median patch painted before the panelghost strokes vanished completelymanual proof only~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
38manual_clean/v03Hand Build 3rotation union applied by handvertical strip fully covered at lastmanual proof only~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
39manual_clean/v04Hand Build 4cross image template extraction testedtemplates unstable across siblingsconfirmed inversion inputs impossible~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
40manual_clean/v05Hand Build 5refined alpha fitting attemptfits never converged inside the clamp ceilingexact recovery mathematically dead~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
41manual_clean/v06Hand Build 6patch guard limits calibrateddelta lum 15 and skip 210 chosen by eyeeyeballed values needed codifying~0.35 ยท 23 d ยท $0~3 ยท 65 h ยท $0~3 ยท 65 h ยท $26~3.2 ยท 61 h ยท $30~3.2 ยท 61 h ยท $73~3.2 ยท 61 h ยท $122~3.2 ยท 61 h ยท $182~3.2 ยท 61 h ยท $30~155 h (6.4 d)
42manual_clean/v07_invert_a28Inversion by Handinversion at measured alpha 0.28dark streaks againconfidently wrong pixels, worst failure type~28 ยท 7 h ยท $028 ยท 7 h ยท $028 ยท 7 h ยท $328 ยท 7 h ยท $328 ยท 7 h ยท $828 ยท 7 h ยท $1428 ยท 7 h ยท $2128 ยท 7 h ยท $3~7 h
43template_match_lama/v02_redditHybrid, Reddit Rulescommunity matching rules added to hybridbest wood grain continuation achieved anywhere localgrain still loses to the paid service~0.04 ยท 203 d ยท $0~0.45 ยท 18 d ยท $0~0.5 ยท 16 d ยท $156~0.55 ยท 15 d ยท $177~0.55 ยท 15 d ยท $424~0.55 ยท 15 d ยท $707~0.55 ยท 15 d ยท $1,061~0.55 ยท 15 d ยท $177~432 h (18 d)
44brushnet/v01Diffusion Challengerfree diffusion inpainting, 512 crops, 30 stepsmuddy slab with ghost text on badge, zero grain on woodlost every comparison at 20x the cost~0.005 ยท 1620 d ยท $00.105 ยท 77 d ยท $0~0.2 ยท 41 d ยท $389~0.3 ยท 27 d ยท $324~0.33 ยท 25 d ยท $707~0.4 ยท 20 d ยท $972~0.5 ยท 16 d ยท $1,167~0.4 ยท 20 d ยท $2431,852 h (77 d)
45simple_morph_t/v16_batch40_a94_v2Production Proofsame 40 images through the shipped stream_clean.pyoutputs match v14 within max diff 0.81, pure JPEG roundingnone, shipped0.25 ยท 32 d ยท $02.06 ยท 3.9 d ยท $0~2.6 ยท 3.1 d ยท $30~2.8 ยท 69 h ยท $35~2.8 ยท 69 h ยท $83~2.8 ยท 69 h ยท $139~2.8 ยท 69 h ยท $208~2.8 ยท 69 h ยท $3594 h (3.9 d)

The same forty five attempts ranked by success, best first. Throughput figures for each row are exactly the ones in the table above.

rankiterationnamewhat it achievedwhat it still lackedverdict
1simple_morph_t/v16_batch40_a94_v2Production Proofthe shipped CLI reproduced the winning recipe on all 40 images, max pixel diff 0.81 which is JPEG roundingnothingshipped
2simple_morph_t/v14_batch40_a94_v2 โ˜…The Locked Recipebadge ghost gone, vertical wardrobe strip fully covered, text unreadable at alpha 0.94 on all 40nothinglocked
3template_match_lama/v02_redditHybrid, Reddit Rulesbest grain continuation through erased strokes ever achieved locallygrain still loses to the paid service on woodproved concept
4simple_morph_t/v13_batch40_a94_v2Glyph Samplerpurple badge sampled near white instead of purple; ghost killedvertical strips still half coveredproved fix
5simple_morph_t/v11_alpha_ladderLadder Part Tworendered opacities 0.86 to 1.00; picked 0.94 as permanently unreadable yet watermark likenothing relevantproduced lock
6simple_morph_t/v10_alpha_ladderLadder Part Onerendered 0.40 to 0.85 and showed every panel traceable below 0.90upper half of the ladder unresolvedruled out half
7simple_morph_t/v12_batch40_a94The Fortyfirst complete end to end batch at 0.94 across 40 real imagespurple badge text ghosted through; vertical strip only half coveredexposed failures
8manual_clean/v01Hand Build 1proved brightest 20 percent sampling removes badge ghost on the test imageone image, by handproved fix
9manual_clean/v02Hand Build 2proved median patch before paint erases strokes under a matching panelone image, by handproved fix
10manual_clean/v03Hand Build 3proved rotation union covers the full vertical stripone image, by handproved fix
11manual_clean/v06Hand Build 6calibrated patch guards: replace above delta lum 15, skip above lum 210values chosen by eye, later codifiedcalibrated
12manual_clean/v04Hand Build 4showed cross image templates never align stablyclosed off the exact recovery input pathnegative result
13manual_clean/v05Hand Build 5showed alpha fits never converge inside clamp ceilingskilled per pixel inversion for goodnegative result
14simple_morph_t/v15_fast3_a94The Shortcut That Backfiredtested YOLO only rotated passes without the OCR vetoslower than v14, 470 vs 427 ms per image, and looser: panel bled over door edgerejected optimization
15simple_morph_t/v09_one_colorOne Color Panelachieved uniform single color panels per markwhich alpha to paint at was still unknownpartial
16simple_morph_t/v08_simple_transparentFirst Transparencyintroduced blend instead of opaque fillcolor basis too crude to match markspartial
17rect_algo/v07_glyph_masksGlyph Firsttested glyph sized panels against union boxesseams between letters made patchworkdead end
18simple_morph_t/v07Sticker Round 7best possible opaque sticker after six lessonsstill reads as pasted on, zero transparencysuperseded
19simple_morph_t/v06Sticker Round 6stabilized one box per mark via union strategyopacity untouchedsuperseded
20simple_morph_t/v05Sticker Round 5learned twin stamp merge behaviordouble boxes until mergedsuperseded
21simple_morph_t/v04Sticker Round 4swept padding values systematicallypadding is not why panels looked wrongsuperseded
22simple_morph_t/v03Sticker Round 3tried percentile color samplingmarginal change onlysuperseded
23simple_morph_t/v02Sticker Round 2tightened sampling region inside maskno visible improvementsuperseded
24simple_morph_t/v01Sticker Round 1first attempt: median fill over detection boxletters vanished completely; panel looked pasted onstarted everything
25rect_algo/v05_roundRounded Paneltested rounded corner aestheticsno coverage improvementdead end
26rect_algo/v04_triTriangle Ruletested triangular coverage shapescovered marks plus half the walldead end
27rect_algo/v02Geometry Sketch 2added aspect ratio priors to placementdrift reduced but never eliminateddead end
28rect_algo/v03Geometry Sketch 3snapped edges to scene linessnapped to window frames insteaddead end
29rect_algo/v01Geometry Sketch 1hand written placement offsetsboxes missed marks on varied aspect ratiosdead end
30clean_v5LaMa Generationbest inpainting era threshold generationfaint residue survived; invented fills unverifiablesuperseded
31clean_v4LaMa Generationwidened masks so fills cover glyph edgestexture areas blurred badlysuperseded
32clean_v2LaMa Generationraised OCR corroboration barreal faint marks skipped as stragglerssuperseded
33clean_v1LaMa Generationoriginal working detect and inpaint baselineinvented window fills, trust ceilingsuperseded
34template_match_lama/v01Hybrid First Passvalidated template match plus LaMa on flat markstextured marks poor, cost highpartial
35replicateTemplate Checkproved cross image alpha templates unusablesaved weeks of dead end worknegative result
36unmixDecomposition Trytested layer separation unmixingJPEG compression makes separation impossibledead end
37brushnet/v01Diffusion Challengerbenchmarked the best free diffusion inpainter honestlylost all three comparisons at 20x costnegative result
38rect_algo/v06_user_scriptBorrowed Scripttested community script geometry rulesits color basis assumes different watermarksdead end
39morph_simpleSimple Probecheapest morphology test firstthin strokes dropped, recall too lowdead end
40morphThe Probemorphology alone as mask sourceragged masks unusable downstreamdead end
41morph_v2Probe Second Cuttighter kernels for cleaner masksfaster but equally raggeddead end
42morph_transparentTransparent Probesoft alpha over morph maskshalos on every edgedead end
43exact_invert/v01_flatFlat Alpha Inversionsingle global alpha inversiondark streaks at stroke edgesconfidently wrong
44exact_invert/v02_perpixelPer Pixel Inversionper pixel alpha map inversionnoise amplified up to 30 timesconfidently wrong
45manual_clean/v07_invert_a28Inversion by Handinversion at measured alpha 0.28dark streaks again; looks plausible, is wrongconfidently wrong

Validation

The locked recipe processed 40 real listing images at 2.0 to 2.3 images per second, roughly four times the inpainting pipeline it replaced. Pixel comparison against the reference batch showed a maximum mean difference of 0.81, which is JPEG encoder rounding between different encoders. Zero images exceeded it.

That settles whether the recipe works. Whether it is good enough against outside competition is part four.

Next: What the rectangle could not beat.

This post is licensed under CC BY 4.0 by the author.