#!/usr/bin/env python3
"""geometry_screen.py -- detect aspect / face-proportion distortion in avatar clips.

Optical-flow horizontal-compression metric. A squish makes the LEFT side of the face
flow right and the RIGHT side flow left => negative slope of (mean horizontal flow) vs x.
A head-TURN is uniform horizontal flow (~flat slope, nonzero offset) -> not flagged.
So this isolates aspect/proportion warp from ordinary motion -- catching exactly what
motion-YAVG / frame-MSE / bbox-width / Haar face-detect are all BLIND to.

Built 2026-06-08 after Jun caught a face-warp squish that motion metrics missed.
Validated: on the happy FF->unit->FF splice it flagged f32-33 and f180-181 (the two
FF<->unit seams) -- matching Jun's eye exactly.

Usage:  python3 geometry_screen.py <video.mp4> [zthresh=4]
Exit 0 = PASS (no aspect distortion), 1 = FAIL (distortion frames found).
"""
import cv2, numpy as np, sys

def screen(V, zthresh=4.0):
    cap = cv2.VideoCapture(V)
    prev=None; slopes=[]; idx=[]; fi=0
    while True:
        ret, fr = cap.read()
        if not ret: break
        g = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
        if prev is not None:
            flow = cv2.calcOpticalFlowFarneback(prev, g, None, 0.5, 3, 21, 3, 5, 1.2, 0)
            fx = flow[..., 0]; h, w = fx.shape
            band = fx[int(h*0.15):int(h*0.60), :]      # face band
            colmean = band.mean(0); xs = np.arange(w) - w/2.0
            slopes.append(np.polyfit(xs, colmean, 1)[0])  # <0 compression, >0 stretch
            idx.append(fi)
        prev = g; fi += 1
    s = np.array(slopes); base = np.median(s)
    mad = np.median(np.abs(s - base)) + 1e-9
    z = (s - base) / (mad * 1.4826)
    ev = [(idx[i], s[i], z[i]) for i in range(len(s)) if abs(z[i]) > zthresh]
    print(f"{V}\n frames={fi} median_slope={base:+.4f}")
    for f, sl, zz in ev:
        print(f"  f{f}: slope={sl:+.4f} z={zz:+.1f} {'SQUISH' if sl < base else 'STRETCH'}")
    print(f" RESULT: {'FAIL ('+str(len(ev))+' geometry events)' if ev else 'PASS (no aspect distortion)'}")
    return 0 if not ev else 1

if __name__ == '__main__':
    V = sys.argv[1]
    zt = float(sys.argv[2]) if len(sys.argv) > 2 else 4.0
    sys.exit(screen(V, zt))
