- pipeline/batch_roster.py: model + clip-kit per fighter, renders base+torn, packs, hitboxes, tunes, portraits — sequential batch - --strip flag (mesh removal) added; Mixamo pack models turn out hollow under clothes, so this batch ships base+torn; true clothes-off waits on rigging the wardrobegod nude bases (phrtt2, daphne) - tune_fighters: manifests + default finisher timing for raver/chef/ exec/jinx/elva/umbra; getup move tuned - select screen wraps to a 4-per-row grid Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
28 lines
951 B
Python
28 lines
951 B
Python
#!/usr/bin/env python3
|
|
"""Select-screen portrait: alpha-bbox head/torso crop of idle frame 0."""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
from PIL import Image
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
|
|
for cid in sys.argv[1:]:
|
|
src = REPO / "characters" / cid / "moves/idle/frames/0000.png"
|
|
if not src.exists():
|
|
print(f"skip {cid}: no idle frame")
|
|
continue
|
|
img = Image.open(src)
|
|
a = np.array(img.split()[-1])
|
|
rows = np.where(a.max(axis=1) > 32)[0]
|
|
cols = np.where(a.max(axis=0) > 32)[0]
|
|
top, bot, l, r = rows[0], rows[-1], cols[0], cols[-1]
|
|
h = int((bot - top) * 0.45)
|
|
cx = (l + r) // 2
|
|
crop = img.crop((max(cx - h // 2, 0), top, min(cx + h // 2, img.width), top + h))
|
|
bg = Image.new("RGBA", (160, 160), (24, 26, 32, 255))
|
|
bg.alpha_composite(crop.resize((160, 160), Image.LANCZOS))
|
|
bg.save(REPO / "characters" / cid / "portrait.png")
|
|
print(f"portrait {cid}")
|