A video-based kinematic analysis tool for athletic performance. Analyzes vertical jump videos to estimate key performance metrics using MediaPipe pose tracking and advanced kinematics.
Supported jump types:
Current Status: Pre-validation (not validated against force plates or motion capture systems)
✅ Training monitoring - Track relative changes within the same athlete over time ✅ Educational purposes - Learn about jump biomechanics and video analysis ✅ Exploratory analysis - Initial investigation before formal testing ✅ Proof-of-concept research - Demonstrate feasibility of video-based methods
❌ Research publications - As a validated measurement instrument ❌ Clinical decision-making - Injury assessment, return-to-play decisions ❌ Talent identification - Absolute performance comparisons between athletes ❌ Legal/insurance assessments - Any context requiring validated measurements ❌ High-stakes testing - Draft combines, professional athlete evaluation
If you need validated measurements for research or clinical use, consider:
For detailed validation status and roadmap, see docs/validation-status.md.
All Platforms:
Platform-Specific:
Required system dependencies:
Recommended for mobile video support:
Required system dependencies:
Xcode Command Line Tools - Provides compilers and system frameworks
xcode-select --install
Recommended for mobile video support:
brew install ffmpeg
Recommended system libraries:
sudo apt-get update
sudo apt-get install -y \
libgl1 \ # OpenGL library for OpenCV
libglib2.0-0 \ # GLib library for MediaPipe
libgomp1 \ # OpenMP library for multi-threading
ffmpeg # Video codec support and metadata extraction
Note: ffmpeg provides the ffprobe tool for video metadata extraction (rotation, aspect ratio). Kinemotion works without it, but mobile/rotated videos may not process correctly. A warning will be shown if ffprobe is not available.
pip install kinemotion
Step 1: Install asdf plugins (if not already installed):
asdf plugin add python
asdf plugin add uv
Step 2: Install versions specified in .tool-versions:
asdf install
Step 3: Install project dependencies using uv:
uv sync
This will install all dependencies and make the kinemotion command available.
Kinemotion supports two jump types with intelligent auto-tuning that automatically optimizes parameters based on video characteristics.
Analyzes reactive strength and ground contact time:
# Automatic parameter tuning based on video characteristics
kinemotion dropjump-analyze video.mp4
Analyzes jump height and biomechanics:
# No drop height needed (floor level)
kinemotion cmj-analyze video.mp4
# With triple extension visualization
kinemotion cmj-analyze video.mp4 --output debug.mp4
Analyzes pure concentric power production:
# Mass is required for power/force calculations
kinemotion sj-analyze video.mp4 --mass 75.0
# Complete analysis with all outputs
kinemotion sj-analyze video.mp4 --mass 75.0 \
--output debug.mp4 \
--json-output results.json \
--verbose
# Save metrics to JSON
kinemotion cmj-analyze video.mp4 --json-output results.json
# Generate debug video
kinemotion cmj-analyze video.mp4 --output debug.mp4
# Complete analysis with all outputs
kinemotion cmj-analyze video.mp4 \
--output debug.mp4 \
--json-output results.json \
--verbose
# Fast (50% faster, good for batch)
kinemotion cmj-analyze video.mp4 --quality fast
# Balanced (default)
kinemotion cmj-analyze video.mp4 --quality balanced
# Accurate (research-grade)
kinemotion cmj-analyze video.mp4 --quality accurate --verbose
Process multiple videos in parallel:
# Drop jumps
kinemotion dropjump-analyze videos/*.mp4 --batch --workers 4
# CMJ with output directories
kinemotion cmj-analyze videos/*.mp4 --batch --workers 4 \
--json-output-dir results/ \
--csv-summary summary.csv
All analysis outputs include automatic quality assessment in the metadata section to help you know when to trust results:
{
"data": {
"jump_height_m": 0.352,
"flight_time_ms": 534.2
},
"metadata": {
"quality": {
"confidence": "high",
"quality_score": 87.3,
"quality_indicators": {
"avg_visibility": 0.89,
"min_visibility": 0.82,
"tracking_stable": true,
"phase_detection_clear": true,
"outliers_detected": 2,
"outlier_percentage": 1.5,
"position_variance": 0.0008,
"fps": 60.0
},
"warnings": []
}
}
}
Confidence Levels:
Common Warnings:
Filtering by Quality:
# Only use high-confidence results
metrics = process_cmj_video("video.mp4")
if metrics.quality_assessment is not None and metrics.quality_assessment.confidence == "high":
print(f"Reliable jump height: {metrics.jump_height:.3f}m")
elif metrics.quality_assessment is not None:
print(f"Low quality - warnings: {metrics.quality_assessment.warnings}")
Use kinemotion as a library for automated pipelines and custom analysis.
from kinemotion import process_dropjump_video
# Process a single video
metrics = process_dropjump_video(
video_path="athlete_jump.mp4",
quality="balanced",
verbose=True
)
# Access results
print(f"Jump height: {metrics.jump_height:.3f} m")
print(f"Ground contact time: {metrics.ground_contact_time * 1000:.1f} ms")
print(f"Flight time: {metrics.flight_time * 1000:.1f} ms")
# Drop jump bulk processing
from kinemotion import DropJumpVideoConfig, process_dropjump_videos_bulk
configs = [
DropJumpVideoConfig("video1.mp4", quality="balanced"),
DropJumpVideoConfig("video2.mp4", quality="accurate"),
]
results = process_dropjump_videos_bulk(configs, max_workers=4)
# CMJ bulk processing
from kinemotion import CMJVideoConfig, process_cmj_videos_bulk
cmj_configs = [
CMJVideoConfig("cmj1.mp4"),
CMJVideoConfig("cmj2.mp4", quality="accurate"),
]
cmj_results = process_cmj_videos_bulk(cmj_configs, max_workers=4)
for result in cmj_results:
if result.success:
print(f"{result.video_path}: {result.metrics.jump_height*100:.1f}cm")
See examples/bulk/README.md for comprehensive API documentation.
# Triple extension angles available in metrics
metrics = process_cmj_video("video.mp4", output_video="debug.mp4")
# Debug video shows:
# - Skeleton overlay (foot→shin→femur→trunk)
# - Joint angles (ankle, knee, hip, trunk)
# - Phase-coded visualization
from kinemotion import process_sj_video
# Mass is required for power/force calculations
metrics = process_sj_video(
video_path="athlete_sj.mp4",
mass_kg=75.0, # Required: athlete body mass
quality="balanced",
verbose=True
)
# Access results
print(f"Jump height: {metrics.jump_height:.3f}m")
print(f"Squat hold: {metrics.squat_hold_duration*1000:.1f}ms")
print(f"Concentric: {metrics.concentric_duration*1000:.1f}ms")
# Power/force (only available if mass provided)
if metrics.peak_power:
print(f"Peak power: {metrics.peak_power:.0f}W")
print(f"Mean power: {metrics.mean_power:.0f}W")
print(f"Peak force: {metrics.peak_force:.0f}N")
# See examples/bulk/ for complete CSV export examples
from kinemotion import process_cmj_video
import csv
# ... process videos ...
with open("results.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["Video", "GCT (ms)", "Flight (ms)", "Jump (m)"])
for r in results:
if r.success and r.metrics:
writer.writerow([
Path(r.video_path).name,
f"{r.metrics.ground_contact_time * 1000:.1f}" if r.metrics.ground_contact_time else "N/A",
f"{r.metrics.flight_time * 1000:.1f}" if r.metrics.flight_time else "N/A",
f"{r.metrics.jump_height:.3f}" if r.metrics.jump_height else "N/A",
])
See examples/bulk/README.md for comprehensive API documentation and more examples.
Kinemotion automatically optimizes parameters based on your video:
All parameters are optional. Kinemotion uses intelligent auto-tuning to select optimal settings based on video characteristics.
--quality [fast|balanced|accurate] (default: balanced)
--verbose / -v
--output <path> / -o
--json-output <path> / -j
For advanced users who need manual control:
--drop-start-frame <int>: Manually specify where drop begins (if auto-detection fails)--smoothing-window <int>: Override auto-tuned smoothing window--velocity-threshold <float>: Override auto-tuned velocity threshold--min-contact-frames <int>: Override auto-tuned minimum contact frames--visibility-threshold <float>: Override visibility threshold--detection-confidence <float>: Override MediaPipe detection confidence--tracking-confidence <float>: Override MediaPipe tracking confidence📖 For detailed parameter explanations, see docs/reference/parameters.md
Note: Most users never need expert parameters - auto-tuning handles optimization automatically!
{
"data": {
"ground_contact_time_ms": 245.67,
"flight_time_ms": 456.78,
"jump_height_m": 0.339,
"jump_height_kinematic_m": 0.339,
"jump_height_trajectory_normalized": 0.0845,
"contact_start_frame": 45,
"contact_end_frame": 67,
"flight_start_frame": 68,
"flight_end_frame": 95,
"peak_height_frame": 82,
"contact_start_frame_precise": 45.234,
"contact_end_frame_precise": 67.891,
"flight_start_frame_precise": 68.123,
"flight_end_frame_precise": 94.567
},
"metadata": {
"quality": { },
"processing_info": { }
}
}
Data Fields:
ground_contact_time_ms: Duration of ground contact phase in millisecondsflight_time_ms: Duration of flight phase in millisecondsjump_height_m: Jump height calculated from flight time: h = g × t² / 8jump_height_kinematic_m: Kinematic estimate (same as jump_height_m)jump_height_trajectory_normalized: Position-based measurement in normalized coordinates (0-1 range)contact_start_frame: Frame index where contact begins (integer, for visualization)contact_end_frame: Frame index where contact ends (integer, for visualization)flight_start_frame: Frame index where flight begins (integer, for visualization)flight_end_frame: Frame index where flight ends (integer, for visualization)peak_height_frame: Frame index at maximum jump height (integer, for visualization)contact_start_frame_precise: Sub-frame precise timing for contact start (fractional, for calculations)contact_end_frame_precise: Sub-frame precise timing for contact end (fractional, for calculations)flight_start_frame_precise: Sub-frame precise timing for flight start (fractional, for calculations)flight_end_frame_precise: Sub-frame precise timing for flight end (fractional, for calculations)Note: Integer frame indices are provided for visualization in debug videos. Precise fractional frames are used for all timing calculations and provide sub-frame accuracy (±10ms at 30fps).
{
"data": {
"jump_height_m": 0.352,
"flight_time_ms": 534.2,
"countermovement_depth_m": 0.285,
"eccentric_duration_ms": 612.5,
"concentric_duration_ms": 321.8,
"total_movement_time_ms": 934.3,
"peak_eccentric_velocity_m_s": -2.145,
"peak_concentric_velocity_m_s": 3.789,
"transition_time_ms": 125.4,
"standing_start_frame": 12.5,
"lowest_point_frame": 45.2,
"takeoff_frame": 67.8,
"landing_frame": 102.3,
"tracking_method": "foot"
},
"metadata": {
"quality": { },
"processing_info": { }
}
}
Data Fields:
jump_height_m: Jump height calculated from flight time: h = g × t² / 8flight_time_ms: Duration of flight phase in millisecondscountermovement_depth_m: Maximum downward displacement during eccentric (descent) phaseeccentric_duration_ms: Time from start of countermovement to lowest pointconcentric_duration_ms: Time from lowest point to takeofftotal_movement_time_ms: Total time from countermovement start to takeoffpeak_eccentric_velocity_m_s: Maximum downward velocity during descent (negative value)peak_concentric_velocity_m_s: Maximum upward velocity during propulsion (positive value)transition_time_ms: Duration at lowest point (amortization phase between descent and propulsion)standing_start_frame: Frame where standing phase ends and countermovement beginslowest_point_frame: Frame at the lowest point of the countermovementtakeoff_frame: Frame where athlete leaves groundlanding_frame: Frame where athlete lands after jumptracking_method: Tracking method used - “foot” (foot landmarks) or “com” (center of mass estimation)The debug video includes:
Symptoms: Erratic landmark positions, missing detections, incorrect contact states
Solutions:
--smoothing-window 7 or higher--detection-confidence 0.6 or --tracking-confidence 0.6--output to visualize what’s being trackedSymptoms: “No frames processed” error or all null landmarks
Solutions:
--detection-confidence 0.3 --tracking-confidence 0.3Symptoms: Wrong ground contact times, flight phases not detected
Solutions:
--velocity-threshold 0.01--velocity-threshold 0.03--min-contact-frames 5 for longer required contact--visibility-threshold 0.3 if feet are partially obscuredSymptoms: Unrealistic jump height values
Solutions:
flight_start_frame and flight_end_frame in JSONjump_height_m (primary) and jump_height_kinematic_m (kinematic-only)Symptoms: Cannot write debug video or corrupted output
Solutions:
.avi extension instead of .mp4This project enforces strict code quality standards:
# Run the tool
uv run kinemotion dropjump-analyze <video_path>
# Run all tests
uv run pytest
# Run tests with verbose output
uv run pytest -v
# Format code
uv run black src/
# Lint code
uv run ruff check
# Auto-fix linting issues
uv run ruff check --fix
# Type check
uv run pyright
# Run all checks
uv run ruff check && uv run pyright && uv run pytest
Before committing code, ensure all checks pass:
See CONTRIBUTING.md for contribution guidelines and requirements, or CLAUDE.md for detailed development guidelines.
MIT License - feel free to use for personal experiments and research.