feat(auto): adaptive detail-targeting polish + --adaptive-polish flag

The fixed mild auto polish (unsharp 0.5 / grain 2.0) under-corrected soft
photo/face output (gemini_3 stayed at lap-var 84 vs its 592 original) and its
grain speckled small text. Replace it with humanizer.adaptive_polish: target the
input's Laplacian variance with a capped unsharp scaled to the deficit + edge-
masked grain (smooth regions only), calibrated by a short sigma search. Self-
limiting on text/graphics -- already high-frequency, so almost no polish lands
and text edges are masked out. Validated on the spaces corpus (gemini_3 84 -> 334
end-to-end; openai_1 text near-untouched).

Interface: every --auto decision is now independently overridable -- add
--adaptive-polish/--no-adaptive-polish (matching --restore-faces; works without
--auto too) so the polish can be disabled or used manually. _apply_auto overrides
exactly the three content-adaptive modes (pipeline, restore-faces, adaptive-
polish); --unsharp/--humanize stay independent fixed filters.

cv2-only, no new deps. Threaded through invisible/all (not batch).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Victor Kuznetsov
2026-06-03 21:49:08 -07:00
co-authored by Claude Opus 4.8
parent 9bd2c17cc4
commit b686dbdd79
8 changed files with 223 additions and 44 deletions
+9 -6
View File
@@ -45,7 +45,8 @@ class TestPlan:
assert cfg is not None
assert cfg.pipeline == "default" # structure-less -> plain SDXL
assert cfg.restore_faces is False
assert cfg.unsharp == 0.0 # no smoothing pass -> no polish
assert cfg.adaptive_polish is False # no smoothing pass -> no polish
assert cfg.unsharp == 0.0
assert cfg.humanize == 0.0
assert cfg.min_resolution == 1024
@@ -65,8 +66,9 @@ class TestPlan:
assert cfg.has_face
assert cfg.restore_faces
assert cfg.pipeline == "controlnet"
assert cfg.unsharp == 0.5 # smoothing pass ran -> polish on
assert cfg.humanize == 2.0
assert cfg.adaptive_polish # smoothing pass ran -> adaptive polish on
assert cfg.unsharp == 0.0 # fixed knobs off; the adaptive polish replaces them
assert cfg.humanize == 0.0
def test_text_signal_forces_controlnet_on_flat(self, tmp_path, monkeypatch):
monkeypatch.setattr(auto_config, "detect_text", lambda _img: True)
@@ -82,8 +84,9 @@ class TestReason:
cfg = auto_config.AutoConfig(
pipeline="controlnet",
restore_faces=True,
unsharp=0.5,
humanize=2.0,
adaptive_polish=True,
unsharp=0.0,
humanize=0.0,
min_resolution=1024,
has_face=True,
has_text=False,
@@ -95,4 +98,4 @@ class TestReason:
assert "controlnet" in r
assert "face" in r
assert "face-restore on" in r
assert "unsharp 0.5" in r
assert "adaptive polish" in r