Document the two repixelization engines
This commit is contained in:
parent
68a45359f9
commit
f95440351c
5 changed files with 241 additions and 8 deletions
|
|
@ -20,7 +20,7 @@ class RenderedPanel:
|
|||
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Regenerate the README comparison sheet and guard closeup from repo fixtures.")
|
||||
parser = argparse.ArgumentParser(description="Regenerate the README comparison sheets and closeups from repo fixtures.")
|
||||
parser.add_argument(
|
||||
"--vector-input",
|
||||
default="tests/fixtures/real/ai-badge-vector.png",
|
||||
|
|
@ -41,6 +41,11 @@ def _parse_args() -> argparse.Namespace:
|
|||
default="docs/readme-assets/guard-right-crop-comparison.png",
|
||||
help="Output path for the standalone sword-guard closeup strip.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-engine-sheet",
|
||||
default="docs/readme-assets/engine-comparison-sheet.png",
|
||||
help="Output path for the pinned phase-field vs tile-graph engine comparison sheet.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--scratch-dir",
|
||||
default="artifacts/readme-build",
|
||||
|
|
@ -60,6 +65,38 @@ def _parse_args() -> argparse.Namespace:
|
|||
metavar=("X0", "Y0", "X1", "Y1"),
|
||||
help="Sword-guard crop bounds in output-grid cell coordinates for the AI row.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--engine-target-width",
|
||||
type=int,
|
||||
default=126,
|
||||
help="Pinned target width for the engine-vs-engine badge comparison.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--engine-target-height",
|
||||
type=int,
|
||||
default=126,
|
||||
help="Pinned target height for the engine-vs-engine badge comparison.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--engine-phase-x",
|
||||
type=float,
|
||||
default=0.0,
|
||||
help="Pinned lattice phase X for the engine-vs-engine badge comparison.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--engine-phase-y",
|
||||
type=float,
|
||||
default=-0.2,
|
||||
help="Pinned lattice phase Y for the engine-vs-engine badge comparison.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--engine-cell-bbox",
|
||||
nargs=4,
|
||||
type=int,
|
||||
default=(67, 90, 97, 122),
|
||||
metavar=("X0", "Y0", "X1", "Y1"),
|
||||
help="Tracked sword-tip crop bounds in output-grid cell coordinates for the pinned engine comparison.",
|
||||
)
|
||||
parser.add_argument("--steps", type=int, default=48, help="Optimizer step budget for both runs.")
|
||||
parser.add_argument("--device", default="cpu", choices=("auto", "cpu", "cuda"), help="Torch device for generation.")
|
||||
return parser.parse_args()
|
||||
|
|
@ -247,6 +284,135 @@ def _save_summary(path: Path, payload: dict[str, object]) -> None:
|
|||
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
||||
|
||||
|
||||
def _build_engine_comparison_sheet(
|
||||
*,
|
||||
source_rgba: np.ndarray,
|
||||
phase_field_rgba: np.ndarray,
|
||||
tile_graph_rgba: np.ndarray,
|
||||
focus_source_bbox: tuple[int, int, int, int],
|
||||
focus_cell_bbox: tuple[int, int, int, int],
|
||||
target_width: int,
|
||||
target_height: int,
|
||||
phase_x: float,
|
||||
phase_y: float,
|
||||
) -> Image.Image:
|
||||
top_panel_width = 320
|
||||
top_panel_height = 338
|
||||
crop_panel_width = 240
|
||||
crop_panel_height = 210
|
||||
col_gap = 18
|
||||
row_gap = 18
|
||||
margin = 24
|
||||
title_height = 24
|
||||
row_title_height = 20
|
||||
|
||||
top_panels = [
|
||||
_render_panel(
|
||||
"Source",
|
||||
rgba=source_rgba,
|
||||
pixelated=False,
|
||||
panel_width=top_panel_width,
|
||||
panel_height=top_panel_height,
|
||||
subtitle="Cleaned AI fake pixel badge",
|
||||
),
|
||||
_render_panel(
|
||||
"Phase-field",
|
||||
rgba=phase_field_rgba,
|
||||
pixelated=True,
|
||||
panel_width=top_panel_width,
|
||||
panel_height=top_panel_height,
|
||||
subtitle=f"{target_width}x{target_height} pinned lattice",
|
||||
),
|
||||
_render_panel(
|
||||
"Tile-graph",
|
||||
rgba=tile_graph_rgba,
|
||||
pixelated=True,
|
||||
panel_width=top_panel_width,
|
||||
panel_height=top_panel_height,
|
||||
subtitle=f"{target_width}x{target_height} pinned lattice",
|
||||
),
|
||||
]
|
||||
_draw_source_bbox(
|
||||
top_panels[0],
|
||||
focus_source_bbox,
|
||||
source_width=source_rgba.shape[1],
|
||||
source_height=source_rgba.shape[0],
|
||||
)
|
||||
_draw_source_bbox(
|
||||
top_panels[1],
|
||||
focus_cell_bbox,
|
||||
source_width=phase_field_rgba.shape[1],
|
||||
source_height=phase_field_rgba.shape[0],
|
||||
)
|
||||
_draw_source_bbox(
|
||||
top_panels[2],
|
||||
focus_cell_bbox,
|
||||
source_width=tile_graph_rgba.shape[1],
|
||||
source_height=tile_graph_rgba.shape[0],
|
||||
)
|
||||
|
||||
crop_panels = [
|
||||
_render_panel(
|
||||
"Source focus",
|
||||
rgba=_crop_rgba(source_rgba, focus_source_bbox),
|
||||
pixelated=True,
|
||||
panel_width=crop_panel_width,
|
||||
panel_height=crop_panel_height,
|
||||
subtitle="Tracked sword-tip crop",
|
||||
),
|
||||
_render_panel(
|
||||
"Phase-field focus",
|
||||
rgba=_crop_rgba(phase_field_rgba, focus_cell_bbox),
|
||||
pixelated=True,
|
||||
panel_width=crop_panel_width,
|
||||
panel_height=crop_panel_height,
|
||||
subtitle="Default optimizer",
|
||||
),
|
||||
_render_panel(
|
||||
"Tile-graph focus",
|
||||
rgba=_crop_rgba(tile_graph_rgba, focus_cell_bbox),
|
||||
pixelated=True,
|
||||
panel_width=crop_panel_width,
|
||||
panel_height=crop_panel_height,
|
||||
subtitle="Source-owned alternate solver",
|
||||
),
|
||||
]
|
||||
|
||||
width = margin * 2 + top_panel_width * 3 + col_gap * 2
|
||||
height = (
|
||||
margin * 2
|
||||
+ title_height
|
||||
+ row_title_height * 2
|
||||
+ top_panel_height
|
||||
+ crop_panel_height
|
||||
+ row_gap
|
||||
)
|
||||
canvas = Image.new("RGBA", (width, height), (11, 11, 13, 255))
|
||||
draw = ImageDraw.Draw(canvas)
|
||||
draw.text(
|
||||
(margin, margin - 2),
|
||||
f"Pinned badge lattice: {target_width}x{target_height} @ ({phase_x:.1f}, {phase_y:.1f})",
|
||||
fill=(255, 255, 255, 255),
|
||||
)
|
||||
draw.text((margin, margin + title_height), "Whole image", fill=(255, 255, 255, 255))
|
||||
top_y = margin + title_height + row_title_height
|
||||
crop_row_y = top_y + top_panel_height + row_gap
|
||||
draw.text((margin, crop_row_y), "Tracked sword-tip crop", fill=(255, 255, 255, 255))
|
||||
crop_y = crop_row_y + row_title_height
|
||||
|
||||
x = margin
|
||||
for panel in top_panels:
|
||||
canvas.alpha_composite(panel.image, (x, top_y))
|
||||
x += top_panel_width + col_gap
|
||||
|
||||
x = margin
|
||||
for panel in crop_panels:
|
||||
canvas.alpha_composite(panel.image, (x, crop_y))
|
||||
x += crop_panel_width + col_gap
|
||||
|
||||
return canvas
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = _parse_args()
|
||||
scratch_dir = Path(args.scratch_dir)
|
||||
|
|
@ -256,8 +422,10 @@ def main() -> None:
|
|||
ai_input = Path(args.ai_input)
|
||||
out_sheet = Path(args.out_sheet)
|
||||
out_guard_crop = Path(args.out_guard_crop)
|
||||
out_engine_sheet = Path(args.out_engine_sheet)
|
||||
out_sheet.parent.mkdir(parents=True, exist_ok=True)
|
||||
out_guard_crop.parent.mkdir(parents=True, exist_ok=True)
|
||||
out_engine_sheet.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
vector_result = run_pipeline(
|
||||
vector_input,
|
||||
|
|
@ -274,6 +442,32 @@ def main() -> None:
|
|||
steps=args.steps,
|
||||
device=args.device,
|
||||
)
|
||||
phase_field_engine_result = run_pipeline(
|
||||
ai_input,
|
||||
scratch_dir / "badge-ai-phase-field-pinned.png",
|
||||
target_width=args.engine_target_width,
|
||||
target_height=args.engine_target_height,
|
||||
phase_x=args.engine_phase_x,
|
||||
phase_y=args.engine_phase_y,
|
||||
diagnostics_dir=scratch_dir / "engine-phase-field-diag",
|
||||
steps=args.steps,
|
||||
device=args.device,
|
||||
reconstruction_mode="phase-field",
|
||||
enable_phase_rerank=False,
|
||||
)
|
||||
tile_graph_engine_result = run_pipeline(
|
||||
ai_input,
|
||||
scratch_dir / "badge-ai-tile-graph-pinned.png",
|
||||
target_width=args.engine_target_width,
|
||||
target_height=args.engine_target_height,
|
||||
phase_x=args.engine_phase_x,
|
||||
phase_y=args.engine_phase_y,
|
||||
diagnostics_dir=scratch_dir / "engine-tile-graph-diag",
|
||||
steps=args.steps,
|
||||
device=args.device,
|
||||
reconstruction_mode="tile-graph",
|
||||
enable_phase_rerank=False,
|
||||
)
|
||||
|
||||
vector_source = load_rgba(vector_input)
|
||||
ai_source = load_rgba(ai_input)
|
||||
|
|
@ -430,6 +624,26 @@ def main() -> None:
|
|||
out_sheet.parent.mkdir(parents=True, exist_ok=True)
|
||||
canvas.save(out_sheet)
|
||||
|
||||
engine_focus_source_bbox = _cell_bbox_to_source_bbox(
|
||||
tuple(args.engine_cell_bbox),
|
||||
source_width=ai_source.shape[1],
|
||||
source_height=ai_source.shape[0],
|
||||
target_width=args.engine_target_width,
|
||||
target_height=args.engine_target_height,
|
||||
)
|
||||
engine_sheet = _build_engine_comparison_sheet(
|
||||
source_rgba=ai_source,
|
||||
phase_field_rgba=phase_field_engine_result.output_rgba,
|
||||
tile_graph_rgba=tile_graph_engine_result.output_rgba,
|
||||
focus_source_bbox=engine_focus_source_bbox,
|
||||
focus_cell_bbox=tuple(args.engine_cell_bbox),
|
||||
target_width=args.engine_target_width,
|
||||
target_height=args.engine_target_height,
|
||||
phase_x=args.engine_phase_x,
|
||||
phase_y=args.engine_phase_y,
|
||||
)
|
||||
engine_sheet.save(out_engine_sheet)
|
||||
|
||||
_save_summary(
|
||||
scratch_dir / "readme-preview-summary.json",
|
||||
{
|
||||
|
|
@ -443,14 +657,22 @@ def main() -> None:
|
|||
"vector_guard_inset_source_bbox": list(vector_guard_inset_bbox),
|
||||
"guard_source_bbox": list(guard_bbox),
|
||||
"ai_guard_inset_source_bbox": list(ai_guard_inset_bbox),
|
||||
"engine_target_width": args.engine_target_width,
|
||||
"engine_target_height": args.engine_target_height,
|
||||
"engine_phase_x": args.engine_phase_x,
|
||||
"engine_phase_y": args.engine_phase_y,
|
||||
"engine_cell_bbox": list(args.engine_cell_bbox),
|
||||
"engine_focus_source_bbox": list(engine_focus_source_bbox),
|
||||
"out_sheet": str(out_sheet),
|
||||
"out_guard_crop": str(out_guard_crop),
|
||||
"out_engine_sheet": str(out_engine_sheet),
|
||||
"scratch_dir": str(scratch_dir),
|
||||
},
|
||||
)
|
||||
|
||||
print(str(out_sheet))
|
||||
print(str(out_guard_crop))
|
||||
print(str(out_engine_sheet))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Reference in a new issue