File size: 3,259 Bytes
1a12965
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/usr/bin/env python
"""Generate samples with multiple random degradations stacked on one template.

Unlike scripts/generate_degradation_gallery.py (which isolates exactly one
effect per sample for comparison), this uses the realistic "varied batch"
probabilities from configs/generate.yaml unmodified -- every enabled effect
independently rolls its own probability per sample, so different samples end
up with different *combinations* of simultaneously-applied degradations, all
on the same template/box for a fair before/after comparison.

Each output image is the standard metrics visualization (full page, crop,
ink mask, coverage metrics, difficulty breakdown) plus a caption band listing
exactly which effects fired for that sample.

Usage:
    python scripts/generate_multiple_degradation_gallery.py
"""

from __future__ import annotations

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from PIL import Image, ImageDraw, ImageFont

from src.config.loader import load_config
from src.generator import GeneratorContext
from src.visualization.visualizer import save_visualization

ROOT = Path(__file__).resolve().parents[1]
OUT_DIR = ROOT / "multiple_degradation"
N_SAMPLES = 10
TEMPLATE_ID = "bank_doc_05"  # same template used in the single-effect gallery


def _load_font(size: int) -> "ImageFont.FreeTypeFont | ImageFont.ImageFont":
    for candidate in (r"C:\Windows\Fonts\consola.ttf", r"C:\Windows\Fonts\arial.ttf"):
        if Path(candidate).exists():
            return ImageFont.truetype(candidate, size)
    return ImageFont.load_default()


def _annotate_applied_effects(path: Path, metadata: dict) -> list[str]:
    effects = metadata["augmentation"]["effects"]
    applied = [name for name, rec in effects.items() if rec["applied"]]
    difficulty = metadata["difficulty"]

    caption = (
        f"{metadata['document_id']}  |  applied degradations "
        f"({len(applied)}/{len(effects)}): {', '.join(applied) if applied else 'none'}"
        f"   |   difficulty = {difficulty['score']:.3f} ({difficulty['tier']})"
    )

    img = Image.open(path).convert("RGB")
    band_h = 40
    canvas = Image.new("RGB", (img.width, img.height + band_h), "white")
    canvas.paste(img, (0, band_h))
    draw = ImageDraw.Draw(canvas)
    font = _load_font(16)
    draw.rectangle([0, 0, canvas.width, band_h], fill=(15, 42, 67))
    draw.text((14, 11), caption, fill="white", font=font)
    canvas.save(path)
    return applied


def main() -> None:
    OUT_DIR.mkdir(parents=True, exist_ok=True)

    overrides = [
        f"document.template={TEMPLATE_ID}",
        "generation.run_validation=false",
    ]
    config = load_config(config_path=ROOT / "configs" / "generate.yaml", overrides=overrides)
    ctx = GeneratorContext(config)

    for i in range(1, N_SAMPLES + 1):
        metadata, final_image, _ = ctx.run_sample(i)
        out_path = OUT_DIR / f"sample_{i}.png"
        save_visualization(out_path, final_image, metadata)
        applied = _annotate_applied_effects(out_path, metadata)
        print(f"[sample_{i}] {len(applied)} effects applied -> {', '.join(applied) or 'none'}")

    print(f"\nWrote {N_SAMPLES} samples -> {OUT_DIR}")


if __name__ == "__main__":
    main()