| """
|
| Body Part Groupings and Joint Metadata
|
| Defines how 17-joint skeleton maps to body part groups for scoring
|
| """
|
|
|
| import numpy as np
|
|
|
|
|
|
|
| JOINT_NAMES = [
|
| 'Hip',
|
| 'RightHip',
|
| 'RightKnee',
|
| 'RightAnkle',
|
| 'LeftHip',
|
| 'LeftKnee',
|
| 'LeftAnkle',
|
| 'Spine',
|
| 'Thorax',
|
| 'Neck',
|
| 'Head',
|
| 'LeftShoulder',
|
| 'LeftElbow',
|
| 'LeftWrist',
|
| 'RightShoulder',
|
| 'RightElbow',
|
| 'RightWrist',
|
| ]
|
|
|
|
|
| JOINT_GROUPS = {
|
| 'right_arm': [14, 15, 16],
|
| 'left_arm': [11, 12, 13],
|
| 'right_leg': [1, 2, 3],
|
| 'left_leg': [4, 5, 6],
|
| 'torso': [0, 7, 8, 9, 10],
|
| 'core': [0, 7, 8],
|
| 'upper_body': [7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
|
| 'lower_body': [0, 1, 2, 3, 4, 5, 6],
|
| }
|
|
|
|
|
|
|
| JOINT_NOISE_LEVELS = {
|
| 'core': 0.02,
|
| 'shoulders': 0.04,
|
| 'elbows': 0.06,
|
| 'wrists': 0.08,
|
| 'hands': 0.10,
|
| }
|
|
|
|
|
| JOINT_TO_NOISE_CATEGORY = {
|
| 0: 'core',
|
| 1: 'shoulders',
|
| 2: 'elbows',
|
| 3: 'wrists',
|
| 4: 'shoulders',
|
| 5: 'elbows',
|
| 6: 'wrists',
|
| 7: 'core',
|
| 8: 'core',
|
| 9: 'shoulders',
|
| 10: 'shoulders',
|
| 11: 'shoulders',
|
| 12: 'elbows',
|
| 13: 'wrists',
|
| 14: 'shoulders',
|
| 15: 'elbows',
|
| 16: 'wrists',
|
| }
|
|
|
|
|
| JOINT_PAIRS = [
|
| (0, 1),
|
| (1, 2),
|
| (2, 3),
|
| (0, 4),
|
| (4, 5),
|
| (5, 6),
|
| (0, 7),
|
| (7, 8),
|
| (8, 9),
|
| (9, 10),
|
| (8, 11),
|
| (11, 12),
|
| (12, 13),
|
| (8, 14),
|
| (14, 15),
|
| (15, 16),
|
| ]
|
|
|
|
|
| def get_body_part_joints(part_name):
|
| """
|
| Get joint indices for a body part group
|
|
|
| Args:
|
| part_name: Name of body part (e.g., 'right_arm', 'core')
|
|
|
| Returns:
|
| List of joint indices
|
| """
|
| if part_name not in JOINT_GROUPS:
|
| raise ValueError(f"Unknown body part: {part_name}. Available: {list(JOINT_GROUPS.keys())}")
|
| return JOINT_GROUPS[part_name]
|
|
|
|
|
| def get_joint_noise_level(joint_idx):
|
| """
|
| Get noise level for a specific joint
|
|
|
| Args:
|
| joint_idx: Joint index (0-16)
|
|
|
| Returns:
|
| Noise level (float) as fraction of body scale
|
| """
|
| if joint_idx not in JOINT_TO_NOISE_CATEGORY:
|
| return 0.05
|
| category = JOINT_TO_NOISE_CATEGORY[joint_idx]
|
| return JOINT_NOISE_LEVELS[category]
|
|
|
|
|
| def get_all_body_parts():
|
| """
|
| Get all available body part names
|
|
|
| Returns:
|
| List of body part names
|
| """
|
| return list(JOINT_GROUPS.keys())
|
|
|
|
|
| def get_joint_name(joint_idx):
|
| """
|
| Get human-readable name for a joint
|
|
|
| Args:
|
| joint_idx: Joint index (0-16)
|
|
|
| Returns:
|
| Joint name string
|
| """
|
| if 0 <= joint_idx < len(JOINT_NAMES):
|
| return JOINT_NAMES[joint_idx]
|
| return f"Joint_{joint_idx}"
|
|
|
|
|
| def get_joints_for_exercise(exercise_type):
|
| """
|
| Get relevant body parts for a specific exercise type
|
|
|
| Args:
|
| exercise_type: Type of exercise (e.g., 'pushup', 'squat', 'plank')
|
|
|
| Returns:
|
| List of body part names relevant to the exercise
|
| """
|
| exercise_focus = {
|
| 'pushup': ['core', 'right_arm', 'left_arm', 'torso'],
|
| 'squat': ['core', 'right_leg', 'left_leg', 'torso'],
|
| 'plank': ['core', 'torso', 'right_arm', 'left_arm'],
|
| 'lunge': ['core', 'right_leg', 'left_leg', 'torso'],
|
| 'all': list(JOINT_GROUPS.keys()),
|
| }
|
|
|
| return exercise_focus.get(exercise_type.lower(), exercise_focus['all'])
|
|
|
|
|
| def calculate_body_scale(poses):
|
| """
|
| Calculate body scale (hip-to-shoulder distance) for normalization
|
|
|
| Args:
|
| poses: Array of shape [frames, 17, 3] or [17, 3]
|
|
|
| Returns:
|
| Average body scale (float)
|
| """
|
| poses = np.array(poses)
|
| if len(poses.shape) == 2:
|
| poses = poses[np.newaxis, :, :]
|
|
|
|
|
| hip_to_thorax = np.linalg.norm(poses[:, 0, :] - poses[:, 8, :], axis=1)
|
| return np.mean(hip_to_thorax)
|
|
|
|
|
| if __name__ == "__main__":
|
|
|
| print("Body Part Groups:")
|
| for part, joints in JOINT_GROUPS.items():
|
| joint_names = [JOINT_NAMES[j] for j in joints]
|
| print(f" {part}: {joints} - {joint_names}")
|
|
|
| print("\nJoint Noise Levels:")
|
| for i in range(17):
|
| print(f" {JOINT_NAMES[i]}: {get_joint_noise_level(i)}")
|
|
|
| print("\nExercise Focus (Push-up):")
|
| print(f" {get_joints_for_exercise('pushup')}")
|
|
|
|
|