Initial commit: handshapes multiclass project

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 22:27:20 -05:00
commit 816e34cb17
22 changed files with 2820 additions and 0 deletions

77
prep_sequence_resampled.py Executable file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python3
# Build fixed-length (N frames) dataset from sequences/<split>/<CLASS>/clip_*.npz
import argparse, os, glob, json
from pathlib import Path
import numpy as np
def resample_sequence(X, N=32):
# X: (T,F) -> (N,F) via linear interpolation over frame index
T = len(X)
if T == 0: return np.zeros((N, X.shape[1]), np.float32)
if T == 1: return np.repeat(X, N, axis=0)
src = np.linspace(0, T-1, num=T, dtype=np.float32)
dst = np.linspace(0, T-1, num=N, dtype=np.float32)
out = np.zeros((N, X.shape[1]), np.float32)
for d in range(X.shape[1]):
out[:, d] = np.interp(dst, src, X[:, d])
return out
def load_classes(seq_root: Path):
# Accept ANY class subfolder under sequences/train/, ignore hidden/system dirs
train_dir = seq_root / "train"
if not train_dir.exists():
raise SystemExit(f"Missing folder: {train_dir}")
classes = sorted([
p.name for p in train_dir.iterdir()
if p.is_dir() and not p.name.startswith(".")
])
if not classes:
raise SystemExit("No classes found in sequences/train/ (folders should be class names like Mother, Father, etc.)")
return classes
def collect_split(seq_root: Path, split: str, classes, N):
Xs, ys = [], []
for ci, cls in enumerate(classes):
for f in sorted(glob.glob(str(seq_root / split / cls / "clip_*.npz"))):
d = np.load(f)
Xi = d["X"].astype(np.float32) # (T,F)
XiN = resample_sequence(Xi, N) # (N,F)
Xs.append(XiN); ys.append(ci)
if Xs:
X = np.stack(Xs, 0); y = np.array(ys, np.int64)
else:
X = np.zeros((0, N, 1), np.float32); y = np.zeros((0,), np.int64)
return X, y
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--in", dest="in_dir", default="sequences")
ap.add_argument("--out", default="landmarks_seq32")
ap.add_argument("--frames", type=int, default=32)
args = ap.parse_args()
seq_root = Path(args.in_dir)
outdir = Path(args.out); outdir.mkdir(parents=True, exist_ok=True)
classes = load_classes(seq_root)
trX, trY = collect_split(seq_root, "train", classes, args.frames)
vaX, vaY = collect_split(seq_root, "val", classes, args.frames)
if trX.size == 0 and vaX.size == 0:
raise SystemExit("Found no clips. Did you run capture and save any clip_*.npz files?")
np.save(outdir/"train_X.npy", trX)
np.save(outdir/"train_y.npy", trY)
np.save(outdir/"val_X.npy", vaX)
np.save(outdir/"val_y.npy", vaY)
json.dump(classes, open(outdir/"class_names.json", "w"))
# Detect true feature dimension from data
input_dim = int(trX.shape[-1] if trX.size else vaX.shape[-1])
json.dump({"frames": args.frames, "input_dim": input_dim}, open(outdir/"meta.json","w"))
print(f"Saved dataset → {outdir}")
print(f" train {trX.shape}, val {vaX.shape}, classes={classes}, input_dim={input_dim}")
if __name__ == "__main__":
main()