""" Find representative task samples at three difficulty levels from the dataset. Easy : 3–4 elements, noise=0.05 Medium : 5–7 elements, noise=0.10 Hard : 7–10 elements, noise=0.15 Writes dataset/task_samples.json for inference.py, copies referenced PNGs into dataset/sample_images/, and rewrites image_path / layer_image_path in the JSON to point at sample_images/ (paths relative to the dataset directory). For each sample background, copies the matching saliency array from dataset/saliency_images/ into dataset/sample_saliency_images/ and sets sample["saliency_image_path"] (e.g. sample_saliency_images/3960_bg.npy). Run preprocess_saliency.py first so those .npy files exist. """ from __future__ import annotations import copy import json import random import shutil import sys from pathlib import Path SCRIPT_DIR = Path(__file__).resolve().parent DATASET_JSON = SCRIPT_DIR / "genposter_5000_images.json" OUTPUT_JSON = SCRIPT_DIR / "task_samples.json" SAMPLE_IMAGES_DIR = SCRIPT_DIR / "sample_images" SAMPLE_IMAGES_PREFIX = "sample_images" SAMPLE_SALIENCY_DIR = SCRIPT_DIR / "sample_saliency_images" SAMPLE_SALIENCY_PREFIX = "sample_saliency_images" SALIENCY_SOURCE_DIR = SCRIPT_DIR / "saliency_images" TASKS = [ { "task_id": "easy", "min_elements": 3, "max_elements": 4, "noise": 0.05, "max_steps": 50, }, { "task_id": "medium", "min_elements": 5, "max_elements": 7, "noise": 0.10, "max_steps": 100, }, { "task_id": "hard", "min_elements": 7, "max_elements": 10, "noise": 0.15, "max_steps": 200, }, ] def _copy_and_remap_path( rel: str, sample_images_dir: Path, dataset_root: Path, missing: list[str], ) -> str: name = Path(rel).name src = (dataset_root / rel).resolve() if not src.is_file(): missing.append(rel) return f"{SAMPLE_IMAGES_PREFIX}/{name}" dest = sample_images_dir / name shutil.copy2(src, dest) return f"{SAMPLE_IMAGES_PREFIX}/{name}" def _copy_saliency_for_background( sample: dict, *, sample_saliency_dir: Path, saliency_source_dir: Path, missing: list[str], ) -> None: """Match preprocess_saliency output: saliency_images/.npy""" sample.pop("saliency_image_path", None) ip = sample.get("image_path") if not ip: return sal_name = f"{Path(ip).stem}.npy" src = (saliency_source_dir / sal_name).resolve() if not src.is_file(): missing.append(f"saliency_images/{sal_name}") return sample_saliency_dir.mkdir(parents=True, exist_ok=True) dest = sample_saliency_dir / sal_name shutil.copy2(src, dest) sample["saliency_image_path"] = f"{SAMPLE_SALIENCY_PREFIX}/{sal_name}" def copy_media_and_rewrite_paths( output: list[dict], *, sample_images_dir: Path = SAMPLE_IMAGES_DIR, sample_saliency_dir: Path = SAMPLE_SALIENCY_DIR, saliency_source_dir: Path = SALIENCY_SOURCE_DIR, dataset_root: Path = SCRIPT_DIR, ) -> None: if sample_images_dir.exists(): shutil.rmtree(sample_images_dir) sample_images_dir.mkdir(parents=True) if sample_saliency_dir.exists(): shutil.rmtree(sample_saliency_dir) sample_saliency_dir.mkdir(parents=True) missing: list[str] = [] saliency_missing: list[str] = [] for entry in output: sample = entry["sample"] ip = sample.get("image_path") if ip: sample["image_path"] = _copy_and_remap_path( ip, sample_images_dir, dataset_root, missing ) for el in sample.get("elements") or []: lp = el.get("layer_image_path") if lp: el["layer_image_path"] = _copy_and_remap_path( lp, sample_images_dir, dataset_root, missing ) _copy_saliency_for_background( sample, sample_saliency_dir=sample_saliency_dir, saliency_source_dir=saliency_source_dir, missing=saliency_missing, ) if missing: for m in missing: print(f"WARNING: missing source file: {dataset_root / m}", file=sys.stderr) if saliency_missing: for m in saliency_missing: print( f"WARNING: missing saliency map (run preprocess_saliency.py): " f"{dataset_root / m}", file=sys.stderr, ) def main() -> None: with open(DATASET_JSON, "r", encoding="utf-8") as f: dataset = json.load(f) rng = random.Random(42) output: list[dict] = [] for task in TASKS: candidates = [ s for s in dataset if task["min_elements"] <= len(s.get("elements", [])) <= task["max_elements"] and s.get("image_path") ] if not candidates: candidates = [ s for s in dataset if task["min_elements"] <= len(s.get("elements", [])) <= task["max_elements"] ] if not candidates: print( f"WARNING: No samples found for task '{task['task_id']}' " f"({task['min_elements']}–{task['max_elements']} elements). Skipping." ) continue chosen = rng.choice(candidates) output.append( { "task_id": task["task_id"], "noise": task["noise"], "max_steps": task["max_steps"], "sample": copy.deepcopy(chosen), } ) print( f" {task['task_id']:8s} id={chosen['id']:<6} " f"elements={len(chosen['elements'])} noise={task['noise']}" ) copy_media_and_rewrite_paths(output) with open(OUTPUT_JSON, "w", encoding="utf-8") as f: json.dump(output, f, indent=2) print(f"\nCopied media to {SAMPLE_IMAGES_DIR}") print(f"Copied saliency arrays (.npy) to {SAMPLE_SALIENCY_DIR}") print(f"Saved {len(output)} task samples to {OUTPUT_JSON}") if __name__ == "__main__": main()