chore(traces): put TRACES tags on their own line; regenerate the report

The parser reads a tag up to end of line, so `# TRACES: GR-004 | SR-001 —
prose` swallowed the prose into the tag and the row went unmatched. Splitting
the comment leaves the tag greppable by the same pattern as the code tags and
the commit trailers, which is the point of the house format.

Mechanical throughout; no logic touched. The regenerated report reflects this
session's new tags: 137 -> 148 found, and one more tagged-but-unexecuted, which
is the SuperHero accuracy assertion that is documented but not yet a test.
This commit is contained in:
2026-08-04 14:04:21 +02:00
parent d98dc2855a
commit f891e579c5
15 changed files with 198 additions and 70 deletions
+65 -7
View File
@@ -30,6 +30,8 @@ import sae_embed # before cv2 — see alignment_compare.py
import numpy as np
import cv2
import argparse
ROOT = "/home/dtourolle/Development/Jray-project/scene-actor-extraction/"
M = ROOT + "models/"
CLIPS = ["5157344", "5157339"]
@@ -37,16 +39,31 @@ PROB_THRESHOLD = 0.754
GROUP_IOU = 0.55 # detections overlapping this much are the same face
MATCH_IOU = 0.35 # tie a detection to the hand-labelled face
base_eng = sae_embed.FaceEmbedder(detector_model=M + "scrfd_500m_bnkps.onnx",
_ap = argparse.ArgumentParser()
_ap.add_argument("--detector", default="scrfd_500m_bnkps.onnx",
help="detector under models/. SCRFD sizes 500m / 2.5g / 10g come "
"from InsightFace's buffalo_sc / buffalo_m / buffalo_l packs")
_ap.add_argument("--vote-conf", type=float, default=None,
help="confidence floor for the voting pass. Omit to auto-tune "
"it to --target-votes")
_ap.add_argument("--target-votes", type=int, default=3,
help="votes per face to tune --vote-conf towards, so detectors "
"are compared at equal redundancy rather than equal settings")
_args = _ap.parse_args()
base_eng = sae_embed.FaceEmbedder(detector_model=M + _args.detector,
arcface_model=M + "LVFace-B_Glint360K.onnx",
conf=0.5, nms=0.4, max_side=0)
# Same models, looser suppression: keep the duplicates NMS would have removed.
vote_eng = sae_embed.FaceEmbedder(detector_model=M + "scrfd_500m_bnkps.onnx",
def _make_vote_engine(conf):
# Same models, looser suppression: keep the duplicates NMS would have removed.
return sae_embed.FaceEmbedder(detector_model=M + _args.detector,
arcface_model=M + "LVFace-B_Glint360K.onnx",
conf=0.3, nms=0.9, max_side=0)
conf=conf, nms=0.9, max_side=0)
cal = sae_embed.gallery_calibration(ROOT + "gallery_lvface.h5")
def iou(a, b):
ax, ay, aw, ah = a; bx, by, bw, bh = b
x0, y0 = max(ax, bx), max(ay, by)
@@ -79,6 +96,46 @@ def vote(dets):
return out
def tune_vote_conf(target, sample=6):
"""Pick the confidence floor giving ~target detections per face to average.
A larger SCRFD is more confident and suppresses harder, so at a fixed floor
it emits fewer overlapping anchors — median 2 against 500m's 3. Comparing
detectors at equal SETTINGS therefore also compares them at unequal
redundancy, and the voting arm is handicapped for the bigger models. Tuning
each to the same votes-per-face isolates landmark quality from how much
there was to average.
"""
frames = sorted(glob.glob(f"frames/d{CLIPS[0]}_*.png"))[:sample]
imgs = [cv2.imread(f) for f in frames]
best = (None, None, 1e9)
for conf in (0.30, 0.20, 0.12, 0.07, 0.04, 0.02, 0.01):
eng = _make_vote_engine(conf)
sizes = [n for img in imgs for _, _, _, n in vote(eng.detect(img))]
if not sizes:
continue
med = float(np.median(sizes))
if abs(med - target) < best[2]:
best = (conf, eng, abs(med - target))
print(f"[tune] conf={conf:.2f} -> median {med:.0f} votes/face", file=sys.stderr)
if med >= target:
break
if best[1] is None:
print(f"[tune] no confidence floor reached {target} votes/face; "
f"falling back to 0.30", file=sys.stderr)
return 0.30, _make_vote_engine(0.30)
print(f"[tune] chose conf={best[0]:.2f} for ~{target} votes/face", file=sys.stderr)
return best[0], best[1]
if _args.vote_conf is not None:
VOTE_CONF, vote_eng = _args.vote_conf, _make_vote_engine(_args.vote_conf)
else:
VOTE_CONF, vote_eng = tune_vote_conf(_args.target_votes)
cal = sae_embed.gallery_calibration(ROOT + "gallery_lvface.h5")
def collect(clip):
lab = {os.path.basename(p): os.path.basename(os.path.dirname(p))
for p in glob.glob(f"labelling/{clip}/*/*.jpg")
@@ -124,7 +181,8 @@ print(f"[voting] group size: median {np.median(allv):.0f}, "
file=sys.stderr)
GAL, PRB = "5157344", "5157339"
print(f"\ngallery {GAL} -> probe {PRB}, P>{PROB_THRESHOLD}\n")
print(f"\ndetector={_args.detector} vote_conf={VOTE_CONF:.2f} "
f"gallery {GAL} -> probe {PRB}, P>{PROB_THRESHOLD}\n")
print(f"{'align':>8}{'person':>8}{'n_gal':>7}{'n_prb':>7}"
f"{'within-clip':>13}{'cross-clip':>12}{'hit rate':>10}")
summary = {}
+2
View File
@@ -1,6 +1,8 @@
#!/usr/bin/env python3
"""Impact of input resolution on cross-source identification.
TRACES: VR-013 | PR-002
Gallery is built from one clip at NATIVE resolution. Probes come from the other
clip with the WHOLE FRAME downscaled before it reaches the detector, so
detection and landmark regression degrade together with the pixels. That is the
+8
View File
@@ -1,6 +1,14 @@
#!/usr/bin/env python3
"""Integrity check on the labelled set, before it is used as ground truth.
TRACES: VR-013 | PR-002
VR-013's ground truth is hand-sorted rather than propagated by embedding
similarity, because propagation would keep only the faces the embedder already
gets right and silently drop the ones the sweep exists to find. This script is
what makes that claim checkable, so it is part of the requirement rather than a
helper of it.
Checks, loudest failure first:
1. INDEX INTEGRITY. Each crop's embedding is taken by re-detecting its source