diff --git a/fam-ui/src/app.py b/fam-ui/src/app.py index a5ba6ac..c2204ae 100644 --- a/fam-ui/src/app.py +++ b/fam-ui/src/app.py @@ -795,11 +795,12 @@ elif page == "👤 人物管理": real_to_label = {v: k for k, v in alias_map.items()} # 聚合每个真实人物出现的帧(时间升序) + # 聚合每个真实人物出现的帧(时间升序),保留原始 person 串供独照判定 person_frames = {} for r in detail_rows: for p in resolve_persons(r['person'], alias_map): person_frames.setdefault(p, []).append( - (r['event_id'], r['frame_index'], r['frame_timestamp'])) + (r['event_id'], r['frame_index'], r['frame_timestamp'], r['person'])) named_keys = [k for k in person_frames if k in real_to_label] st.markdown( @@ -823,19 +824,28 @@ elif page == "👤 人物管理": _meta_cache[event_id] = {} return _meta_cache[event_id] - def person_photo(frames): - """头像优先挑有人脸的帧(face_count 最大),其次按时间序第一张""" - best, best_faces = None, -1 - for eid, fidx, _ in frames: + def person_photo(key, frames): + """头像挑选策略: + 1. 优先『独照』——该帧只有当前人物一个标签且人脸数=1(不会拿双人图当头像) + 2. 无独照时退而求其次:人脸数最多的帧 + 3. 最后按时间序第一张兜底 + """ + solo, best, best_faces = None, None, -1 + for eid, fidx, _ts, person_str in frames: meta = _load_meta(eid) faces = int(meta.get(str(fidx), 0) or 0) - if faces > best_faces: + if faces == 1 and len(resolve_persons(person_str, alias_map)) == 1: + if solo is None: + solo = load_frame_b64(eid, fidx) + elif faces > best_faces: b64 = load_frame_b64(eid, fidx) if b64: best, best_faces = b64, faces + if solo: + return solo if best: return best - for eid, fidx, _ in frames: + for eid, fidx, _ts, _ps in frames: b64 = load_frame_b64(eid, fidx) if b64: return b64 @@ -888,7 +898,7 @@ elif page == "👤 人物管理": is_named = key in real_to_label label = real_to_label.get(key, key) feat = feat_map.get(label) or '暂无特征描述' - photo = person_photo(frames) + photo = person_photo(key, frames) first_ts = parse_ts(frames[0][2]) last_ts = parse_ts(frames[-1][2]) first_str = first_ts.strftime('%m-%d %H:%M') if first_ts else '--'