From b66d7963c228b9e088031a29e86af9706c6d7239 Mon Sep 17 00:00:00 2001 From: Accusys Date: Thu, 14 May 2026 00:32:39 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20store=5Ftraced=5Ffaces=20=E2=80=94=20emb?= =?UTF-8?q?ed=20from=20DB,=20UPDATE=20not=20INSERT,=20dedup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/store_traced_faces.py | 70 +++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/scripts/store_traced_faces.py b/scripts/store_traced_faces.py index 469a6e3..cc1c354 100644 --- a/scripts/store_traced_faces.py +++ b/scripts/store_traced_faces.py @@ -48,10 +48,25 @@ def run_face_tracker(face_json_path: str, traced_json_path: str) -> str: frames_dict = {} for frame in face_data["frames"]: fnum = str(frame["frame"]) + faces = [] + for f in frame.get("faces", []): + bbox = f.get("bbox", f) + face = { + "x": bbox.get("x", f.get("x", 0)), + "y": bbox.get("y", f.get("y", 0)), + "width": bbox.get("width", f.get("width", 0)), + "height": bbox.get("height", f.get("height", 0)), + "confidence": f.get("confidence", 0.0), + } + if "landmarks" in f: + face["landmarks"] = f["landmarks"] + if "embedding" in f: + face["embedding"] = f["embedding"] + faces.append(face) frames_dict[fnum] = { "frame_number": frame["frame"], "time_seconds": frame.get("timestamp", 0), - "faces": frame.get("faces", []), + "faces": faces, } face_data["frames"] = frames_dict # Preserve metadata (fps needed by face_tracker) @@ -63,6 +78,41 @@ def run_face_tracker(face_json_path: str, traced_json_path: str) -> str: print(f"[TRACE] Processing {len(face_data.get('frames', {}))} frames") + # Load embeddings from DB for the face tracker + file_uuid = face_json_path.split("/")[-1].replace(".face.json", "").replace("_traced.json", "") + try: + conn = get_conn() + cur = conn.cursor() + cur.execute(f""" + SELECT frame_number, x, y, width, height, embedding + FROM {SCHEMA}.face_detections + WHERE file_uuid = %s AND embedding IS NOT NULL + """, (file_uuid,)) + emb_rows = cur.fetchall() + conn.close() + # Build lookup: frame_number → list of (bbox, embedding) + emb_map = {} + for fn, x, y, w, h, emb in emb_rows: + emb_map.setdefault(fn, []).append(((x, y, w, h), emb)) + print(f"[TRACE] Loaded {len(emb_rows)} embeddings from DB") + + # Attach embeddings to face data + attached = 0 + for fnum_str, frm_data in face_data.get("frames", {}).items(): + fnum = int(fnum_str) + for face in frm_data.get("faces", []): + x, y, w, h = face.get("x", 0), face.get("y", 0), face.get("width", 0), face.get("height", 0) + candidates = emb_map.get(fnum, []) + # Find matching embedding by bbox proximity + for (ex, ey, ew, eh), emb in candidates: + if abs(x - ex) < 10 and abs(y - ey) < 10 and abs(w - ew) < 10 and abs(h - eh) < 10: + face["embedding"] = emb + attached += 1 + break + print(f"[TRACE] Attached {attached} embeddings to faces") + except Exception as e: + print(f"[TRACE] WARNING: Could not load embeddings: {e}") + # Load cut boundaries from cut.json (same directory as face.json) cut_boundaries = None cuts_path = face_json_path.replace("_traced.json", ".cut.json").replace(".face.json", ".cut.json") @@ -121,20 +171,18 @@ def store_traced_faces(file_uuid: str, traced_json_path: str, schema: str = SCHE try: cur.execute( f""" - INSERT INTO {schema}.face_detections - (file_uuid, frame_number, face_id, trace_id, - x, y, width, height, confidence, embedding) - VALUES (%s, %s, %s, %s, - %s, %s, %s, %s, %s, %s) - ON CONFLICT DO NOTHING + UPDATE {schema}.face_detections + SET trace_id = %s + WHERE file_uuid = %s AND frame_number = %s + AND x = %s AND y = %s AND width = %s AND height = %s """, ( - file_uuid, frame_num, face_id, trace_id, - x, y, w, h, confidence, - embed_vec, + trace_id, + file_uuid, frame_num, x, y, w, h, ), ) - total_stored += 1 + if cur.rowcount > 0: + total_stored += 1 except Exception as e: print(f"[TRACE] Error storing face at frame {frame_num}: {e}") conn.rollback()