foitin/tools/make_portrait.py
m3ultra 0f83637fcc Roster batch tooling: 6 new fighters from the asset library
- 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>
2026-07-28 23:38:16 +10:00

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}")