docs: note content-based strip routing + SDXL watermarker fixes

Document both fixes in CLAUDE.md (the metadata.py and watermark_remover.py
bullets). Also add a --backend flag to the visible-removal audit script so a
realistic quality pass can run the production MI-GAN fill instead of cv2
(removal SUCCESS is backend-independent, but only migan/lama reflect the
recovered-region quality a user actually gets).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Victor Kuznetsov
2026-07-14 17:16:56 +03:00
co-authored by Claude Opus 4.8
parent 183793fbf2
commit 9fe12c3997
2 changed files with 16 additions and 4 deletions
+2 -2
View File
File diff suppressed because one or more lines are too long
+14 -2
View File
@@ -10,6 +10,11 @@ NOT sufficient (their NCC detector is fooled by a thin residual outline -- see
CLAUDE.md). Treat a detector-clean Doubao/Jimeng as "detector passes"; visual
residual is a separate check.
Backend: for a REALISTIC quality audit pass ``--backend migan`` (the production
fill), not ``cv2``. Removal SUCCESS (detector-clean) is backend-independent, so cv2
is fine for a fast pass/fail sweep, but only migan/lama reflect the recovered-region
quality a user actually gets. Run migan when validating the visible pipeline for real.
Operates on gitignored data only (data/spaces/...); writes nothing tracked.
uv run python scripts/visible_removal_audit.py \
@@ -54,7 +59,14 @@ def _rel(p: Path, corpus: Path) -> str:
help="Audit only these paths (one per line), skipping the full rglob.",
)
@click.option("--limit", type=int, default=0, help="Scan at most N files (0 = all).")
def main(corpus: Path, out: Path, dataset_root: Path, paths_file: Path | None, limit: int) -> None:
@click.option(
"--backend",
type=click.Choice(["auto", "cv2", "migan", "lama"]),
default="auto",
help="Fill backend for removal. Removal SUCCESS (detector-clean) is backend-independent; "
"cv2 is fastest for a bulk audit, migan/lama only change recovered-region quality.",
)
def main(corpus: Path, out: Path, dataset_root: Path, paths_file: Path | None, limit: int, backend: str) -> None:
logging.basicConfig(level=logging.WARNING, format="%(message)s")
if paths_file is not None:
files = [Path(s) for line in paths_file.read_text().splitlines() if (s := line.strip()) and Path(s).is_file()]
@@ -86,7 +98,7 @@ def main(corpus: Path, out: Path, dataset_root: Path, paths_file: Path | None, l
shutil.copy2(p, ddir / p.name)
# Remove, then re-detect with the SAME mark's detector.
try:
cleaned, _ = mark.remove(img)
cleaned, _ = mark.remove(img, backend=backend)
after = mark.detect(cleaned)
except Exception as exc:
log.warning("remove failed on %s (%s): %s", p.name, det.key, exc)