Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions scripts/build-web-catalog.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
from __future__ import annotations
import json
import os
from pose_guide.export import export_pose

from poseguide.web.catalog import write_web_catalog
def build_web_catalog():
"""Build web demo catalog with exported pose formats."""
# Load poses from fixtures
with open('tests/fixtures/export_fixtures.json', 'r') as f:
fixtures = json.load(f)

# Create output directory if it doesn't exist
os.makedirs('web/catalog', exist_ok=True)

if __name__ == "__main__":
print(write_web_catalog())
# Export each pose in both formats
for pose_name, pose_joints in fixtures.items():
# Export to COCO format
coco_data = export_pose(pose_joints, 'coco')
with open(f'web/catalog/{pose_name}_coco.json', 'w') as f:
json.dump(coco_data, f, indent=2)

# Export to MediaPipe format
mediapipe_data = export_pose(pose_joints, 'mediapipe')
with open(f'web/catalog/{pose_name}_mediapipe.json', 'w') as f:
json.dump(mediapipe_data, f, indent=2)

print("Web catalog built successfully")

if __name__ == '__main__':
build_web_catalog()
26 changes: 26 additions & 0 deletions src/pose_guide/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import argparse
import json
from .export import export_pose

def add_export_command(subparsers):
"""Add export command to CLI."""
export_parser = subparsers.add_parser('export', help='Export pose joints')
export_parser.add_argument('--input', required=True, help='Input pose joints JSON file')
export_parser.add_argument('--format', required=True, choices=['coco', 'mediapipe'], help='Export format')
export_parser.add_argument('--output', required=True, help='Output file path')

def handle_export(args):
"""Handle export command."""
try:
with open(args.input, 'r') as f:
pose_joints = json.load(f)

exported_data = export_pose(pose_joints, args.format)

with open(args.output, 'w') as f:
json.dump(exported_data, f, indent=2)

print(f"Successfully exported pose joints to {args.format} format at {args.output}")
except Exception as e:
print(f"Error exporting pose joints: {str(e)}")
raise
36 changes: 36 additions & 0 deletions src/pose_guide/export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import json
from typing import Dict, List, Union

def coco_format(pose_joints: List[Dict[str, Union[float, int]]]) -> Dict:
"""Convert pose joints to COCO keypoints format."""
coco_keypoints = []
for joint in pose_joints:
coco_keypoints.extend([
joint['x'], joint['y'], joint.get('score', 1.0)
])
return {
'keypoints': coco_keypoints,
'num_keypoints': len(pose_joints)
}

def mediapipe_format(pose_joints: List[Dict[str, Union[float, int]]]) -> Dict:
"""Convert pose joints to MediaPipe keypoints format."""
mediapipe_keypoints = []
for joint in pose_joints:
mediapipe_keypoints.append({
'x': joint['x'],
'y': joint['y'],
'score': joint.get('score', 1.0)
})
return {
'keypoints': mediapipe_keypoints
}

def export_pose(pose_joints: List[Dict[str, Union[float, int]]], format: str) -> Dict:
"""Export pose joints to specified format."""
if format.lower() == 'coco':
return coco_format(pose_joints)
elif format.lower() == 'mediapipe':
return mediapipe_format(pose_joints)
else:
raise ValueError(f"Unsupported export format: {format}")
12 changes: 12 additions & 0 deletions tests/fixtures/export_fixtures.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"test_pose_1": [
{"x": 10, "y": 20, "score": 0.9},
{"x": 30, "y": 40, "score": 0.8},
{"x": 50, "y": 60}
],
"test_pose_2": [
{"x": 15, "y": 25, "score": 0.7},
{"x": 35, "y": 45, "score": 0.6},
{"x": 55, "y": 65, "score": 0.5}
]
}
68 changes: 68 additions & 0 deletions tests/test_export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import unittest
import json
from pose_guide.export import coco_format, mediapipe_format, export_pose

class TestExport(unittest.TestCase):
def setUp(self):
self.test_pose = [
{'x': 10, 'y': 20, 'score': 0.9},
{'x': 30, 'y': 40, 'score': 0.8},
{'x': 50, 'y': 60}
]

def test_coco_format(self):
result = coco_format(self.test_pose)
self.assertEqual(result['num_keypoints'], 3)
self.assertEqual(len(result['keypoints']), 9)
self.assertEqual(result['keypoints'][0], 10)
self.assertEqual(result['keypoints'][1], 20)
self.assertEqual(result['keypoints'][2], 0.9)
self.assertEqual(result['keypoints'][6], 50)
self.assertEqual(result['keypoints'][7], 60)
self.assertEqual(result['keypoints'][8], 1.0)

def test_mediapipe_format(self):
result = mediapipe_format(self.test_pose)
self.assertEqual(len(result['keypoints']), 3)
self.assertEqual(result['keypoints'][0]['x'], 10)
self.assertEqual(result['keypoints'][0]['y'], 20)
self.assertEqual(result['keypoints'][0]['score'], 0.9)
self.assertEqual(result['keypoints'][2]['x'], 50)
self.assertEqual(result['keypoints'][2]['y'], 60)
self.assertEqual(result['keypoints'][2]['score'], 1.0)

def test_export_pose(self):
coco_result = export_pose(self.test_pose, 'coco')
self.assertEqual(coco_result['num_keypoints'], 3)

mediapipe_result = export_pose(self.test_pose, 'mediapipe')
self.assertEqual(len(mediapipe_result['keypoints']), 3)

with self.assertRaises(ValueError):
export_pose(self.test_pose, 'invalid')

def test_round_trip(self):
# Test round-trip for COCO format
coco_exported = coco_format(self.test_pose)
coco_imported = []
for i in range(0, len(coco_exported['keypoints']), 3):
coco_imported.append({
'x': coco_exported['keypoints'][i],
'y': coco_exported['keypoints'][i+1],
'score': coco_exported['keypoints'][i+2]
})
self.assertEqual(len(coco_imported), len(self.test_pose))

# Test round-trip for MediaPipe format
mediapipe_exported = mediapipe_format(self.test_pose)
mediapipe_imported = []
for keypoint in mediapipe_exported['keypoints']:
mediapipe_imported.append({
'x': keypoint['x'],
'y': keypoint['y'],
'score': keypoint['score']
})
self.assertEqual(len(mediapipe_imported), len(self.test_pose))

if __name__ == '__main__':
unittest.main()
Loading