568 lines
21 KiB
Python
568 lines
21 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
from PIL import Image, ImageDraw
|
|
|
|
from repixelizer.baselines import lanczos_resize_baseline
|
|
from repixelizer.io import load_rgba, save_rgba
|
|
from repixelizer.pipeline import run_pipeline
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class RenderedPanel:
|
|
image: Image.Image
|
|
content_box: tuple[int, int, int, int]
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class PreviewRow:
|
|
row_id: str
|
|
title: str
|
|
source_rgba: np.ndarray
|
|
source_subtitle: str
|
|
lanczos_rgba: np.ndarray
|
|
lanczos_subtitle: str
|
|
phase_field_rgba: np.ndarray
|
|
phase_field_subtitle: str
|
|
target_width: int
|
|
target_height: int
|
|
focus_cell_bbox: tuple[int, int, int, int]
|
|
|
|
|
|
def _parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="Regenerate the README comparison sheet and closeups from repo fixtures.")
|
|
parser.add_argument(
|
|
"--input",
|
|
default="tests/fixtures/real/ai-badge-cleaned.png",
|
|
help="Cleaned AI fake-pixel badge source.",
|
|
)
|
|
parser.add_argument(
|
|
"--out-sheet",
|
|
default="docs/readme-assets/badge-example-sheet.png",
|
|
help="Output path for the full README comparison sheet.",
|
|
)
|
|
parser.add_argument(
|
|
"--out-guard-crop",
|
|
default="docs/readme-assets/guard-right-crop-comparison.png",
|
|
help="Output path for the standalone sword-guard closeup strip.",
|
|
)
|
|
parser.add_argument(
|
|
"--scratch-dir",
|
|
default="artifacts/readme-build",
|
|
help="Directory for intermediate low-res outputs and diagnostics.",
|
|
)
|
|
parser.add_argument(
|
|
"--dense-input",
|
|
default="tests/fixtures/real/dense-landscape.png",
|
|
help="Dense high-resolution pixel-art source used for the second README row.",
|
|
)
|
|
parser.add_argument(
|
|
"--dense-phase-field-output",
|
|
default="",
|
|
help="Optional existing dense landscape output. If omitted, the dense row is regenerated with automatic lattice inference.",
|
|
)
|
|
parser.add_argument(
|
|
"--guard-cell-bbox",
|
|
nargs=4,
|
|
type=int,
|
|
default=(73, 20, 107, 44),
|
|
metavar=("X0", "Y0", "X1", "Y1"),
|
|
help="Sword-guard crop bounds in output-grid cell coordinates for the AI row.",
|
|
)
|
|
parser.add_argument(
|
|
"--dense-focus-cell-bbox",
|
|
nargs=4,
|
|
type=int,
|
|
default=(44, 396, 124, 476),
|
|
metavar=("X0", "Y0", "X1", "Y1"),
|
|
help="Focus crop bounds in output-grid cell coordinates for the dense landscape row.",
|
|
)
|
|
parser.add_argument(
|
|
"--target-width",
|
|
type=int,
|
|
default=126,
|
|
help="Pinned target width for the canonical badge comparison.",
|
|
)
|
|
parser.add_argument(
|
|
"--target-height",
|
|
type=int,
|
|
default=126,
|
|
help="Pinned target height for the canonical badge comparison.",
|
|
)
|
|
parser.add_argument(
|
|
"--dense-target-width",
|
|
type=int,
|
|
default=512,
|
|
help="Fallback target width used only when --dense-phase-field-output is supplied.",
|
|
)
|
|
parser.add_argument(
|
|
"--dense-target-height",
|
|
type=int,
|
|
default=512,
|
|
help="Fallback target height used only when --dense-phase-field-output is supplied.",
|
|
)
|
|
parser.add_argument(
|
|
"--dense-auto-inferred-width",
|
|
type=int,
|
|
default=418,
|
|
help="Deprecated display fallback for old fixed-output runs.",
|
|
)
|
|
parser.add_argument(
|
|
"--dense-auto-inferred-height",
|
|
type=int,
|
|
default=418,
|
|
help="Deprecated display fallback for old fixed-output runs.",
|
|
)
|
|
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()
|
|
|
|
|
|
def _to_image(rgba: np.ndarray) -> Image.Image:
|
|
rgba8 = np.clip(np.rint(rgba * 255.0), 0, 255).astype(np.uint8)
|
|
return Image.fromarray(rgba8, mode="RGBA")
|
|
|
|
|
|
def _checkerboard(width: int, height: int, tile: int = 12) -> Image.Image:
|
|
image = Image.new("RGBA", (width, height), (236, 236, 236, 255))
|
|
draw = ImageDraw.Draw(image)
|
|
accent = (218, 218, 218, 255)
|
|
for y in range(0, height, tile):
|
|
for x in range(0, width, tile):
|
|
if ((x // tile) + (y // tile)) % 2:
|
|
draw.rectangle((x, y, min(width, x + tile), min(height, y + tile)), fill=accent)
|
|
return image
|
|
|
|
|
|
def _fit_rgba(
|
|
rgba: np.ndarray,
|
|
*,
|
|
target_width: int,
|
|
target_height: int,
|
|
pixelated: bool,
|
|
) -> tuple[Image.Image, tuple[int, int, int, int]]:
|
|
image = _to_image(rgba)
|
|
scale = min(target_width / max(1, image.width), target_height / max(1, image.height))
|
|
resized_width = max(1, int(round(image.width * scale)))
|
|
resized_height = max(1, int(round(image.height * scale)))
|
|
resample = Image.Resampling.NEAREST if pixelated else Image.Resampling.LANCZOS
|
|
resized = image.resize((resized_width, resized_height), resample=resample)
|
|
offset_x = (target_width - resized_width) // 2
|
|
offset_y = (target_height - resized_height) // 2
|
|
return resized, (offset_x, offset_y, resized_width, resized_height)
|
|
|
|
|
|
def _render_panel(
|
|
label: str,
|
|
*,
|
|
rgba: np.ndarray,
|
|
pixelated: bool,
|
|
panel_width: int,
|
|
panel_height: int,
|
|
subtitle: str | None = None,
|
|
) -> RenderedPanel:
|
|
header_height = 38 if subtitle else 28
|
|
gutter = 10
|
|
canvas = Image.new("RGBA", (panel_width, panel_height), (18, 18, 20, 255))
|
|
checker = _checkerboard(panel_width - gutter * 2, panel_height - header_height - gutter * 2)
|
|
canvas.alpha_composite(checker, (gutter, header_height + gutter))
|
|
|
|
fitted, (inner_x, inner_y, inner_w, inner_h) = _fit_rgba(
|
|
rgba,
|
|
target_width=checker.width,
|
|
target_height=checker.height,
|
|
pixelated=pixelated,
|
|
)
|
|
content_x = gutter + inner_x
|
|
content_y = header_height + gutter + inner_y
|
|
canvas.alpha_composite(fitted, (content_x, content_y))
|
|
|
|
draw = ImageDraw.Draw(canvas)
|
|
draw.text((gutter, 6), label, fill=(255, 255, 255, 255))
|
|
if subtitle:
|
|
draw.text((gutter, 22), subtitle, fill=(200, 200, 200, 255))
|
|
draw.rounded_rectangle((0, 0, panel_width - 1, panel_height - 1), radius=10, outline=(72, 72, 80, 255), width=1)
|
|
return RenderedPanel(canvas, (content_x, content_y, inner_w, inner_h))
|
|
|
|
|
|
def _draw_source_bbox(render: RenderedPanel, source_bbox: tuple[int, int, int, int], *, source_width: int, source_height: int) -> None:
|
|
x0, y0, x1, y1 = source_bbox
|
|
inner_x, inner_y, inner_w, inner_h = render.content_box
|
|
left = inner_x + int(round(inner_w * (x0 / max(1, source_width))))
|
|
right = inner_x + int(round(inner_w * (x1 / max(1, source_width))))
|
|
top = inner_y + int(round(inner_h * (y0 / max(1, source_height))))
|
|
bottom = inner_y + int(round(inner_h * (y1 / max(1, source_height))))
|
|
draw = ImageDraw.Draw(render.image)
|
|
for delta, color in ((0, (255, 245, 120, 255)), (1, (20, 20, 20, 255))):
|
|
draw.rectangle((left - delta, top - delta, right + delta, bottom + delta), outline=color, width=1)
|
|
|
|
|
|
def _build_guard_strip(
|
|
source_crop: np.ndarray,
|
|
lanczos_crop: np.ndarray,
|
|
repixelized_crop: np.ndarray,
|
|
*,
|
|
include_lanczos: bool = True,
|
|
panel_width: int = 220,
|
|
panel_height: int = 170,
|
|
title: str | None = "Sword guard close-up",
|
|
) -> Image.Image:
|
|
panels = [
|
|
_render_panel("Source", rgba=source_crop, pixelated=True, panel_width=panel_width, panel_height=panel_height),
|
|
_render_panel("Repixelized", rgba=repixelized_crop, pixelated=True, panel_width=panel_width, panel_height=panel_height),
|
|
]
|
|
if include_lanczos:
|
|
panels.insert(
|
|
1,
|
|
_render_panel("Lanczos", rgba=lanczos_crop, pixelated=True, panel_width=panel_width, panel_height=panel_height),
|
|
)
|
|
title_height = 24 if title else 0
|
|
gap = 10
|
|
width = sum(panel.image.width for panel in panels) + gap * (len(panels) + 1)
|
|
height = title_height + max(panel.image.height for panel in panels) + gap * 2
|
|
canvas = Image.new("RGBA", (width, height), (14, 14, 16, 242))
|
|
draw = ImageDraw.Draw(canvas)
|
|
draw.rounded_rectangle((0, 0, width - 1, height - 1), radius=12, fill=(14, 14, 16, 242), outline=(92, 92, 104, 255), width=1)
|
|
if title:
|
|
draw.text((gap, 4), title, fill=(255, 255, 255, 255))
|
|
x = gap
|
|
for panel in panels:
|
|
canvas.alpha_composite(panel.image, (x, title_height + gap))
|
|
x += panel.image.width + gap
|
|
return canvas
|
|
|
|
|
|
def _build_pip_inset(
|
|
rgba_crop: np.ndarray,
|
|
*,
|
|
width: int = 126,
|
|
height: int = 94,
|
|
) -> Image.Image:
|
|
fitted, (inner_x, inner_y, inner_w, inner_h) = _fit_rgba(
|
|
rgba_crop,
|
|
target_width=width - 12,
|
|
target_height=height - 12,
|
|
pixelated=True,
|
|
)
|
|
canvas = Image.new("RGBA", (width, height), (14, 14, 16, 236))
|
|
draw = ImageDraw.Draw(canvas)
|
|
draw.rounded_rectangle((0, 0, width - 1, height - 1), radius=10, fill=(14, 14, 16, 236), outline=(92, 92, 104, 255), width=1)
|
|
checker = _checkerboard(width - 12, height - 12, tile=8)
|
|
canvas.alpha_composite(checker, (6, 6))
|
|
canvas.alpha_composite(fitted, (6 + inner_x, 6 + inner_y))
|
|
return canvas
|
|
|
|
|
|
def _pip_size_for_crop(
|
|
rgba_crop: np.ndarray,
|
|
*,
|
|
max_width: int,
|
|
max_height: int,
|
|
padding: int = 12,
|
|
) -> tuple[int, int]:
|
|
crop_height, crop_width = rgba_crop.shape[:2]
|
|
if crop_width <= 0 or crop_height <= 0:
|
|
return max_width, max_height
|
|
inner_max_width = max(1, max_width - padding)
|
|
inner_max_height = max(1, max_height - padding)
|
|
aspect = crop_width / max(1, crop_height)
|
|
inner_width = int(round(inner_max_height * aspect))
|
|
inner_width = max(min(inner_width, inner_max_width), min(inner_max_width, inner_max_height))
|
|
return inner_width + padding, inner_max_height + padding
|
|
|
|
|
|
def _add_pip_inset(render: RenderedPanel, inset: Image.Image, *, margin_x: int = 12, margin_y: int = 12) -> None:
|
|
inner_x, inner_y, inner_w, inner_h = render.content_box
|
|
placement_x = inner_x + max(0, inner_w - inset.width - margin_x)
|
|
placement_y = inner_y + max(0, inner_h - inset.height - margin_y)
|
|
render.image.alpha_composite(inset, (placement_x, placement_y))
|
|
|
|
|
|
def _cell_bbox_to_source_bbox(
|
|
cell_bbox: tuple[int, int, int, int],
|
|
*,
|
|
source_width: int,
|
|
source_height: int,
|
|
target_width: int,
|
|
target_height: int,
|
|
) -> tuple[int, int, int, int]:
|
|
x0, y0, x1, y1 = cell_bbox
|
|
return (
|
|
int(np.floor(x0 * source_width / max(1, target_width))),
|
|
int(np.floor(y0 * source_height / max(1, target_height))),
|
|
int(np.ceil(x1 * source_width / max(1, target_width))),
|
|
int(np.ceil(y1 * source_height / max(1, target_height))),
|
|
)
|
|
|
|
|
|
def _crop_rgba(rgba: np.ndarray, bbox: tuple[int, int, int, int]) -> np.ndarray:
|
|
x0, y0, x1, y1 = bbox
|
|
return rgba[y0:y1, x0:x1]
|
|
|
|
|
|
def _shrink_bbox_bottom_right(
|
|
bbox: tuple[int, int, int, int],
|
|
*,
|
|
scale_x: float,
|
|
scale_y: float,
|
|
) -> tuple[int, int, int, int]:
|
|
x0, y0, x1, y1 = bbox
|
|
width = max(1, x1 - x0)
|
|
height = max(1, y1 - y0)
|
|
new_width = max(1, int(round(width * scale_x)))
|
|
new_height = max(1, int(round(height * scale_y)))
|
|
return (x1 - new_width, y1 - new_height, x1, y1)
|
|
|
|
|
|
def _save_summary(path: Path, payload: dict[str, object]) -> None:
|
|
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
|
|
|
|
|
def _build_row_panels(
|
|
row: PreviewRow,
|
|
*,
|
|
panel_width: int,
|
|
panel_height: int,
|
|
inset_width: int = 139,
|
|
inset_height: int = 103,
|
|
) -> tuple[list[RenderedPanel], tuple[int, int, int, int]]:
|
|
panels = [
|
|
_render_panel(
|
|
"Source",
|
|
rgba=row.source_rgba,
|
|
pixelated=False,
|
|
panel_width=panel_width,
|
|
panel_height=panel_height,
|
|
subtitle=row.source_subtitle,
|
|
),
|
|
_render_panel(
|
|
"Lanczos",
|
|
rgba=row.lanczos_rgba,
|
|
pixelated=True,
|
|
panel_width=panel_width,
|
|
panel_height=panel_height,
|
|
subtitle=row.lanczos_subtitle,
|
|
),
|
|
_render_panel(
|
|
"Phase-field",
|
|
rgba=row.phase_field_rgba,
|
|
pixelated=True,
|
|
panel_width=panel_width,
|
|
panel_height=panel_height,
|
|
subtitle=row.phase_field_subtitle,
|
|
),
|
|
]
|
|
focus_source_bbox = _cell_bbox_to_source_bbox(
|
|
row.focus_cell_bbox,
|
|
source_width=row.source_rgba.shape[1],
|
|
source_height=row.source_rgba.shape[0],
|
|
target_width=row.target_width,
|
|
target_height=row.target_height,
|
|
)
|
|
for panel in panels:
|
|
_draw_source_bbox(
|
|
panel,
|
|
focus_source_bbox,
|
|
source_width=row.source_rgba.shape[1],
|
|
source_height=row.source_rgba.shape[0],
|
|
)
|
|
inset_crops = [
|
|
_crop_rgba(row.source_rgba, focus_source_bbox),
|
|
_crop_rgba(row.lanczos_rgba, row.focus_cell_bbox),
|
|
_crop_rgba(row.phase_field_rgba, row.focus_cell_bbox),
|
|
]
|
|
for panel, crop in zip(panels, inset_crops, strict=True):
|
|
pip_width, pip_height = _pip_size_for_crop(crop, max_width=inset_width, max_height=inset_height)
|
|
_add_pip_inset(panel, _build_pip_inset(crop, width=pip_width, height=pip_height), margin_x=4, margin_y=4)
|
|
return panels, focus_source_bbox
|
|
|
|
|
|
def main() -> None:
|
|
args = _parse_args()
|
|
scratch_dir = Path(args.scratch_dir)
|
|
scratch_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
source_input = Path(args.input)
|
|
dense_input = Path(args.dense_input)
|
|
out_sheet = Path(args.out_sheet)
|
|
out_guard_crop = Path(args.out_guard_crop)
|
|
out_sheet.parent.mkdir(parents=True, exist_ok=True)
|
|
out_guard_crop.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
phase_field_result = run_pipeline(
|
|
source_input,
|
|
scratch_dir / "badge-ai-phase-field-pinned.png",
|
|
target_width=args.target_width,
|
|
target_height=args.target_height,
|
|
diagnostics_dir=scratch_dir / "phase-field-diag",
|
|
steps=args.steps,
|
|
device=args.device,
|
|
enable_candidate_rerank=False,
|
|
)
|
|
|
|
source_rgba = load_rgba(source_input)
|
|
lanczos = lanczos_resize_baseline(source_rgba, width=args.target_width, height=args.target_height)
|
|
dense_source_rgba = load_rgba(dense_input)
|
|
if args.dense_phase_field_output:
|
|
dense_phase_field_output = Path(args.dense_phase_field_output)
|
|
dense_phase_field_rgba = load_rgba(dense_phase_field_output)
|
|
dense_target_width = int(dense_phase_field_rgba.shape[1])
|
|
dense_target_height = int(dense_phase_field_rgba.shape[0])
|
|
dense_phase_field_subtitle = f"tracked {dense_target_width}x{dense_target_height} output"
|
|
dense_title = (
|
|
f"Dense {dense_source_rgba.shape[1]}px pixel art -> tracked "
|
|
f"{dense_target_width}x{dense_target_height} output"
|
|
)
|
|
dense_output_summary = str(dense_phase_field_output)
|
|
else:
|
|
dense_phase_field_result = run_pipeline(
|
|
dense_input,
|
|
scratch_dir / "dense-landscape-phase-field-auto.png",
|
|
diagnostics_dir=scratch_dir / "dense-phase-field-auto-diag",
|
|
steps=args.steps,
|
|
device=args.device,
|
|
lattice_inference_mode="autocorr",
|
|
)
|
|
dense_phase_field_rgba = dense_phase_field_result.output_rgba
|
|
dense_target_width = int(dense_phase_field_result.inference.target_width)
|
|
dense_target_height = int(dense_phase_field_result.inference.target_height)
|
|
dense_phase_field_subtitle = f"{dense_target_width}x{dense_target_height} inferred lattice"
|
|
dense_title = (
|
|
f"Dense {dense_source_rgba.shape[1]}px pixel art -> "
|
|
f"{dense_target_width}x{dense_target_height} inferred lattice"
|
|
)
|
|
dense_output_summary = str(scratch_dir / "dense-landscape-phase-field-auto.png")
|
|
dense_lanczos = lanczos_resize_baseline(
|
|
dense_source_rgba,
|
|
width=dense_target_width,
|
|
height=dense_target_height,
|
|
)
|
|
|
|
save_rgba(scratch_dir / "badge-ai-lanczos.png", lanczos)
|
|
save_rgba(scratch_dir / f"dense-landscape-lanczos-{dense_target_width}x{dense_target_height}.png", dense_lanczos)
|
|
|
|
panel_width = 320
|
|
panel_height = 360
|
|
col_gap = 18
|
|
margin = 24
|
|
row_title_height = 22
|
|
row_gap = 20
|
|
|
|
badge_focus_cell_bbox = _shrink_bbox_bottom_right(
|
|
tuple(args.guard_cell_bbox),
|
|
scale_x=0.5,
|
|
scale_y=0.5,
|
|
)
|
|
dense_focus_cell_bbox = (
|
|
int(round(args.dense_focus_cell_bbox[0] * dense_target_width / max(1, args.dense_target_width))),
|
|
int(round(args.dense_focus_cell_bbox[1] * dense_target_height / max(1, args.dense_target_height))),
|
|
int(round(args.dense_focus_cell_bbox[2] * dense_target_width / max(1, args.dense_target_width))),
|
|
int(round(args.dense_focus_cell_bbox[3] * dense_target_height / max(1, args.dense_target_height))),
|
|
)
|
|
|
|
rows = [
|
|
PreviewRow(
|
|
row_id="badge",
|
|
title=f"AI fake pixel art -> {args.target_width}x{args.target_height} pinned lattice",
|
|
source_rgba=source_rgba,
|
|
source_subtitle="Cleaned AI fake pixel art",
|
|
lanczos_rgba=lanczos,
|
|
lanczos_subtitle=f"{args.target_width}x{args.target_height} baseline",
|
|
phase_field_rgba=phase_field_result.output_rgba,
|
|
phase_field_subtitle=f"{args.target_width}x{args.target_height} pinned lattice",
|
|
target_width=args.target_width,
|
|
target_height=args.target_height,
|
|
focus_cell_bbox=badge_focus_cell_bbox,
|
|
),
|
|
PreviewRow(
|
|
row_id="dense-landscape",
|
|
title=dense_title,
|
|
source_rgba=dense_source_rgba,
|
|
source_subtitle=f"{dense_source_rgba.shape[1]}px source",
|
|
lanczos_rgba=dense_lanczos,
|
|
lanczos_subtitle=f"{dense_target_width}x{dense_target_height} baseline",
|
|
phase_field_rgba=dense_phase_field_rgba,
|
|
phase_field_subtitle=dense_phase_field_subtitle,
|
|
target_width=dense_target_width,
|
|
target_height=dense_target_height,
|
|
focus_cell_bbox=dense_focus_cell_bbox,
|
|
),
|
|
]
|
|
built_rows: list[tuple[PreviewRow, list[RenderedPanel], tuple[int, int, int, int]]] = []
|
|
for row in rows:
|
|
panels, focus_source_bbox = _build_row_panels(
|
|
row,
|
|
panel_width=panel_width,
|
|
panel_height=panel_height,
|
|
)
|
|
built_rows.append((row, panels, focus_source_bbox))
|
|
|
|
guard_bbox = _cell_bbox_to_source_bbox(
|
|
tuple(args.guard_cell_bbox),
|
|
source_width=source_rgba.shape[1],
|
|
source_height=source_rgba.shape[0],
|
|
target_width=args.target_width,
|
|
target_height=args.target_height,
|
|
)
|
|
guard_strip = _build_guard_strip(
|
|
_crop_rgba(source_rgba, guard_bbox),
|
|
_crop_rgba(lanczos, tuple(args.guard_cell_bbox)),
|
|
_crop_rgba(phase_field_result.output_rgba, tuple(args.guard_cell_bbox)),
|
|
title=None,
|
|
)
|
|
guard_strip.save(out_guard_crop)
|
|
|
|
width = margin * 2 + panel_width * 3 + col_gap * 2
|
|
row_block_height = row_title_height + panel_height
|
|
height = margin * 2 + row_block_height * len(built_rows) + row_gap * max(0, len(built_rows) - 1)
|
|
canvas = Image.new("RGBA", (width, height), (11, 11, 13, 255))
|
|
draw = ImageDraw.Draw(canvas)
|
|
row_y = margin
|
|
for row, panels, _focus_source_bbox in built_rows:
|
|
draw.text((margin, row_y - 2), row.title, fill=(255, 255, 255, 255))
|
|
panel_y = row_y + row_title_height
|
|
x = margin
|
|
for panel in panels:
|
|
canvas.alpha_composite(panel.image, (x, panel_y))
|
|
x += panel_width + col_gap
|
|
row_y += row_block_height + row_gap
|
|
|
|
out_sheet.parent.mkdir(parents=True, exist_ok=True)
|
|
canvas.save(out_sheet)
|
|
|
|
_save_summary(
|
|
scratch_dir / "readme-preview-summary.json",
|
|
{
|
|
"rows": [
|
|
{
|
|
"row_id": row.row_id,
|
|
"title": row.title,
|
|
"target_width": row.target_width,
|
|
"target_height": row.target_height,
|
|
"focus_cell_bbox": list(row.focus_cell_bbox),
|
|
"focus_source_bbox": list(focus_source_bbox),
|
|
}
|
|
for row, _panels, focus_source_bbox in built_rows
|
|
],
|
|
"badge_input": str(source_input),
|
|
"dense_input": str(dense_input),
|
|
"dense_phase_field_output": dense_output_summary,
|
|
"guard_cell_bbox": list(args.guard_cell_bbox),
|
|
"guard_source_bbox": list(guard_bbox),
|
|
"out_sheet": str(out_sheet),
|
|
"out_guard_crop": str(out_guard_crop),
|
|
"scratch_dir": str(scratch_dir),
|
|
},
|
|
)
|
|
|
|
print(str(out_sheet))
|
|
print(str(out_guard_crop))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|