kinemotion 0.2.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kinemotion might be problematic. Click here for more details.

Files changed (36) hide show
  1. {kinemotion-0.2.0 → kinemotion-0.5.0}/.gitignore +2 -0
  2. kinemotion-0.5.0/.pre-commit-config.yaml +33 -0
  3. {kinemotion-0.2.0 → kinemotion-0.5.0}/CLAUDE.md +67 -46
  4. kinemotion-0.5.0/GEMINI.md +162 -0
  5. {kinemotion-0.2.0 → kinemotion-0.5.0}/PKG-INFO +36 -86
  6. {kinemotion-0.2.0 → kinemotion-0.5.0}/README.md +34 -84
  7. kinemotion-0.5.0/docs/ERRORS_FINDINGS.md +260 -0
  8. kinemotion-0.5.0/docs/FRAMERATE.md +747 -0
  9. kinemotion-0.5.0/docs/IMPLEMENTATION_PLAN.md +795 -0
  10. kinemotion-0.5.0/docs/IMU_METADATA_PRESERVATION.md +124 -0
  11. {kinemotion-0.2.0 → kinemotion-0.5.0}/docs/PARAMETERS.md +244 -332
  12. kinemotion-0.5.0/docs/VALIDATION_PLAN.md +709 -0
  13. {kinemotion-0.2.0 → kinemotion-0.5.0}/pyproject.toml +3 -2
  14. kinemotion-0.5.0/src/kinemotion/cli.py +20 -0
  15. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/dropjump/analysis.py +14 -2
  16. {kinemotion-0.2.0/src/kinemotion → kinemotion-0.5.0/src/kinemotion/dropjump}/cli.py +41 -80
  17. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/dropjump/kinematics.py +23 -7
  18. {kinemotion-0.2.0 → kinemotion-0.5.0}/.tool-versions +0 -0
  19. {kinemotion-0.2.0 → kinemotion-0.5.0}/LICENSE +0 -0
  20. {kinemotion-0.2.0 → kinemotion-0.5.0}/examples/programmatic_usage.py +0 -0
  21. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/__init__.py +0 -0
  22. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/core/__init__.py +0 -0
  23. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/core/filtering.py +0 -0
  24. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/core/pose.py +0 -0
  25. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/core/smoothing.py +0 -0
  26. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/core/video_io.py +0 -0
  27. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/dropjump/__init__.py +0 -0
  28. {kinemotion-0.2.0 → kinemotion-0.5.0}/src/kinemotion/dropjump/debug_overlay.py +0 -0
  29. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/__init__.py +0 -0
  30. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/test_adaptive_threshold.py +0 -0
  31. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/test_aspect_ratio.py +0 -0
  32. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/test_com_estimation.py +0 -0
  33. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/test_contact_detection.py +0 -0
  34. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/test_filtering.py +0 -0
  35. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/test_kinematics.py +0 -0
  36. {kinemotion-0.2.0 → kinemotion-0.5.0}/tests/test_polyorder.py +0 -0
@@ -60,3 +60,5 @@ Thumbs.db
60
60
  *.mp4
61
61
  *.jpeg
62
62
  *.jpg
63
+
64
+ .claude/settings.local.json*
@@ -0,0 +1,33 @@
1
+ # See https://pre-commit.com for more information
2
+ # See https://pre-commit.com/hooks.html for more hooks
3
+ repos:
4
+ - repo: https://github.com/pre-commit/pre-commit-hooks
5
+ rev: v6.0.0
6
+ hooks:
7
+ - id: trailing-whitespace
8
+ - id: end-of-file-fixer
9
+ - id: check-yaml
10
+ - id: check-added-large-files
11
+ args: ['--maxkb=1000']
12
+ - id: check-merge-conflict
13
+ - id: check-toml
14
+ - id: debug-statements
15
+ - id: mixed-line-ending
16
+
17
+ - repo: https://github.com/psf/black
18
+ rev: 23.12.1
19
+ hooks:
20
+ - id: black
21
+
22
+ - repo: https://github.com/astral-sh/ruff-pre-commit
23
+ rev: v0.1.9
24
+ hooks:
25
+ - id: ruff
26
+ args: [--fix, --exit-non-zero-on-fix]
27
+
28
+ - repo: https://github.com/pre-commit/mirrors-mypy
29
+ rev: v1.7.1
30
+ hooks:
31
+ - id: mypy
32
+ args: [--ignore-missing-imports, --no-strict-optional]
33
+ exclude: ^tests/
@@ -11,12 +11,14 @@ Kinemotion: Video-based kinematic analysis tool for athletic performance. Analyz
11
11
  ### Dependencies
12
12
 
13
13
  Managed with `uv` and `asdf`:
14
+
14
15
  - Python version: 3.12.7 (specified in `.tool-versions`)
15
16
  - **Important**: MediaPipe requires Python 3.12 or earlier (no 3.13 support yet)
16
17
  - Install dependencies: `uv sync`
17
18
  - Run CLI: `kinemotion dropjump-analyze <video.mp4>`
18
19
 
19
20
  **Production dependencies:**
21
+
20
22
  - click: CLI framework
21
23
  - opencv-python: Video processing
22
24
  - mediapipe: Pose detection and tracking
@@ -24,6 +26,7 @@ Managed with `uv` and `asdf`:
24
26
  - scipy: Signal processing (Savitzky-Golay filter)
25
27
 
26
28
  **Development dependencies:**
29
+
27
30
  - pytest: Testing framework
28
31
  - black: Code formatting
29
32
  - ruff: Fast Python linter
@@ -45,20 +48,22 @@ Managed with `uv` and `asdf`:
45
48
 
46
49
  ### Module Structure
47
50
 
48
- ```
51
+ ```text
49
52
  src/kinemotion/
50
53
  ├── __init__.py
51
- ├── cli.py # Click-based CLI entry point
54
+ ├── cli.py # Main CLI entry point (registers subcommands)
52
55
  ├── core/ # Shared functionality across all jump types
53
56
  │ ├── __init__.py
54
57
  │ ├── pose.py # MediaPipe Pose integration + CoM
55
58
  │ ├── smoothing.py # Savitzky-Golay landmark smoothing
56
- └── filtering.py # Outlier rejection + bilateral filtering
59
+ ├── filtering.py # Outlier rejection + bilateral filtering
60
+ │ └── video_io.py # Video processing (VideoProcessor class)
57
61
  └── dropjump/ # Drop jump specific analysis
58
62
  ├── __init__.py
63
+ ├── cli.py # Drop jump CLI command (dropjump-analyze)
59
64
  ├── analysis.py # Ground contact state detection
60
65
  ├── kinematics.py # Drop jump metrics calculations
61
- └── video_io.py # Video processing and debug overlay rendering
66
+ └── debug_overlay.py # Debug video overlay rendering
62
67
 
63
68
  tests/
64
69
  ├── test_adaptive_threshold.py # Adaptive threshold tests
@@ -70,14 +75,25 @@ tests/
70
75
  └── test_polyorder.py # Polynomial order tests
71
76
 
72
77
  docs/
73
- └── PARAMETERS.md # Comprehensive guide to all CLI parameters
78
+ ├── PARAMETERS.md # Comprehensive guide to all CLI parameters
79
+ └── IMPLEMENTATION_PLAN.md # Implementation plan and fix guide
74
80
  ```
75
81
 
76
82
  **Design Rationale:**
83
+
77
84
  - `core/` contains shared code reusable across different jump types (CMJ, squat jumps, etc.)
78
- - `dropjump/` contains drop jump specific logic and metrics
79
- - Future jump types (CMJ, squat) will be sibling modules to `dropjump/`
80
- - Single CLI with subcommands for different analysis types
85
+ - `dropjump/` contains drop jump specific logic, metrics, and CLI command
86
+ - Each jump type module contains its own CLI command definition
87
+ - Main `cli.py` is just an entry point that registers subcommands from each module
88
+ - Future jump types (CMJ, squat) will be sibling modules to `dropjump/` with their own cli.py
89
+ - Single CLI group with subcommands for different analysis types
90
+
91
+ **CLI Architecture:**
92
+
93
+ - `src/kinemotion/cli.py` (20 lines): Main CLI group + command registration
94
+ - `src/kinemotion/dropjump/cli.py` (358 lines): Complete dropjump-analyze command
95
+ - Commands registered using Click's `cli.add_command()` pattern
96
+ - Modular design allows easy addition of new jump type analysis commands
81
97
 
82
98
  ### Analysis Pipeline
83
99
 
@@ -123,7 +139,7 @@ docs/
123
139
  - **Configurable thresholds**: CLI flags allow tuning for different video qualities and athletes
124
140
  - **Calibrated jump height**: Position-based measurement with drop height calibration for accuracy
125
141
  - Optional `--drop-height` parameter uses known drop box height to calibrate measurements
126
- - Achieves ~88% accuracy (vs 71% with kinematic-only method)
142
+ - **⚠️ Accuracy claim unvalidated** - theoretical benefit estimated, not empirically tested
127
143
  - Fallback to empirically-corrected kinematic formula when no calibration provided
128
144
  - **Aspect ratio preservation**: Output video ALWAYS matches source video dimensions
129
145
  - Handles SAR (Sample Aspect Ratio) metadata from mobile videos
@@ -162,6 +178,7 @@ The codebase enforces strict code quality standards using multiple tools:
162
178
  ### When Contributing Code
163
179
 
164
180
  Always run before committing:
181
+
165
182
  ```bash
166
183
  # Format code
167
184
  uv run black src/
@@ -177,17 +194,18 @@ uv run pytest
177
194
  ```
178
195
 
179
196
  Or run all checks at once:
197
+
180
198
  ```bash
181
199
  uv run ruff check && uv run mypy src/kinemotion && uv run pytest
182
200
  ```
183
201
 
184
202
  ## Critical Implementation Details
185
203
 
186
- ### Aspect Ratio Preservation & SAR Handling (dropjump/video_io.py)
204
+ ### Aspect Ratio Preservation & SAR Handling (core/video_io.py)
187
205
 
188
206
  **IMPORTANT**: The tool preserves the exact aspect ratio of the source video, including SAR (Sample Aspect Ratio) metadata. No dimensions are hardcoded.
189
207
 
190
- #### VideoProcessor (`dropjump/video_io.py:15-110`)
208
+ #### VideoProcessor (`core/video_io.py:15-110`)
191
209
 
192
210
  - Reads the **first actual frame** to get true encoded dimensions (not OpenCV properties)
193
211
  - Critical for mobile videos with rotation metadata
@@ -206,13 +224,14 @@ if ret:
206
224
  ```
207
225
 
208
226
  **Never do this:**
227
+
209
228
  ```python
210
229
  # Wrong - may return incorrect dimensions with rotated videos
211
230
  self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
212
231
  self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
213
232
  ```
214
233
 
215
- #### DebugOverlayRenderer (`dropjump/video_io.py:130-330`)
234
+ #### DebugOverlayRenderer (`dropjump/debug_overlay.py`)
216
235
 
217
236
  - Creates output video with **display dimensions** (respecting SAR)
218
237
  - Resizes frames from encoded dimensions to display dimensions if needed (INTER_LANCZOS4)
@@ -230,12 +249,14 @@ self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
230
249
  Instead of simple frame-to-frame differences, velocity is computed as the derivative of the smoothed position trajectory using Savitzky-Golay filter:
231
250
 
232
251
  **Advantages:**
252
+
233
253
  - **Smoother velocity curves**: Eliminates noise from frame-to-frame jitter
234
254
  - **More accurate threshold crossings**: Clean transitions without false positives
235
255
  - **Better interpolation**: Smoother velocity gradient for sub-frame precision
236
256
  - **Consistent with smoothing**: Uses same polynomial fit as position smoothing
237
257
 
238
258
  **Implementation:**
259
+
239
260
  ```python
240
261
  # OLD: Simple differences (noisy)
241
262
  velocities = np.abs(np.diff(foot_positions, prepend=foot_positions[0]))
@@ -245,6 +266,7 @@ velocities = savgol_filter(positions, window_length=5, polyorder=2, deriv=1, del
245
266
  ```
246
267
 
247
268
  **Key Function:**
269
+
248
270
  - `compute_velocity_from_derivative()`: Computes first derivative using Savitzky-Golay filter
249
271
 
250
272
  #### Sub-Frame Interpolation Algorithm
@@ -252,9 +274,11 @@ velocities = savgol_filter(positions, window_length=5, polyorder=2, deriv=1, del
252
274
  At 30fps, each frame represents 33.3ms. Contact events (landing, takeoff) rarely occur exactly at frame boundaries. Sub-frame interpolation estimates the exact moment between frames when velocity crosses the threshold.
253
275
 
254
276
  **Algorithm:**
277
+
255
278
  1. Calculate smooth velocity using derivative: `v = derivative(smooth_position)`
256
279
  2. Find frames where velocity crosses threshold (e.g., from 0.025 to 0.015, threshold 0.020)
257
280
  3. Use linear interpolation to find exact crossing point:
281
+
258
282
  ```python
259
283
  # If v[10] = 0.025 and v[11] = 0.015, threshold = 0.020
260
284
  t = (0.020 - 0.025) / (0.015 - 0.025) = 0.5
@@ -262,11 +286,13 @@ At 30fps, each frame represents 33.3ms. Contact events (landing, takeoff) rarely
262
286
  ```
263
287
 
264
288
  **Key Functions:**
289
+
265
290
  - `interpolate_threshold_crossing()`: Linear interpolation of velocity crossing
266
291
  - `find_interpolated_phase_transitions()`: Returns fractional frame indices for all phases
267
292
 
268
293
  **Accuracy Improvement:**
269
- ```
294
+
295
+ ```text
270
296
  30fps without interpolation: ±33ms (1 frame on each boundary)
271
297
  30fps with interpolation: ±10ms (sub-frame precision)
272
298
  60fps without interpolation: ±17ms
@@ -274,6 +300,7 @@ At 30fps, each frame represents 33.3ms. Contact events (landing, takeoff) rarely
274
300
  ```
275
301
 
276
302
  **Velocity Comparison:**
303
+
277
304
  ```python
278
305
  # Frame-to-frame differences: noisy, discontinuous jumps
279
306
  v_simple = [0.01, 0.03, 0.02, 0.04, 0.02, 0.01] # Jittery
@@ -283,6 +310,7 @@ v_deriv = [0.015, 0.022, 0.025, 0.024, 0.018, 0.012] # Smooth
283
310
  ```
284
311
 
285
312
  **Example:**
313
+
286
314
  ```python
287
315
  # Integer frames: contact from frame 49 to 53 (5 frames = 168ms at 30fps)
288
316
  # With derivative velocity: contact from 49.0 to 53.0 (4 frames = 135ms)
@@ -298,12 +326,14 @@ v_deriv = [0.015, 0.022, 0.025, 0.024, 0.018, 0.012] # Smooth
298
326
  Acceleration (second derivative) reveals characteristic patterns at contact events:
299
327
 
300
328
  **Physical Patterns:**
329
+
301
330
  - **Landing impact**: Large acceleration spike as feet decelerate on impact
302
331
  - **Takeoff**: Acceleration change as body transitions from static to upward motion
303
332
  - **In flight**: Constant acceleration (gravity ≈ -9.81 m/s²)
304
333
  - **On ground**: Near-zero acceleration (stationary position)
305
334
 
306
335
  **Implementation:**
336
+
307
337
  ```python
308
338
  # Compute acceleration using Savitzky-Golay second derivative
309
339
  acceleration = savgol_filter(positions, window=5, polyorder=2, deriv=2, delta=1.0)
@@ -317,6 +347,7 @@ takeoff_frame = np.argmax(accel_change[search_window])
317
347
  ```
318
348
 
319
349
  **Key Functions:**
350
+
320
351
  - `compute_acceleration_from_derivative()`: Computes second derivative using Savitzky-Golay
321
352
  - `refine_transition_with_curvature()`: Searches for acceleration patterns near transitions
322
353
  - `find_interpolated_phase_transitions_with_curvature()`: Combines velocity + curvature
@@ -330,11 +361,13 @@ Curvature analysis refines velocity-based estimates through blending:
330
361
  3. **Blending**: 70% curvature-based + 30% velocity-based
331
362
 
332
363
  **Why Blending?**
364
+
333
365
  - Velocity is reliable for coarse timing
334
366
  - Curvature provides fine detail but can be noisy at boundaries
335
367
  - Blending prevents large deviations while incorporating physical insights
336
368
 
337
369
  **Algorithm:**
370
+
338
371
  ```python
339
372
  # 1. Get velocity-based estimate
340
373
  velocity_estimate = 49.0 # from interpolation
@@ -349,6 +382,7 @@ blend = 0.7 * 47.2 + 0.3 * 49.0 # = 47.74
349
382
  ```
350
383
 
351
384
  **Accuracy Improvement:**
385
+
352
386
  ```python
353
387
  # Example: Landing detection
354
388
  # Velocity only: frame 49.0 (when velocity drops below threshold)
@@ -357,6 +391,7 @@ blend = 0.7 * 47.2 + 0.3 * 49.0 # = 47.74
357
391
  ```
358
392
 
359
393
  **Optional Feature:**
394
+
360
395
  - Enabled by default (`--use-curvature`, default: True)
361
396
  - Can be disabled with `--no-curvature` flag for pure velocity-based detection
362
397
  - Negligible performance impact (reuses smoothed trajectory)
@@ -374,12 +409,13 @@ Always convert to Python `int()` in `to_dict()` method:
374
409
  ```
375
410
 
376
411
  **Never do this:**
412
+
377
413
  ```python
378
414
  # Wrong - will fail with "Object of type int64 is not JSON serializable"
379
415
  "contact_start_frame": self.contact_start_frame
380
416
  ```
381
417
 
382
- ### Video Codec Handling (dropjump/video_io.py:78-94)
418
+ ### Video Codec Handling (dropjump/debug_overlay.py)
383
419
 
384
420
  - Primary codec: H.264 (avc1) - better quality, smaller file size
385
421
  - Fallback codec: MPEG-4 (mp4v) - broader compatibility
@@ -393,6 +429,7 @@ OpenCV and NumPy use different dimension ordering:
393
429
  - **OpenCV VideoWriter size**: `(width, height)` tuple
394
430
 
395
431
  Example:
432
+
396
433
  ```python
397
434
  frame.shape # (1080, 1920, 3) - height first
398
435
  cv2.VideoWriter(..., (1920, 1080)) # width first
@@ -407,12 +444,13 @@ Always be careful with dimension ordering to avoid squashed/stretched videos.
407
444
  1. Update `DropJumpMetrics` class in `dropjump/kinematics.py:10-19`
408
445
  2. Add calculation logic in `calculate_drop_jump_metrics()` function
409
446
  3. Update `to_dict()` method for JSON serialization (remember to convert NumPy types to Python types)
410
- 4. Optionally add visualization in `DebugOverlayRenderer.render_frame()` in `dropjump/video_io.py:96`
447
+ 4. Optionally add visualization in `DebugOverlayRenderer.render_frame()` in `dropjump/debug_overlay.py`
411
448
  5. Add tests in `tests/test_kinematics.py`
412
449
 
413
450
  ### Modifying Contact Detection Logic
414
451
 
415
452
  Edit `detect_ground_contact()` in `dropjump/analysis.py:14`. Key parameters:
453
+
416
454
  - `velocity_threshold`: Tune for different surface/athlete combinations (default: 0.02)
417
455
  - `min_contact_frames`: Adjust for frame rate and contact duration expectations (default: 3)
418
456
  - `visibility_threshold`: Minimum landmark visibility score (default: 0.5)
@@ -420,6 +458,7 @@ Edit `detect_ground_contact()` in `dropjump/analysis.py:14`. Key parameters:
420
458
  ### Adjusting Smoothing
421
459
 
422
460
  Modify `smooth_landmarks()` in `core/smoothing.py:9`:
461
+
423
462
  - `window_length`: Controls smoothing strength (must be odd, default: 5)
424
463
  - `polyorder`: Polynomial order for Savitzky-Golay filter (default: 2)
425
464
 
@@ -427,11 +466,10 @@ Modify `smooth_landmarks()` in `core/smoothing.py:9`:
427
466
 
428
467
  **IMPORTANT**: See `docs/PARAMETERS.md` for comprehensive guide on all CLI parameters.
429
468
 
430
- Quick reference:
431
- - **use-com**: Use center of mass tracking instead of feet (↑ accuracy by 3-5%)
432
- - **adaptive-threshold**: Auto-calibrate velocity threshold from baseline (↑ accuracy by 2-3%)
469
+ Quick reference for `dropjump-analyze`:
470
+
433
471
  - **smoothing-window**: Trajectory smoothness (↑ for noisy video)
434
- - **velocity-threshold**: Contact sensitivity (↓ to detect brief contacts) - ignored if adaptive-threshold enabled
472
+ - **velocity-threshold**: Contact sensitivity (↓ to detect brief contacts)
435
473
  - **min-contact-frames**: Temporal filter (↑ to remove false contacts)
436
474
  - **visibility-threshold**: Landmark confidence (↓ for occluded landmarks)
437
475
  - **detection-confidence**: Pose detection strictness (MediaPipe)
@@ -439,7 +477,10 @@ Quick reference:
439
477
  - **drop-height**: Drop box height in meters for calibration (e.g., 0.40 for 40cm)
440
478
  - **use-curvature**: Enable trajectory curvature analysis (default: enabled)
441
479
 
480
+ **Note**: Drop jump analysis always uses foot-based tracking with fixed velocity thresholds because typical drop jump videos are ~3 seconds long without a stationary baseline period. The `--use-com` and `--adaptive-threshold` options (available in `core/` modules) require longer videos (~5+ seconds) with 3 seconds of standing baseline, making them suitable for future jump types like CMJ (countermovement jump) but not drop jumps.
481
+
442
482
  The detailed guide includes:
483
+
443
484
  - How each parameter works internally
444
485
  - Frame rate considerations
445
486
  - Scenario-based recommended settings
@@ -449,6 +490,7 @@ The detailed guide includes:
449
490
  ### Working with Different Video Formats
450
491
 
451
492
  The tool handles various video formats and aspect ratios:
493
+
452
494
  - 16:9 landscape (1920x1080)
453
495
  - 4:3 standard (640x480)
454
496
  - 9:16 portrait (1080x1920)
@@ -484,6 +526,7 @@ uv run pytest -v
484
526
  ### Code Quality
485
527
 
486
528
  All code passes:
529
+
487
530
  - ✅ **Type checking**: Full mypy strict mode compliance
488
531
  - ✅ **Linting**: ruff checks with comprehensive rule sets
489
532
  - ✅ **Tests**: 25/25 tests passing
@@ -499,6 +542,7 @@ All code passes:
499
542
  ### Video Dimension Issues
500
543
 
501
544
  If output video has wrong aspect ratio:
545
+
502
546
  1. Check `VideoProcessor` is reading first frame correctly
503
547
  2. Verify `DebugOverlayRenderer` receives correct width/height from `VideoProcessor`
504
548
  3. Check that `write_frame()` validation is enabled (should raise error if dimensions mismatch)
@@ -507,6 +551,7 @@ If output video has wrong aspect ratio:
507
551
  ### JSON Serialization Errors
508
552
 
509
553
  If you see "Object of type X is not JSON serializable":
554
+
510
555
  1. Check `kinematics.py` `to_dict()` method
511
556
  2. Ensure all NumPy types are converted to Python types with `int()` or `float()`
512
557
  3. Run `tests/test_kinematics.py::test_metrics_to_dict` to verify
@@ -514,6 +559,7 @@ If you see "Object of type X is not JSON serializable":
514
559
  ### Video Codec Issues
515
560
 
516
561
  If output video won't play:
562
+
517
563
  1. Try different output format: `.avi` instead of `.mp4`
518
564
  2. Check OpenCV codec support: `cv2.getBuildInformation()`
519
565
  3. DebugOverlayRenderer will fallback from H.264 to MPEG-4 automatically
@@ -521,6 +567,7 @@ If output video won't play:
521
567
  ### Type Checking Issues
522
568
 
523
569
  If mypy reports errors:
570
+
524
571
  1. Ensure all function signatures have complete type annotations (parameters and return types)
525
572
  2. For numpy types, use explicit casts: `int()`, `float()` when converting to Python types
526
573
  3. For third-party libraries without stubs (cv2, mediapipe, scipy), use `# type: ignore` comments sparingly
@@ -565,38 +612,12 @@ uv run kinemotion dropjump-analyze video.mp4 \
565
612
  uv run kinemotion dropjump-analyze jump.mp4 \
566
613
  --output debug.mp4 \
567
614
  --json-output metrics.json
568
-
569
- # Use center of mass tracking for improved accuracy (3-5% gain)
570
- uv run kinemotion dropjump-analyze video.mp4 \
571
- --use-com \
572
- --output debug.mp4 \
573
- --json-output metrics.json
574
-
575
- # Full analysis with CoM tracking and calibration
576
- uv run kinemotion dropjump-analyze video.mp4 \
577
- --use-com \
578
- --drop-height 0.40 \
579
- --output debug_com.mp4 \
580
- --json-output metrics.json
581
-
582
- # Adaptive threshold for auto-calibration (2-3% accuracy gain)
583
- uv run kinemotion dropjump-analyze video.mp4 \
584
- --adaptive-threshold \
585
- --output debug.mp4 \
586
- --json-output metrics.json
587
-
588
- # Maximum accuracy: CoM + adaptive threshold + calibration (~93-96%)
589
- uv run kinemotion dropjump-analyze video.mp4 \
590
- --adaptive-threshold \
591
- --use-com \
592
- --drop-height 0.40 \
593
- --output debug_max.mp4 \
594
- --json-output metrics.json
595
615
  ```
596
616
 
597
617
  ## MCP Server Configuration
598
618
 
599
619
  The repository includes MCP server configuration in `.mcp.json`:
620
+
600
621
  - **web-search**: DuckDuckGo search via @dannyboy2042/freebird-mcp
601
622
  - **sequential**: Sequential thinking via @smithery-ai/server-sequential-thinking
602
623
  - **context7**: Library documentation via @upstash/context7-mcp
@@ -0,0 +1,162 @@
1
+ # GEMINI.md
2
+
3
+ This file provides guidance to the Gemini model when working with code in this repository.
4
+
5
+ ## Repository Purpose
6
+
7
+ Kinemotion is a video-based kinematic analysis tool for athletic performance. It analyzes drop-jump videos to estimate ground contact time, flight time, and jump height. The analysis is done by tracking an athlete's movement using MediaPipe pose tracking and applying advanced kinematic calculations. It supports both traditional foot-based tracking and a more accurate center of mass (CoM) tracking.
8
+
9
+ **IMPORTANT**: The tool's accuracy has not been validated against gold-standard measurements. Any accuracy claims are theoretical.
10
+
11
+ ## Project Setup
12
+
13
+ ### Dependencies
14
+
15
+ The project uses `uv` for dependency management and `asdf` for Python version management.
16
+
17
+ - **Python Version**: 3.12.7 (specified in `.tool-versions`). MediaPipe requires Python <= 3.12.
18
+ - **Install Dependencies**: `uv sync`
19
+
20
+ **Key Libraries:**
21
+
22
+ - **Production**: `click`, `opencv-python`, `mediapipe`, `numpy`, `scipy`.
23
+ - **Development**: `pytest`, `black`, `ruff`, `mypy`.
24
+
25
+ ### Development Commands
26
+
27
+ - **Run CLI**: `uv run kinemotion dropjump-analyze <video_path>`
28
+ - **Install/Sync Dependencies**: `uv sync`
29
+ - **Run Tests**: `uv run pytest`
30
+ - **Format Code**: `uv run black src/`
31
+ - **Lint Code**: `uv run ruff check`
32
+ - **Auto-fix Linting**: `uv run ruff check --fix`
33
+ - **Type Check**: `uv run mypy src/kinemotion`
34
+ - **Run All Checks**: `uv run ruff check && uv run mypy src/kinemotion && uv run pytest`
35
+
36
+ ## Architecture
37
+
38
+ ### Module Structure
39
+
40
+ ```text
41
+ src/kinemotion/
42
+ ├── cli.py # Main CLI entry point
43
+ ├── core/ # Shared functionality (pose, smoothing, filtering, video_io)
44
+ └── dropjump/ # Drop jump specific analysis (cli, analysis, kinematics, debug_overlay)
45
+ tests/ # Unit and integration tests
46
+ docs/ # Documentation (PARAMETERS.md is key)
47
+ ```
48
+
49
+ - `core/` contains reusable code for different jump types.
50
+ - `dropjump/` contains logic specific to drop jumps.
51
+ - The main `cli.py` registers subcommands from modules like `dropjump/cli.py`.
52
+
53
+ ### Analysis Pipeline
54
+
55
+ 1. **Pose Tracking** (`core/pose.py`): Extracts 13 body landmarks per frame using MediaPipe.
56
+ 2. **Center of Mass (CoM) Estimation** (`core/pose.py`): Optional, more accurate tracking using a biomechanical model.
57
+ 3. **Smoothing** (`core/smoothing.py`): A Savitzky-Golay filter reduces jitter.
58
+ 4. **Contact Detection** (`dropjump/analysis.py`): Analyzes vertical velocity to determine ground contact vs. flight.
59
+ 5. **Phase Identification**: Finds continuous ground contact and flight periods.
60
+ 6. **Sub-Frame Interpolation** (`dropjump/analysis.py`): Estimates exact transition times between frames using linear interpolation on the velocity curve, improving timing precision significantly.
61
+ 7. **Trajectory Curvature Analysis** (`dropjump/analysis.py`): Refines transition timing by detecting acceleration spikes (e.g., landing impact).
62
+ 8. **Metrics Calculation** (`dropjump/kinematics.py`): Calculates ground contact time, flight time, and jump height.
63
+ 9. **Output**: Provides metrics in JSON format and an optional debug video.
64
+
65
+ ## Critical Implementation Details
66
+
67
+ ### 1. Aspect Ratio Preservation & SAR Handling (`core/video_io.py`)
68
+
69
+ - **CRITICAL**: The tool must preserve the source video's exact aspect ratio, including Sample Aspect Ratio (SAR) from mobile videos.
70
+ - **DO**: Get frame dimensions from the first actual frame read from the video (`frame.shape[:2]`), not from `cv2.CAP_PROP_*` properties, which can be wrong for rotated videos.
71
+ - **DO**: Use `ffprobe` to extract SAR and calculate correct display dimensions.
72
+ - The `DebugOverlayRenderer` uses these display dimensions for the output video.
73
+
74
+ ### 2. Sub-Frame Interpolation (`dropjump/analysis.py`)
75
+
76
+ - **CRITICAL**: Timing precision is achieved by interpolating between frames.
77
+ - **Velocity Calculation**: Velocity is computed as the **first derivative of the smoothed position trajectory** using a Savitzky-Golay filter (`savgol_filter(..., deriv=1)`). This is much smoother and more accurate than simple frame-to-frame differences.
78
+ - **Interpolation**: When velocity crosses the contact threshold between two frames, linear interpolation is used to find the fractional frame index of the crossing. This improves timing accuracy from ~33ms to ~10ms at 30fps.
79
+
80
+ ### 3. Trajectory Curvature Analysis (`dropjump/analysis.py`)
81
+
82
+ - **CRITICAL**: Event timing is further refined using acceleration patterns.
83
+ - **Acceleration Calculation**: Acceleration is the **second derivative of the smoothed position** (`savgol_filter(..., deriv=2)`).
84
+ - **Event Detection**:
85
+ - **Landing**: A large acceleration spike (impact deceleration).
86
+ - **Takeoff**: A sharp change in acceleration.
87
+ - **Blending**: The final transition time is a weighted blend: 70% from the curvature-based estimate and 30% from the velocity-based estimate. This is enabled by default via `--use-curvature`.
88
+
89
+ ### 4. JSON Serialization of NumPy Types (`dropjump/kinematics.py`)
90
+
91
+ - **CRITICAL**: Standard `json.dump` cannot serialize NumPy integer types (e.g., `np.int64`).
92
+ - **DO**: Explicitly cast all NumPy numbers to standard Python types (`int()`, `float()`) within the `to_dict()` methods of data classes before serialization.
93
+
94
+ ### 5. OpenCV Frame Dimensions
95
+
96
+ - **CRITICAL**: Be aware of dimension ordering differences.
97
+ - **NumPy `frame.shape`**: `(height, width, channels)`
98
+ - **OpenCV `cv2.VideoWriter()` size**: `(width, height)`
99
+ - Always pass dimensions to OpenCV functions in `(width, height)` order.
100
+
101
+ ## Code Quality & Workflow
102
+
103
+ When contributing code, strictly adhere to the project's quality standards.
104
+
105
+ 1. **Format Code**: `uv run black src/`
106
+ 2. **Lint and Fix**: `uv run ruff check --fix`
107
+ 3. **Type Check**: `uv run mypy src/kinemotion`
108
+ 4. **Run Tests**: `uv run pytest`
109
+
110
+ **Run all checks before committing**: `uv run ruff check && uv run mypy src/kinemotion && uv run pytest`
111
+
112
+ - **Type Safety**: The project uses `mypy` in strict mode. All functions must have full type annotations.
113
+ - **Linting**: `ruff` is used for linting. Configuration is in `pyproject.toml`.
114
+ - **Formatting**: `black` is used for code formatting.
115
+
116
+ ## Common Development Tasks
117
+
118
+ - **Adding New Metrics**:
119
+ 1. Update `DropJumpMetrics` in `dropjump/kinematics.py`.
120
+ 2. Add calculation logic in `calculate_drop_jump_metrics()`.
121
+ 3. Update `to_dict()` method (remember to cast NumPy types).
122
+ 4. (Optional) Add visualization in `DebugOverlayRenderer`.
123
+ 5. Add tests in `tests/test_kinematics.py`.
124
+ - **Modifying Contact Detection**: Edit `detect_ground_contact()` in `dropjump/analysis.py`.
125
+ - **Adjusting Smoothing**: Modify `smooth_landmarks()` in `core/smoothing.py`.
126
+
127
+ ## Parameter Tuning
128
+
129
+ A comprehensive guide to all CLI parameters is in `docs/PARAMETERS.md`. Refer to it for detailed explanations.
130
+
131
+ **Key `dropjump-analyze` parameters:**
132
+
133
+ - `--smoothing-window`: Controls trajectory smoothness. Increase for noisy video.
134
+ - `--polyorder`: Polynomial order for smoothing. `2` is ideal for jump physics.
135
+ - `--velocity-threshold`: Contact sensitivity. Decrease to detect shorter contacts.
136
+ - `--min-contact-frames`: Temporal filter. Increase to remove false contacts.
137
+ - `--drop-height`: **Important for accuracy.** Calibrates jump height using a known box height in meters.
138
+ - `--use-curvature`: Enables acceleration-based timing refinement (default: True).
139
+ - `--outlier-rejection`: Removes tracking glitches before smoothing (default: True).
140
+ - `--bilateral-filter`: Experimental edge-preserving smoothing alternative to Savitzky-Golay.
141
+
142
+ ## Testing
143
+
144
+ - **Run all tests**: `uv run pytest`
145
+ - **Run a specific test file**: `uv run pytest tests/test_contact_detection.py -v`
146
+ - The project has comprehensive test coverage for core functionalities like aspect ratio, contact detection, CoM estimation, and kinematics.
147
+
148
+ ## CLI Usage Examples
149
+
150
+ ```bash
151
+ # Get help for the dropjump command
152
+ uv run kinemotion dropjump-analyze --help
153
+
154
+ # Basic analysis, print JSON to stdout
155
+ uv run kinemotion dropjump-analyze video.mp4
156
+
157
+ # Full analysis: generate debug video, save metrics, and use calibration
158
+ uv run kinemotion dropjump-analyze video.mp4 \
159
+ --output debug_video.mp4 \
160
+ --json-output metrics.json \
161
+ --drop-height 0.40
162
+ ```