Make the regen pipeline check the kit, and fix the swing and toss
Every roll drifts the palette and nothing measured it: a white headband on six frames, pale grey shorts on the toss twice, brick-red shirts and brown shoes on the swing all sailed past --tries. check: "same"/"loose" skips colour_match, and colour_match is a global mean/sd fit far too weak to pull brick-red back to red — a nearest-colour palette lock is worse still, it drags the duller reds into the racket's browns. So _regen.py measures three numbers and a batch opts in with palette_ref: redness (r minus mean(g,b) over saturated warm pixels — brightness alone cannot tell brick-red from red), shorts brightness (charcoal 61 vs the drift's 83), and the near-white fraction that is the shoes and socks (brown drops it to 0.9%, pale shorts push it to 7.9%, correct frames sit at 2.8%). Frames known to be right cluster tightly on all three; every drifted frame fell outside on at least one. It rejected five bad rolls in a row, then passed a good one. The swing also kept re-inheriting its own drift: ref_sheet is built from [lead] + the sprites being replaced, so it was showing the generator the very brick-red frame it was about to overwrite. Copying a canonical frame over the targets first breaks the loop — it passed on the next roll. Swing is now a real backswing and follow-through (silhouettes differ by 1.0, racket low behind vs up over the shoulder), both at full standing height, and the toss and smash wear charcoal shorts again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
494bab1b69
commit
af30db2ff3
10 files changed
+72
-10
No files matched your search
@@ -68,6 +68,40 @@ def density(path):
|
||||
d = np.abs(np.diff(a[..., :3].astype(int), axis=1)).sum(2)
|
||||
return round(float(((d > 40) & solid[:, :-1]).sum() / max(1, solid.sum())), 3)
|
||||
|
||||
def kit(path):
|
||||
"""Three numbers that say whether a roll is wearing the right clothes:
|
||||
REDNESS how red the shirt is (r minus the mean of g,b, over the saturated warm pixels).
|
||||
Brightness alone will NOT do — a brick-red shirt is as bright as a red one.
|
||||
SHORTS mean brightness of the mid-tone neutral pixels. Charcoal ~61, pale grey ~83.
|
||||
BRIGHT fraction of the body that is near-white — the shoes and socks. Brown shoes drop it,
|
||||
pale shorts push it up.
|
||||
Calibrated on frames known to be right (idle/bounce/run): redness 99-110, shorts 60-63,
|
||||
bright 2.7-2.9%. Every frame that had visibly drifted fell outside on at least one axis."""
|
||||
a = np.array(Image.open(path).convert('RGBA')).astype(int)
|
||||
px = a[..., :3][a[..., 3] > 128]
|
||||
if not len(px): return (0.0, 0.0, 0.0)
|
||||
red = px[(px[:, 0] > px[:, 1] + 45) & (px[:, 0] > px[:, 2] + 45)]
|
||||
neutral = px[(px.max(1) - px.min(1)) < 55]
|
||||
shorts = neutral[(neutral.mean(1) > 25) & (neutral.mean(1) < 145)]
|
||||
bright = neutral[neutral.mean(1) >= 150]
|
||||
return (round(float((red[:, 0] - (red[:, 1] + red[:, 2]) / 2).mean()) if len(red) else 0, 1),
|
||||
round(float(shorts.mean()) if len(shorts) else 0, 1),
|
||||
round(len(bright) / len(px) * 100, 1))
|
||||
|
||||
def kit_off(outs, ref_name, tol=(12, 10, 1.5)):
|
||||
"""Is this roll wearing the right kit? Generative rolls drift the palette EVERY TIME and nothing
|
||||
else here catches it: colour_match only runs for `check: finer`, and it is a global mean/sd fit
|
||||
far too weak to pull brick-red back to red. Before this existed, six frames shipped with a white
|
||||
headband, the toss shipped twice in pale grey shorts, and a swing pair shipped in brown shoes.
|
||||
Compared against a canonical frame that is NOT part of the batch (o_idle1 for the opponent)."""
|
||||
ref = kit(os.path.join(HERE, ref_name + '.png'))
|
||||
for o in outs:
|
||||
got = kit(o)
|
||||
if any(abs(g - r) > t for g, r, t in zip(got, ref, tol)):
|
||||
return (f'kit drifted vs {ref_name}: redness/shorts/bright {got} vs {ref} '
|
||||
f'(tolerance {tol})')
|
||||
return None
|
||||
|
||||
def not_magenta(sheet):
|
||||
"""The generator sometimes ignores the magenta and paints its own background. That was written
|
||||
off as harmless — the key uses the corner colour — right up until it returned a GREEN sheet and
|
||||
@@ -143,6 +177,9 @@ def run(name, spec, dry=False):
|
||||
bar = {'finer': 1.25, 'same': 0.85, 'loose': 0.7}[spec.get('check', 'finer')]
|
||||
if sum(after) / len(after) < sum(before) / len(before) * bar:
|
||||
print(f'[{name}] REJECTED: not finer than what it replaces {before} -> {after}'); return False
|
||||
if spec.get('palette_ref'):
|
||||
bad = kit_off(outs, spec['palette_ref'])
|
||||
if bad: print(f'[{name}] REJECTED: {bad}'); return False
|
||||
for o, s in zip(outs, sprites):
|
||||
if spec.get('check', 'finer') == 'finer': colour_match(o, s)
|
||||
Image.open(o).save(os.path.join(HERE, s + '.png'))
|
||||
|
||||
Reference in new issue
Block a user