fix: face tracker embedding threshold — reject similarity < 0.5, tighten fallback to >0.75
This commit is contained in:
@@ -111,6 +111,7 @@ def match_faces(
|
|||||||
similarity_threshold: float = 0.7,
|
similarity_threshold: float = 0.7,
|
||||||
distance_threshold: float = 100.0,
|
distance_threshold: float = 100.0,
|
||||||
use_embedding: bool = True,
|
use_embedding: bool = True,
|
||||||
|
frame_gap: int = 1,
|
||||||
) -> Dict[int, int]:
|
) -> Dict[int, int]:
|
||||||
"""
|
"""
|
||||||
Match current frame faces to previous frame faces
|
Match current frame faces to previous frame faces
|
||||||
@@ -122,6 +123,7 @@ def match_faces(
|
|||||||
similarity_threshold: Minimum embedding similarity for matching
|
similarity_threshold: Minimum embedding similarity for matching
|
||||||
distance_threshold: Maximum bbox center distance for matching
|
distance_threshold: Maximum bbox center distance for matching
|
||||||
use_embedding: Whether to use embedding similarity
|
use_embedding: Whether to use embedding similarity
|
||||||
|
frame_gap: Number of frames between current and previous (1=adjacent)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict mapping current_face_index -> previous_face_index (or -1 if new)
|
Dict mapping current_face_index -> previous_face_index (or -1 if new)
|
||||||
@@ -165,14 +167,21 @@ def match_faces(
|
|||||||
|
|
||||||
score = 0.0
|
score = 0.0
|
||||||
|
|
||||||
|
# Always reject if embedding similarity is too low (different person)
|
||||||
|
if use_embedding and curr_emb and prev_emb and similarity < 0.5:
|
||||||
|
continue
|
||||||
|
|
||||||
if iou > iou_threshold and similarity > similarity_threshold:
|
if iou > iou_threshold and similarity > similarity_threshold:
|
||||||
score = iou + similarity
|
score = iou + similarity
|
||||||
elif iou > 0.5:
|
elif iou > 0.5 and similarity > 0.65:
|
||||||
score = iou * 2
|
score = iou * 1.5 + similarity * 0.5
|
||||||
elif similarity > 0.85:
|
elif similarity > 0.85:
|
||||||
score = similarity * 2
|
score = similarity * 2
|
||||||
elif distance < distance_threshold and similarity > 0.6:
|
elif similarity > 0.75 and distance < distance_threshold:
|
||||||
score = similarity - distance / 1000
|
score = similarity - distance / 1000
|
||||||
|
# For frame gaps (tracking lost and recovered), require higher confidence
|
||||||
|
elif frame_gap > 1 and similarity > 0.8 and iou > 0.2:
|
||||||
|
score = similarity + iou
|
||||||
|
|
||||||
if score > best_score:
|
if score > best_score:
|
||||||
best_score = score
|
best_score = score
|
||||||
@@ -220,6 +229,7 @@ def track_faces(
|
|||||||
|
|
||||||
prev_faces = []
|
prev_faces = []
|
||||||
prev_trace_ids = []
|
prev_trace_ids = []
|
||||||
|
prev_frame_num = None
|
||||||
|
|
||||||
print(f"\nTracking faces across {len(sorted_frames)} frames...")
|
print(f"\nTracking faces across {len(sorted_frames)} frames...")
|
||||||
print(f"Parameters: iou={iou_threshold}, similarity={similarity_threshold}, distance={distance_threshold}")
|
print(f"Parameters: iou={iou_threshold}, similarity={similarity_threshold}, distance={distance_threshold}")
|
||||||
@@ -227,6 +237,9 @@ def track_faces(
|
|||||||
|
|
||||||
for frame_num_str, frame_data in sorted_frames:
|
for frame_num_str, frame_data in sorted_frames:
|
||||||
frame_num = int(frame_num_str)
|
frame_num = int(frame_num_str)
|
||||||
|
frame_gap = frame_num - prev_frame_num if prev_frame_num is not None else 1
|
||||||
|
prev_frame_num = frame_num
|
||||||
|
|
||||||
faces = frame_data.get("faces", [])
|
faces = frame_data.get("faces", [])
|
||||||
|
|
||||||
if not faces:
|
if not faces:
|
||||||
@@ -241,6 +254,7 @@ def track_faces(
|
|||||||
similarity_threshold,
|
similarity_threshold,
|
||||||
distance_threshold,
|
distance_threshold,
|
||||||
use_embedding,
|
use_embedding,
|
||||||
|
frame_gap,
|
||||||
)
|
)
|
||||||
|
|
||||||
trace_ids = []
|
trace_ids = []
|
||||||
|
|||||||
Reference in New Issue
Block a user