Technique analysis
How to use the api and interpret the output
Technique Analysis API Documentation
Overview
The Technique Analysis Server provides a REST API for analyzing sports technique from video data. It processes video files containing human motion and returns detailed analysis results including pose estimation, technique features, and performance metrics.
Server Endpoints
Main Processing Endpoint
POST /process
Processes a video file and returns comprehensive analysis results.
Request Format
The endpoint accepts multipart/form-data with the following fields:
file(required): Video file (supports .mp4, .avi, .mov, .mkv)metadata(required): JSON string containing analysis parameters
Metadata Parameters
{
"uid": "unique_identifier",
"store_data": false,
"sport": "pickleball",
"swing_type": "forehand_drive",
"dominant_hand": "right",
"player_height_mm": 1800,
"request_id": "optional_request_id",
"timestamp": "2025-09-26T00:09:46.122307",
"form_session_id": "optional_session_id",
"ball_timestamp": 1.5
}Required Parameters:
uid: Unique identifier for the requestsport: Sport type (e.g., "pickleball", "tennis", "none")swing_type: Type of swing/technique (e.g., "forehand_drive", "backhand_drive")dominant_hand: Player's dominant hand ("left" or "right")player_height_mm: Player height in millimeters
Optional Parameters:
store_data: Whether to store data to S3 (default: false)ball_timestamp: Ball hit timestamp for test cases (auto-detected if not provided)request_id: Optional request identifiertimestamp: Request timestampform_session_id: Form session identifier
Response Format
The API returns a streaming JSON response with the following structure:
{
"status": "done",
"uid": "unique_identifier",
"warnings": [],
"errors": [],
"result": {
"features": [...],
"feature_categories": {...},
"kinetic_chain": {...},
"wrist_speed": {...}
},
"video_entry_2D_json": {...},
"video_entry_3D_json": {...}
}Supported Sports and Techniques
Pickleball
- forehand_drive: Forehand drive technique
- backhand_drive: Backhand drive technique (2-handed)
Response Interpretation
Status Codes
- "processing": Video is being processed
- "done": Analysis completed successfully
- "error": Analysis failed
- "failed": Critical error occurred
Result Structure
Features Array
Each feature in the features array contains:
{
"feature_name": "leg_width_at_ball_hit",
"feature_human_readable_name": "Leg Width at Ball Hit",
"level": "advanced",
"score": 85.0,
"value": 0.8,
"observation": "Your leg width is optimal for stability and power",
"suggestion": "Maintain this stance width for consistent performance",
"feature_categories": ["balance", "lower_body", "stability"],
"highlight_joints": [15, 16],
"highlight_limbs": {
"left_lower_leg": [15, 13],
"right_lower_leg": [16, 14]
},
"event": {
"name": "ball_hit",
"timestamp": 1.5,
"frame_nr": 45
},
"score_ranges": {
"beginner": [0, 40],
"intermediate": [40, 60],
"advanced": [60, 80],
"professional": [80, 100]
},
"value_ranges": {
"beginner": [0.0, 0.3],
"intermediate": [0.3, 0.5],
"advanced": [0.5, 0.7],
"professional": [0.7, 1.0]
}
}Feature Categories
The feature_categories object provides aggregated statistics:
{
"balance": {
"average_score": 78.5,
"feature_count": 5,
"features": ["leg_width_at_ball_hit", "stance_stability", ...]
},
"power": {
"average_score": 82.3,
"feature_count": 3,
"features": ["kinetic_chain_coordination", ...]
}
}Kinetic Chain Analysis
The kinetic_chain object contains motion analysis:
{
"speed_dict": {
"hip": {
"plot_values": [0.1, 0.3, 0.8, 1.2, 0.9, ...],
"peak_index": 3,
"peak_speed": 1.2
},
"shoulder": {
"plot_values": [0.2, 0.4, 0.9, 1.1, 0.8, ...],
"peak_index": 3,
"peak_speed": 1.1
},
"wrist": {
"plot_values": [0.1, 0.2, 0.5, 1.5, 1.8, ...],
"peak_index": 4,
"peak_speed": 1.8
}
}
}Pose Data
2D Pose Data (video_entry_2D_json)
Contains 2D pose estimation results:
{
"entry_type": "video",
"source_path": "/path/to/video.mp4",
"annotation_format": "H36M",
"annotation_data": [
{
"frame_nr": 0,
"timestamp": 0.0,
"instances": [
{
"keypoints": [[x1, y1], [x2, y2], ...],
"confidences": [0.9, 0.8, ...],
"bbox": [x, y, width, height],
"box_confidence": 0.95
}
]
}
]
}3D Pose Data (video_entry_3D_json)
Contains 3D pose estimation results:
{
"entry_type": "video",
"source_path": "/path/to/video.mp4",
"annotation_format": "H36M",
"annotation_data": [
{
"frame_nr": 0,
"timestamp": 0.0,
"instances": [
{
"keypoints": [[x1, y1, z1], [x2, y2, z2], ...],
"confidences": [0.9, 0.8, ...],
"bbox": [x, y, width, height],
"box_confidence": 0.95
}
]
}
]
}Usage Examples
Example 1: Basic Pickleball Forehand Analysis
curl -X POST "http://192.168.50.187:6000/process" \
-F "file=@forehand_video.mp4" \
-F 'metadata={"uid":"test_001","sport":"pickleball","swing_type":"forehand_drive","dominant_hand":"right","player_height_mm":1750}'Example 2: Python Request
import requests
import json
# Prepare metadata
metadata = {
"uid": "python_test_001",
"sport": "pickleball",
"swing_type": "forehand_drive",
"dominant_hand": "right",
"player_height_mm": 1800,
"store_data": False
}
# Send request
with open("video.mp4", "rb") as f:
files = {"file": ("video.mp4", f)}
data = {"metadata": json.dumps(metadata)}
response = requests.post(
"http://192.168.50.187:6000/process",
files=files,
data=data,
stream=True
)
# Process streaming response
for line in response.iter_lines(decode_unicode=True):
if line:
result = json.loads(line)
if result.get("status") == "done":
print("Analysis completed!")
print(f"Features found: {len(result['result']['features'])}")
breakError Handling
Common Error Responses
Invalid Request Format
{
"error": "Invalid response format",
"status": "error",
"timestamp": "2025-09-26T00:21:44.754097",
"uid": "webapp_b5ef741e"
}Server Processing Error
{
"status": "failed",
"uid": "unique_identifier",
"errors": ["Detailed error message"],
"warnings": ["Warning message"]
}Debugging Tips
- Check Video Quality: Ensure the video contains clear human poses
- Verify Parameters: Confirm sport/swing type combinations are valid
- Check Player Height: Use accurate height measurements in millimeters
- Video Duration: Ensure video includes the complete swing motion
- Audio Quality: For ball hit detection, ensure audio is clear
Output Files
The server also provides a ZIP file containing:
video_entry_2d.pb: 2D pose data in protobuf formatvideo_entry_3d.pb: 3D pose data in protobuf formattechnique_analysis.json: Analysis results in JSON format
Performance Considerations
- Processing Time: Typically 30-120 seconds depending on video length
- Video Length: Recommended 3-10 seconds for optimal analysis
- Resolution: Higher resolution videos may take longer to process
- Frame Rate: 30fps recommended for smooth motion capture
Integration Examples
Web Application Integration
// Frontend JavaScript example
async function analyzeVideo(videoFile, metadata) {
const formData = new FormData();
formData.append('file', videoFile);
formData.append('metadata', JSON.stringify(metadata));
const response = await fetch('/process', {
method: 'POST',
body: formData
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.trim()) {
const result = JSON.parse(line);
if (result.status === 'done') {
return result;
}
}
}
}
}Batch Processing
import os
import json
import requests
from pathlib import Path
def batch_analyze_videos(video_directory, output_directory):
"""Process multiple videos in batch"""
video_files = list(Path(video_directory).glob("*.mp4"))
results = []
for video_file in video_files:
metadata = {
"uid": f"batch_{video_file.stem}",
"sport": "pickleball",
"swing_type": "forehand_drive",
"dominant_hand": "right",
"player_height_mm": 1800
}
try:
with open(video_file, "rb") as f:
files = {"file": (video_file.name, f)}
data = {"metadata": json.dumps(metadata)}
response = requests.post(
"http://192.168.50.187:6000/process",
files=files,
data=data,
stream=True
)
# Process response
for line in response.iter_lines(decode_unicode=True):
if line:
result = json.loads(line)
if result.get("status") == "done":
results.append({
"video": video_file.name,
"result": result
})
break
except Exception as e:
print(f"Error processing {video_file}: {e}")
return resultsTroubleshooting
Common Issues
- "Invalid response format": Usually indicates server-side processing errors
- Empty features array: May indicate insufficient pose data or invalid parameters
- Connection errors: Ensure the server is running and accessible
- Timeout errors: Try with shorter videos or check server resources
Debug Information
The server provides detailed debug information including:
- Pose detection confidence scores
- Frame count and video duration
- Ball hit detection results
- Processing warnings and errors
Support
For technical support or questions about the API, refer to the server logs and debug information provided in the response.