Files
momentry_core/scripts/compare_pose_detections.py
T
Accusys 39a2cbc65b fix: face group name read consistency, sync_file_status fix, cleanup ghost records, identity_agent replaced with face_dedup
- get_face_groups_handler: COALESCE(tp.name, tn.label) for name consistency
- sync_file_status: compare JSON vs pre_chunks (not chunk table)
- face consistency: compare frames.len() not total_faces
- cleanup 2 ghost records with NULL file_name/file_path
- replace identity_agent with face_dedup in pipeline stages
- remove identity_agent_api.rs and all references
- update required_processors to match actual processors
- update AGENTS.md with team responsibilities
- add Studio pipeline changes documentation
2026-07-27 02:15:51 +08:00

148 lines
5.0 KiB
Python

#!/opt/homebrew/bin/python3.11
"""
Compare Apple Vision pose vs MediaPipe pose
Finds:
- Intersection: Poses detected by both
- Apple Vision only: Poses only in Apple Vision
- MediaPipe only: Poses only in MediaPipe
Usage:
python3 scripts/compare_pose_detections.py --file-uuid <uuid>
"""
import argparse
import json
from pathlib import Path
def load_apple_vision_poses(file_uuid, output_dir):
"""Load Apple Vision pose data from pose.json"""
pose_path = Path(output_dir) / f"{file_uuid}.pose.json"
if not pose_path.exists():
return {}
with open(pose_path) as f:
data = json.load(f)
poses = {}
for frame in data.get('frames', []):
frame_num = frame.get('frame', frame.get('frame_number', 0))
for i, person in enumerate(frame.get('persons', [])):
pose_key = f"frame_{frame_num}_person_{i}"
poses[pose_key] = {
'frame': frame_num,
'person_idx': i,
'keypoints': person.get('keypoints', []),
'source': 'apple_vision'
}
return poses
def load_mediapipe_poses(file_uuid, output_dir):
"""Load MediaPipe pose data from pose.mediapipe.json"""
pose_path = Path(output_dir) / f"{file_uuid}.pose.mediapipe.json"
if not pose_path.exists():
return {}
with open(pose_path) as f:
data = json.load(f)
poses = {}
for frame in data.get('frames', []):
frame_num = frame.get('frame', 0)
for i, person in enumerate(frame.get('persons', [])):
pose_key = f"frame_{frame_num}_person_{i}"
poses[pose_key] = {
'frame': frame_num,
'person_idx': i,
'keypoints': person.get('keypoints', []),
'source': 'mediapipe'
}
return poses
def compare_poses(file_uuid, output_dir):
"""Compare Apple Vision vs MediaPipe poses."""
print(f"[compare] Loading pose data for {file_uuid}...")
av_poses = load_apple_vision_poses(file_uuid, output_dir)
mp_poses = load_mediapipe_poses(file_uuid, output_dir)
print(f"[compare] Apple Vision poses: {len(av_poses)}")
print(f"[compare] MediaPipe poses: {len(mp_poses)}")
# Find intersection and differences
av_keys = set(av_poses.keys())
mp_keys = set(mp_poses.keys())
intersection = av_keys & mp_keys
av_only = av_keys - mp_keys
mp_only = mp_keys - av_keys
print(f"\n[compare] === COMPARISON ===")
print(f"[compare] Intersection (both detected): {len(intersection)}")
print(f"[compare] Apple Vision only: {len(av_only)}")
print(f"[compare] MediaPipe only: {len(mp_only)}")
# Analyze intersection - check alignment
intersection_aligned = 0
for key in intersection:
av_pose = av_poses[key]
mp_pose = mp_poses[key]
# Check if both have face keypoints
av_face_kps = [kp for kp in av_pose.get('keypoints', []) if kp.get('name') in ['nose', 'left_eye', 'right_eye']]
mp_face_kps = [kp for kp in mp_pose.get('keypoints', []) if kp.get('name') in ['nose', 'left_eye', 'right_eye']]
if av_face_kps and mp_face_kps:
intersection_aligned += 1
print(f"\n[compare] Intersection with face keypoints: {intersection_aligned}")
# Frame coverage
av_frames = set(av_poses[k]['frame'] for k in av_keys)
mp_frames = set(mp_poses[k]['frame'] for k in mp_keys)
print(f"\n[compare] === FRAME COVERAGE ===")
print(f"[compare] Apple Vision frames: {len(av_frames)}")
print(f"[compare] MediaPipe frames: {len(mp_frames)}")
print(f"[compare] Overlapping frames: {len(av_frames & mp_frames)}")
# Save results
output_path = Path(output_dir) / f"{file_uuid}.pose_comparison.json"
with open(output_path, 'w') as f:
json.dump({
'apple_vision_count': len(av_poses),
'mediapipe_count': len(mp_poses),
'intersection_count': len(intersection),
'apple_vision_only_count': len(av_only),
'mediapipe_only_count': len(mp_only),
'intersection_aligned_count': intersection_aligned,
'apple_vision_frames': len(av_frames),
'mediapipe_frames': len(mp_frames),
'overlapping_frames': len(av_frames & mp_frames),
'intersection_keys': sorted(list(intersection))[:100], # Sample
'apple_vision_only_keys': sorted(list(av_only))[:100],
'mediapipe_only_keys': sorted(list(mp_only))[:100],
}, f, indent=2)
print(f"\n[compare] Results saved to: {output_path}")
def main():
parser = argparse.ArgumentParser(description="Compare pose detections")
parser.add_argument("--file-uuid", "-u", required=True, help="File UUID")
parser.add_argument("--output-dir", "-o", default="/Users/accusys/momentry/output", help="Output directory")
args = parser.parse_args()
compare_poses(args.file_uuid, args.output_dir)
if __name__ == "__main__":
main()