2d-motion-interface / features2d.py
KanameYOkoYAMA's picture
Deploy 2D Motion Interface demo
0cdc216 verified
Raw
History Blame Contribute Delete
3.36 kB
"""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)