Spaces:
Running on Zero
Running on Zero
| """Standalone 2D keypoint -> feature conversion. | |
| Extracted verbatim from src.data.adapter_datasets._VitPoseMixin so the demo | |
| carries no dependency on Text2MotionDataset / HumanML3D / glove. | |
| Two feature layouts are produced: | |
| * 81-dim "estimated" features (with per-joint confidence) -> adapter input | |
| * 68-dim features (without confidence) -> adapter-less input | |
| """ | |
| import json | |
| import numpy as np | |
| # COCO-17 -> COCO-13: drop eyes/ears (indices 1,2,3,4) | |
| COCO17_TO_COCO13 = [0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] | |
| COCO13 = ['nose', 'left_shoulder', 'right_shoulder', 'left_elbow', 'right_elbow', | |
| 'left_wrist', 'right_wrist', 'left_hip_extra', 'right_hip_extra', | |
| 'left_knee', 'right_knee', 'left_ankle', 'right_ankle'] | |
| _LHIP = COCO13.index('left_hip_extra') | |
| _RHIP = COCO13.index('right_hip_extra') | |
| def load_vitpose_json(path): | |
| """<id>.json -> (keypoints (T,17,2), confidences (T,17)) as float32.""" | |
| data = json.load(open(path)) | |
| kp = np.array([f["instances"][0]["keypoints"] for f in data], dtype=np.float32) | |
| cf = np.array([f["instances"][0]["keypoint_scores"] for f in data], dtype=np.float32) | |
| return kp, cf | |
| def to_coco13(kp, cf): | |
| return kp[:, COCO17_TO_COCO13, :], cf[:, COCO17_TO_COCO13] | |
| def normalize_2d_coco13_midhip(joints_2d, eps=1e-8, q=99): | |
| """Mid-hip-centred, scale-normalised 2D joints. Scale makes this | |
| resolution-independent, so raw pixel coordinates are fine as input.""" | |
| joints_2d = np.asarray(joints_2d) | |
| root_pos = 0.5 * (joints_2d[:, _LHIP, :] + joints_2d[:, _RHIP, :]) | |
| joints_rel = joints_2d - root_pos[:, None, :] | |
| abs_xy = np.abs(joints_rel).reshape(-1, 2) | |
| s = max(np.percentile(abs_xy[:, 0], q), np.percentile(abs_xy[:, 1], q), eps) | |
| return root_pos, joints_rel, s | |
| def decompose_2d_motion_coco13_midhip_root(joints_2d): | |
| root_pos, joints_rel, s = normalize_2d_coco13_midhip(joints_2d) | |
| root_y_2d = (root_pos[:, 1:2] / s).astype(np.float32) | |
| root_y_2d = root_y_2d - root_y_2d[0:1] | |
| joints_pos_2d = (joints_rel / s).reshape(joints_rel.shape[0], -1).astype(np.float32) | |
| root_norm = (root_pos / s).astype(np.float32) | |
| root_vel_2d = np.zeros_like(root_norm) | |
| root_vel_2d[1:] = root_norm[1:] - root_norm[:-1] | |
| return root_y_2d, joints_pos_2d, root_vel_2d | |
| def compute_joint_features_2d_coco13(joints_2d): | |
| _, joints_rel, s = normalize_2d_coco13_midhip(joints_2d) | |
| joints_rel_norm = (joints_rel / s).astype(np.float32) | |
| rot = np.arctan2(joints_rel_norm[:, :, 1], joints_rel_norm[:, :, 0]).astype(np.float32) | |
| vel = np.zeros_like(joints_rel_norm) | |
| vel[1:] = joints_rel_norm[1:] - joints_rel_norm[:-1] | |
| vel = vel.reshape(joints_rel_norm.shape[0], -1).astype(np.float32) | |
| return rot, vel | |
| def feature_68(joints_2d): | |
| """[root_vel(2), root_y(1), joints_pos(26), joints_rot(13), joints_vel(26)]""" | |
| root_y, joints_pos, root_vel = decompose_2d_motion_coco13_midhip_root(joints_2d) | |
| joints_rot, joints_vel = compute_joint_features_2d_coco13(joints_2d) | |
| return np.concatenate([root_vel, root_y, joints_pos, joints_rot, joints_vel], axis=-1) | |
| def feature_81(joints_2d, conf): | |
| """feature_68 with per-joint confidence appended (adapter input).""" | |
| feat = feature_68(joints_2d) | |
| c = np.asarray(conf).reshape(feat.shape[0], -1) | |
| return np.concatenate([feat, c], axis=-1) | |