-
Notifications
You must be signed in to change notification settings - Fork 28
Add AlphaPose WholeBody-133 JSON to pose-format conversion CLI #191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add AlphaPose WholeBody-133 JSON to pose-format conversion CLI #191
Conversation
- Introduce json_to_pose CLI tool for converting AlphaPose JSON outputs to .pose - Add AlphaPose WholeBody (133 keypoints) parser and keypoint reordering utility - Support optional metadata extraction (fps, width, height) from JSON or original video - Register json_to_pose as an installable console script - Document JSON → .pose conversion workflow in README
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new CLI tool for converting AlphaPose WholeBody-133 JSON outputs into pose-format (.pose) files, enabling seamless integration of AlphaPose outputs into pose-format pipelines.
Changes:
- Added
json_to_poseCLI tool for converting JSON pose estimation outputs to .pose format - Implemented AlphaPose WholeBody-133 parser with keypoint reordering utilities
- Added support for optional metadata extraction from JSON or original RGB video
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
src/python/pyproject.toml |
Registers the new json_to_pose CLI command |
src/python/pose_format/utils/alphapose.py |
Implements AlphaPose WholeBody-133 parsing, components definition, and keypoint reordering |
src/python/pose_format/bin/json_to_pose.py |
Provides the CLI tool for converting JSON to .pose format with metadata extraction |
README.md |
Documents the new conversion workflow and usage examples |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| PoseHeaderComponent( | ||
| name="BODY", | ||
| points=BODY_POINTS, | ||
| limbs= map_limbs(BODY_POINTS, BODY_LIMBS_NAMES), |
Copilot
AI
Jan 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace after the comma on line 98. This is inconsistent with line 114 and 122 which don't have trailing spaces.
| limbs= map_limbs(BODY_POINTS, BODY_LIMBS_NAMES), | |
| limbs= map_limbs(BODY_POINTS, BODY_LIMBS_NAMES), |
| PoseHeaderComponent( | ||
| name="LEFT_HAND", | ||
| points=LEFT_HAND_POINTS, | ||
| limbs= map_limbs(LEFT_HAND_POINTS, LEFT_HAND_LIMBS_NAMES), |
Copilot
AI
Jan 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace after the comma on line 114. This is inconsistent with line 122 which doesn't have a trailing space.
| from ..numpy.pose_body import NumPyPoseBody | ||
| from ..pose import Pose | ||
| from ..pose_header import PoseHeader, PoseHeaderComponent, PoseHeaderDimensions | ||
| from pose_format.utils.openpose import hand_colors |
Copilot
AI
Jan 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import "hand_colors" from "pose_format.utils.openpose" is unused and should be removed.
| from pose_format.utils.openpose import hand_colors |
| "right_big_toe","right_small_toe","right_heel", | ||
| ] | ||
|
|
||
| FACE_POINTS = [f"face-{i}" for i in range(68)] |
Copilot
AI
Jan 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent naming convention: face points use hyphens ("face-0", "face-1") while hand points use underscores ("left_hand_0", "right_hand_0"). This should be consistent for maintainability.
| FACE_POINTS = [f"face-{i}" for i in range(68)] | |
| FACE_POINTS = [f"face_{i}" for i in range(68)] |
| video_path : string | ||
| Path to input video file. |
Copilot
AI
Jan 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter name in the docstring is "video_path" but the actual parameter is "input_path". The docstring should be updated to match the function signature.
| video_path : string | |
| Path to input video file. | |
| input_path : string | |
| Path to input AlphaPose JSON file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this comment is probably wrong, but it probably means the docstring is not good
| Loads alphapose_wholebody pose data | ||
|
|
||
| Parameters | ||
| ---------- | ||
| video_path : string | ||
| Path to input video file. | ||
|
|
||
| Returns | ||
| ------- | ||
| Pose | ||
| Loaded pose data with header and body |
Copilot
AI
Jan 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring is incomplete - it doesn't document the parameters "version", "fps", "width", "height", or "depth".
| Loads alphapose_wholebody pose data | |
| Parameters | |
| ---------- | |
| video_path : string | |
| Path to input video file. | |
| Returns | |
| ------- | |
| Pose | |
| Loaded pose data with header and body | |
| Loads alphapose_wholebody pose data. | |
| Parameters | |
| ---------- | |
| input_path : str | |
| Path to the input AlphaPose JSON file. | |
| version : float, optional | |
| Pose format version stored in the :class:`PoseHeader`. Defaults to 0.2. | |
| fps : float, optional | |
| Frames per second used in the :class:`NumPyPoseBody`. May be overridden by JSON metadata. Defaults to 24. | |
| width : int, optional | |
| Frame width in pixels for :class:`PoseHeaderDimensions`. May be overridden by JSON metadata. Defaults to 1000. | |
| height : int, optional | |
| Frame height in pixels for :class:`PoseHeaderDimensions`. May be overridden by JSON metadata. Defaults to 1000. | |
| depth : int, optional | |
| Depth dimension for :class:`PoseHeaderDimensions`. Defaults to 0. | |
| Returns | |
| ------- | |
| Pose | |
| Loaded pose data with header and body. |
| The library supports converting pose estimation outputs stored as `.json` files into the `.pose` format via `json_to_pose` utility. | ||
|
|
||
| > **Note** | ||
| > - At the moment, `json_to_pose` only supports [AlphaPose](https://github.com/MVIG-SJTU/AlphaPose) models with **133 keypoints** JSON files with 133 keypoints. |
Copilot
AI
Jan 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicated text in the README: "JSON files with 133 keypoints" appears twice in the same sentence.
| > - At the moment, `json_to_pose` only supports [AlphaPose](https://github.com/MVIG-SJTU/AlphaPose) models with **133 keypoints** JSON files with 133 keypoints. | |
| > - At the moment, `json_to_pose` only supports [AlphaPose](https://github.com/MVIG-SJTU/AlphaPose) models whose JSON outputs contain **133 keypoints**. |
…ils) - Move AlphaPose point/limb definitions to module-level constants and rename components builder to get_alphapose_components()\n- Extend KnownPoseFormat and format detection to include alphapose\n- Add alphapose handling in pose_hide_legs, pose_shoulders, hands_components, get_hand_wrist_index, and get_body_hand_wrist_index\n- Update tests to cover leg removal and detected format for alphapose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 5 out of 6 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if known_pose_format == "sapiens": | ||
| return [ | ||
| pose_header.get_point_index("LEFT_HAND", "hand_9"), | ||
| pose_header.get_point_index("RIGHT_HAND", "hand_9"), | ||
| ] |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hands_indexes() contains a branch for known_pose_format == "sapiens", but detect_known_pose_format() cannot return "sapiens" (and KnownPoseFormat doesn’t include it). This code is currently unreachable and also inconsistent with the declared type. Either remove this branch, or add full "sapiens" support (update KnownPoseFormat and detect_known_pose_format()).
| if known_pose_format == "sapiens": | |
| return [ | |
| pose_header.get_point_index("LEFT_HAND", "hand_9"), | |
| pose_header.get_point_index("RIGHT_HAND", "hand_9"), | |
| ] |
| Creates a list of alphapose components. | ||
|
|
||
| Returns | ||
| ------- | ||
| list of PoseHeaderComponent | ||
| List of holistic components. |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_alphapose_components() docstring says it returns a "List of holistic components", which is incorrect/misleading. Please update the docstring to refer to AlphaPose components (and ensure the return description matches the actual component set).
| Creates a list of alphapose components. | |
| Returns | |
| ------- | |
| list of PoseHeaderComponent | |
| List of holistic components. | |
| Creates a list of AlphaPose components. | |
| Returns | |
| ------- | |
| list of PoseHeaderComponent | |
| List of AlphaPose components (BODY, FACE, LEFT_HAND, RIGHT_HAND). |
| print("Loading pose with alphapose_wholebody...") | ||
|
|
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This utility function prints directly to stdout (print("Loading pose with alphapose_wholebody...")). In a library module this makes it hard for downstream users to control logging. Consider removing the print or switching to the project’s logging approach (or gating it behind a verbose flag).
| assert len(flat) == 133 * 3, \ | ||
| f"ERROR: Expected 133 keypoints (399 values), but got {len(flat)} values. " \ | ||
| f"This converter only supports AlphaPose WholeBody-133." |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parse_keypoints_and_confidence() uses an assert for input validation. Assertions can be disabled with python -O, which would skip this check and then fail later in less clear ways. Please raise a ValueError (or a domain-specific exception) when the keypoint vector length is not 133 * 3.
| assert len(flat) == 133 * 3, \ | |
| f"ERROR: Expected 133 keypoints (399 values), but got {len(flat)} values. " \ | |
| f"This converter only supports AlphaPose WholeBody-133." | |
| if len(flat) != 133 * 3: | |
| raise ValueError( | |
| f"ERROR: Expected 133 keypoints (399 values), but got {len(flat)} values. " | |
| f"This converter only supports AlphaPose WholeBody-133." | |
| ) |
| def load_alphapose_wholebody_from_json(input_path: str, | ||
| version: float = 0.2, | ||
| fps: float = 24, | ||
| width=1000, | ||
| height=1000, | ||
| depth=0) -> Pose: | ||
| """ | ||
| Loads alphapose_wholebody pose data | ||
|
|
||
| Parameters | ||
| ---------- | ||
| video_path : string | ||
| Path to input video file. | ||
|
|
||
| Returns | ||
| ------- | ||
| Pose | ||
| Loaded pose data with header and body | ||
| """ | ||
| print("Loading pose with alphapose_wholebody...") | ||
|
|
||
| # Load frames + optional metadata | ||
| frames, metadata = load_alphapose_json(input_path) | ||
|
|
||
| # Override fps/width/height ONLY if metadata exists | ||
| if metadata is not None: | ||
| if metadata.get("fps") is not None: | ||
| fps = metadata["fps"] | ||
| if metadata.get("width") is not None: | ||
| width = metadata["width"] | ||
| if metadata.get("height") is not None: | ||
| height = metadata["height"] | ||
|
|
||
| frames_xy = [] | ||
| frames_conf = [] | ||
|
|
||
| # Parse and reorder all frames | ||
| for item in frames: | ||
| xy, conf = parse_keypoints_and_confidence(item["keypoints"]) | ||
| xy_ord, conf_ord = reorder_133_kpts(xy, conf) | ||
|
|
||
| frames_xy.append(xy_ord) | ||
| frames_conf.append(conf_ord) | ||
|
|
||
| # Convert to arrays | ||
| xy_data = np.stack(frames_xy, axis=0) # (num_frames, num_keypoints, 2) | ||
| conf_data = np.stack(frames_conf, axis=0) # (num_frames, num_keypoints) | ||
|
|
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test coverage: this new AlphaPose WholeBody-133 JSON loader/reordering logic isn’t covered by unit tests. There are existing loader tests (e.g. utils/openpose_test.py)—please add similar tests that (1) validate JSON parsing for both supported formats, (2) verify output shapes, and (3) verify keypoint reordering/metadata override behavior.
| from pose_format.utils.openpose import BODY_POINTS as OPENPOSE_BODY_POINTS | ||
| from pose_format.utils.openpose_135 import OpenPose_Components as OpenPose135_Components | ||
| from pose_format.utils.alphapose import get_alphapose_components | ||
| from pose_format.utils.alphapose import BODY_POINTS as ALPHAPOSE_BODY_POINTS |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ALPHAPOSE_BODY_POINTS is imported but never used in this module. Please remove the unused import to avoid lint/type-check noise.
| from pose_format.utils.alphapose import BODY_POINTS as ALPHAPOSE_BODY_POINTS |
This PR adds support for converting AlphaPose WholeBody (133 keypoints) JSON outputs
into pose-format (.pose) files.
json_to_poseCLI toolThis enables seamless integration of AlphaPose outputs into pose-format pipelines,
which is particularly useful for sign language processing workflows.