"""Cross-validate OVFaceDetector vs ultralytics CPU baseline on real stills.""" import glob, sys, time import numpy as np, cv2 imgs = sorted(glob.glob('/home/alex/Documents/ov-bench/imgs/*.png')) sys.path.insert(0, '.') from ov_detector import OVFaceDetector # baseline: ultralytics torch CPU (deterministic on CPU) from ultralytics import YOLO base = YOLO('models/yolov8x6_animeface.pt') ovd = OVFaceDetector('models/yolov8x6_animeface.onnx', device='GPU', imgsz=1280) def iou(a, b): xx1, yy1 = max(a[0], b[0]), max(a[1], b[1]) xx2, yy2 = min(a[2], b[2]), min(a[3], b[3]) inter = max(0, xx2-xx1) * max(0, yy2-yy1) ua = (a[2]-a[0])*(a[3]-a[1]) + (b[2]-b[0])*(b[3]-b[1]) - inter return inter / max(ua, 1e-9) ious, n_match, n_only_base, n_only_ov = [], 0, 0, 0 t0=time.time() for p in imgs: fr = cv2.imread(p) rb = base.predict(fr, conf=0.25, imgsz=1280, device='cpu', verbose=False)[0] ro = ovd.predict(fr, conf=0.25, imgsz=1280, verbose=False)[0] bb = rb.boxes.xyxy.cpu().numpy() if rb.boxes is not None else np.zeros((0,4)) bo = ro.boxes.xyxy.numpy() used = set() for box in bb: best, bi = 0, -1 for j, ob in enumerate(bo): v = iou(box, ob) if v > best: best, bi = v, j if best > 0.5: ious.append(best); n_match += 1; used.add(bi) else: n_only_base += 1 n_only_ov += len(bo) - len(used) dt = time.time()-t0 print(f"imgs={len(imgs)} matched={n_match} (mean IoU {np.mean(ious):.3f}) only_base={n_only_base} only_ov={n_only_ov} [{dt:.0f}s total]")