Files
Dragon-s-Lair-X68k/tools/analysis/02_denoise_BROKEN.py
T
reala-misaki 65112b9305 Session 1: hardware research, content measurement, codec decision, MAME harness
Verified GVRAM is one word-access per pixel in ALL color modes; chose 256-color
256x192 with movem.l bursts (page 1 sacrificed as double-buffer).

Measured 8 scenes from the Blu-ray source: blit costs under 8% of the 12fps
cycle budget, so I/O is the bottleneck, not CPU. Naive delta+RLE reaches only
3.2:1 (365 KB/s, 470MB) -> decision to use 4x4 vector quantization (~30 KB/s).

"Shot on twos" assumption failed: the transfer has zero duplicate frames, so
12fps requires explicit decimation.

Documents three false measurement results and their root causes (per-frame
Floyd-Steinberg dithering, temporal denoise, exact-match dedupe on noisy source).

MAME Lua injection harness works and is reusable for cycle-cost measurement;
the IOCS _B_READ disk benchmark is blocked returning -1.

Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
2026-08-23 11:23:49 -07:00

62 lines
2.5 KiB
Python

import numpy as np, glob
from PIL import Image
files = sorted(glob.glob("an2/f*.png"))
imgs = [Image.open(f) for f in files]
print("PIL mode:", imgs[0].mode)
idx = [np.asarray(im.convert("P") if im.mode!="P" else im, dtype=np.uint8) for im in imgs]
N = len(idx); H,W = idx[0].shape; raw = H*W
print(f"frames={N} size={H}x{W} raw={raw} B/frame")
# --- per-pair change stats on the QUANTIZED stream ---
pct = np.array([100.0*np.count_nonzero(idx[i]!=idx[i-1])/raw for i in range(1,N)])
print(f"\n--- consecutive change % (24fps, quantized) ---")
print(f"mean {pct.mean():.1f} median {np.median(pct):.1f} p10 {np.percentile(pct,10):.1f} p90 {np.percentile(pct,90):.1f} max {pct.max():.1f}")
print(f"pairs under 2% changed: {np.count_nonzero(pct<2.0)}/{len(pct)} ({100*np.count_nonzero(pct<2.0)/len(pct):.0f}%)")
# --- threshold dedupe (twos detection) ---
THRESH = 2.0
keep=[0]
for i in range(1,N):
if 100.0*np.count_nonzero(idx[i]!=idx[keep[-1]])/raw >= THRESH:
keep.append(i)
print(f"\n--- dedupe @ {THRESH}% ---")
print(f"unique frames: {len(keep)}/{N} -> effective {len(keep)/12.0:.1f} fps")
cp = np.array([100.0*np.count_nonzero(idx[keep[j]]!=idx[keep[j-1]])/raw for j in range(1,len(keep))])
print(f"unique-pair change %: mean {cp.mean():.1f} median {np.median(cp):.1f} p90 {np.percentile(cp,90):.1f} max {cp.max():.1f}")
def encode_size(a,b,gap=4):
total=0
for y in range(a.shape[0]):
ra,rb=a[y],b[y]
d=np.nonzero(ra!=rb)[0]
if len(d)==0: continue
spans=[]; s=d[0]; p=d[0]
for x in d[1:]:
if x-p>gap: spans.append((s,p)); s=x
p=x
spans.append((s,p))
total+=2
for s0,e0 in spans:
seg=rb[s0:e0+1]; total+=2
i2=0
while i2<len(seg):
r=1
while i2+r<len(seg) and seg[i2+r]==seg[i2] and r<127: r+=1
total += 2 if r>=3 else r
i2+=r
return total
sz=np.array([encode_size(idx[keep[j-1]],idx[keep[j]]) for j in range(1,len(keep))])
fps_eff=len(keep)/12.0
rate=sz.mean()*fps_eff
print(f"\n--- codec estimate ---")
print(f"delta bytes: mean {sz.mean():.0f} median {np.median(sz):.0f} p90 {np.percentile(sz,90):.0f} max {sz.max():.0f}")
print(f"ratio vs raw: {raw/sz.mean():.1f}:1")
print(f"stream rate : {rate/1024:.1f} KB/s")
print(f"22min video : {rate*22*60/1048576:.0f} MB")
px=cp.mean()/100*raw
print(f"blit cost : ~{px*6.5/1000:.0f}k cycles/frame (budget 833k)")
print(f"p90 blit : ~{np.percentile(cp,90)/100*raw*6.5/1000:.0f}k cycles")