The run cycles anchor on their feet, and stride at a real cadence
Oliver: 'the motion seems very flashy and unnatural'. Two causes, both measured: drawChar centres a frame by its total width while the racket's reach varies across the cycle, so the BODY teleported sideways up to 28 source px on a frame swap (the female player was worst) — every frame is now padded until its lower-third centroid sits at the frame centre (residuals ±0.2 px, the normalisation lives in _runroll.py's cut). And the hardcoded 4.5 cycles/s was tuned on 2-4 near-duplicate frames; on eight real phases it was a strobe — rolled sets stride at TUNE.runHz (2.4), old art keeps 4.5. In-pane: body wobble down from ~36 device px per swap to 3.2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9a49acff51
commit
e8b5c1905f
32 files changed
+27
-5
No files matched your search
@@ -176,6 +176,24 @@ def cut(k, install=False, n=0):
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
outs = [os.path.join(outdir, f'{pre}{i}{suf}.png') for i in range(1, got + 1)]
|
||||
_fine.main(sheet, outs, TARGET_H, [], -1)
|
||||
# ANCHOR EVERY FRAME ON ITS FEET. drawChar centres a frame by its total width, and the racket's
|
||||
# reach varies wildly across a cycle (the cut female frames measured -28..+15 px of feet drift
|
||||
# from frame centre) — so the BODY teleported sideways every frame, which is exactly Oliver's
|
||||
# "very flashy and unnatural". Pad each frame with transparency until the lower-third centroid
|
||||
# (the same surface the stride gate reads) sits at the frame's horizontal centre.
|
||||
import numpy as np
|
||||
for o in outs:
|
||||
im = Image.open(o).convert('RGBA')
|
||||
a = np.array(im)
|
||||
op = a[..., 3] > 40
|
||||
ys, xs = np.nonzero(op[int(op.shape[0] * 0.66):])
|
||||
if not len(xs): continue
|
||||
cx = xs.mean()
|
||||
off = round(2 * (cx - im.width / 2)) # feet right of centre -> pad RIGHT, and vice versa:
|
||||
if off == 0: continue # new centre (w+|off|)/2 then lands on the feet
|
||||
pad = Image.new('RGBA', (im.width + abs(off), im.height), (0, 0, 0, 0))
|
||||
pad.paste(im, (0 if off > 0 else abs(off), 0))
|
||||
pad.save(o)
|
||||
# THE STRIDE GATE, on what was actually cut: every neighbouring pair (wrapping — it loops) must
|
||||
# differ in the legs, or the cycle holds a duplicated pose. Threshold calibrated against
|
||||
# _famref's (30% = a real stride pair; 12 catches only true near-duplicates).
|
||||
|
||||
Reference in new issue
Block a user