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:
@@ -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 = {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user