3d8825f5a9
REGISTRY rewritten around the central rule: a character folder is born only when a body ships to ariki-game (<character>_base_v<NN> = ship ordinal). lena_nude dissolves accordingly: - characters/female/lena_base_v01/ — SHIPPED 2026-08-10: AccuRig GLB carrier, T-pose/rig FBX + JSON, previews, frozen README - characters/work/lena/ — the live lane: recipes 01-47 (incl. new 36-47: refill/sheets/clay/despeckle/musculature/spin/AccuRig export/graft/pose QC), masters (athletic_v04 blend + textures, accurig blend), lane-history README - hires_claude/hires_work intermediates (blends, logs, probes) pruned Supporting docs: AGENTS.md, working-files rule, rig-graft plan addendum, originals README, prune_lane.py. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
46 lines
1.7 KiB
Python
46 lines
1.7 KiB
Python
# Stage 33 (read-only): A/B the re-atlased body against its input. A faithful re-atlas should
|
|
# look the SAME — same skin, same tones — while carrying a completely different UV layout
|
|
# underneath. Large differences would mean the transfer lost or moved her texture.
|
|
#
|
|
# blender --background --python 33_ab.py -- <dirA> <dirB>
|
|
import bpy, sys, os
|
|
import numpy as np
|
|
|
|
argv = sys.argv[sys.argv.index("--") + 1:]
|
|
A_DIR, B_DIR = argv[0], argv[1]
|
|
|
|
|
|
def load(p):
|
|
im = bpy.data.images.load(p)
|
|
w, h = im.size
|
|
b = np.empty(w * h * 4, dtype=np.float32)
|
|
im.pixels.foreach_get(b)
|
|
a = b.reshape(h, w, 4)[:, :, :3].copy()
|
|
bpy.data.images.remove(im)
|
|
return a
|
|
|
|
|
|
print(f"{'view':<12} {'mean|d|':>9} {'p95|d|':>8} {'p99|d|':>8} {'>0.05':>8} {'>0.15':>8}")
|
|
tot = []
|
|
for name in ("full_front", "full_40", "full_back", "chest", "hip"):
|
|
pa = os.path.join(A_DIR, name + ".png")
|
|
pb = os.path.join(B_DIR, name + ".png")
|
|
if not (os.path.exists(pa) and os.path.exists(pb)):
|
|
print(f"{name:<12} missing")
|
|
continue
|
|
A, B = load(pa), load(pb)
|
|
if A.shape != B.shape:
|
|
print(f"{name:<12} shape mismatch {A.shape} vs {B.shape}")
|
|
continue
|
|
# only compare where the body is: the background is identical by construction
|
|
body = (np.abs(A - np.array([0.22, 0.22, 0.24])).max(axis=2) > 0.02)
|
|
d = np.abs(A - B).max(axis=2)[body]
|
|
tot.append(d)
|
|
print(f"{name:<12} {d.mean():9.4f} {np.percentile(d,95):8.4f} {np.percentile(d,99):8.4f} "
|
|
f"{100.0*(d>0.05).mean():7.2f}% {100.0*(d>0.15).mean():7.2f}%")
|
|
if tot:
|
|
d = np.concatenate(tot)
|
|
print(f"\nALL BODY PIXELS: mean |d| {d.mean():.4f} p99 {np.percentile(d,99):.4f} "
|
|
f"fraction over 0.05: {100.0*(d>0.05).mean():.2f}%")
|
|
print("AB_DONE")
|