feat(viz): ARKit 91 -> MP 33 joint map
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"""ARKit ARSkeleton3D 91-joint indices → MediaPipe Pose 33 indices.
|
||||
|
||||
The ARKit ARSkeleton.JointName enum (Apple SDK) orders 91 joints
|
||||
starting with the root, hips, spine chain, shoulders, etc. We pick
|
||||
only the joints with a clear 1:1 anatomical correspondence to the
|
||||
MediaPipe Pose 33 landmark set (which is what AVLiveBody renders).
|
||||
Face/hand sub-joints (fingers, eyes) are skipped — those keep their
|
||||
existing data sources (MediaPipe Face/Hand + HaMeR MANO).
|
||||
|
||||
Reference for ARKit joint order : Apple developer docs
|
||||
"ARSkeleton.JointName" — the canonical 91-joint list runs from
|
||||
root_joint=0 down to right_handThumbEndJoint=90.
|
||||
|
||||
The selection here mirrors `multi.py::SMPLX_TO_MP33` so the same 14
|
||||
body slots are overridden by ARKit when fresh. Confidence comes
|
||||
from ARKit's tracking state but is not currently fanned out — we
|
||||
trust ARKit body tracking when its OSC frame is present.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
# MediaPipe Pose 33 cardinality (cf. mediapipe pose_world_landmarks).
|
||||
MP33_NUM_LANDMARKS = 33
|
||||
|
||||
# Pelvis = ARKit hips_joint, slot 1 in the canonical enum order.
|
||||
# Used by multi_hmr_worker for cam-translation z lock.
|
||||
ARKIT_PELVIS_IDX = 1
|
||||
|
||||
# (arkit_joint_idx, mediapipe_pose_idx). Match the body slots used
|
||||
# by the SMPL-X body fusion in multi.py.
|
||||
ARKIT91_TO_MP33: tuple[tuple[int, int], ...] = (
|
||||
(50, 11), # left_shoulder_1_joint -> L_SHOULDER
|
||||
(32, 12), # right_shoulder_1_joint -> R_SHOULDER
|
||||
(53, 13), # left_arm_joint -> L_ELBOW
|
||||
(35, 14), # right_arm_joint -> R_ELBOW
|
||||
(54, 15), # left_forearm_joint -> L_WRIST
|
||||
(36, 16), # right_forearm_joint -> R_WRIST
|
||||
(62, 23), # left_upLeg_joint -> L_HIP
|
||||
(57, 24), # right_upLeg_joint -> R_HIP
|
||||
(63, 25), # left_leg_joint -> L_KNEE
|
||||
(58, 26), # right_leg_joint -> R_KNEE
|
||||
(64, 27), # left_foot_joint -> L_ANKLE
|
||||
(59, 28), # right_foot_joint -> R_ANKLE
|
||||
(65, 31), # left_toes_joint -> L_FOOT_INDEX
|
||||
(60, 32), # right_toes_joint -> R_FOOT_INDEX
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
"""ARKit 91 joints → MediaPipe Pose 33 mapping integrity."""
|
||||
from data_only_viz.arkit_joint_map import (
|
||||
ARKIT91_TO_MP33, ARKIT_PELVIS_IDX, MP33_NUM_LANDMARKS,
|
||||
)
|
||||
|
||||
|
||||
def test_mapping_is_tuple_of_pairs():
|
||||
assert isinstance(ARKIT91_TO_MP33, tuple)
|
||||
assert len(ARKIT91_TO_MP33) > 0
|
||||
for pair in ARKIT91_TO_MP33:
|
||||
assert isinstance(pair, tuple)
|
||||
assert len(pair) == 2
|
||||
|
||||
|
||||
def test_mapping_indices_in_range():
|
||||
for arkit_idx, mp33_idx in ARKIT91_TO_MP33:
|
||||
assert 0 <= arkit_idx < 91, f"arkit idx out of range: {arkit_idx}"
|
||||
assert 0 <= mp33_idx < MP33_NUM_LANDMARKS, \
|
||||
f"mp33 idx out of range: {mp33_idx}"
|
||||
|
||||
|
||||
def test_pelvis_index_valid():
|
||||
assert 0 <= ARKIT_PELVIS_IDX < 91
|
||||
|
||||
|
||||
def test_no_duplicate_mp33_targets():
|
||||
"""Each MediaPipe slot must be written by at most one ARKit joint."""
|
||||
mp33_seen = set()
|
||||
for _, mp33_idx in ARKIT91_TO_MP33:
|
||||
assert mp33_idx not in mp33_seen, \
|
||||
f"mp33 slot {mp33_idx} mapped twice"
|
||||
mp33_seen.add(mp33_idx)
|
||||
Reference in New Issue
Block a user