kinemotion 0.10.1__tar.gz → 0.10.2__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 (55) hide show
  1. {kinemotion-0.10.1 → kinemotion-0.10.2}/CHANGELOG.md +8 -0
  2. {kinemotion-0.10.1 → kinemotion-0.10.2}/PKG-INFO +1 -1
  3. {kinemotion-0.10.1 → kinemotion-0.10.2}/pyproject.toml +1 -1
  4. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_adaptive_threshold.py +17 -16
  5. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_aspect_ratio.py +2 -1
  6. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_filtering.py +10 -5
  7. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_polyorder.py +8 -4
  8. {kinemotion-0.10.1 → kinemotion-0.10.2}/uv.lock +1 -1
  9. {kinemotion-0.10.1 → kinemotion-0.10.2}/.dockerignore +0 -0
  10. {kinemotion-0.10.1 → kinemotion-0.10.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  11. {kinemotion-0.10.1 → kinemotion-0.10.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  12. {kinemotion-0.10.1 → kinemotion-0.10.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  13. {kinemotion-0.10.1 → kinemotion-0.10.2}/.github/pull_request_template.md +0 -0
  14. {kinemotion-0.10.1 → kinemotion-0.10.2}/.github/workflows/release.yml +0 -0
  15. {kinemotion-0.10.1 → kinemotion-0.10.2}/.gitignore +0 -0
  16. {kinemotion-0.10.1 → kinemotion-0.10.2}/.pre-commit-config.yaml +0 -0
  17. {kinemotion-0.10.1 → kinemotion-0.10.2}/.tool-versions +0 -0
  18. {kinemotion-0.10.1 → kinemotion-0.10.2}/CLAUDE.md +0 -0
  19. {kinemotion-0.10.1 → kinemotion-0.10.2}/CODE_OF_CONDUCT.md +0 -0
  20. {kinemotion-0.10.1 → kinemotion-0.10.2}/CONTRIBUTING.md +0 -0
  21. {kinemotion-0.10.1 → kinemotion-0.10.2}/Dockerfile +1 -1
  22. {kinemotion-0.10.1 → kinemotion-0.10.2}/GEMINI.md +0 -0
  23. {kinemotion-0.10.1 → kinemotion-0.10.2}/LICENSE +0 -0
  24. {kinemotion-0.10.1 → kinemotion-0.10.2}/README.md +0 -0
  25. {kinemotion-0.10.1 → kinemotion-0.10.2}/SECURITY.md +0 -0
  26. {kinemotion-0.10.1 → kinemotion-0.10.2}/docs/BULK_PROCESSING.md +0 -0
  27. {kinemotion-0.10.1 → kinemotion-0.10.2}/docs/ERRORS_FINDINGS.md +0 -0
  28. {kinemotion-0.10.1 → kinemotion-0.10.2}/docs/FRAMERATE.md +0 -0
  29. {kinemotion-0.10.1 → kinemotion-0.10.2}/docs/IMU_METADATA_PRESERVATION.md +0 -0
  30. {kinemotion-0.10.1 → kinemotion-0.10.2}/docs/PARAMETERS.md +0 -0
  31. {kinemotion-0.10.1 → kinemotion-0.10.2}/docs/VALIDATION_PLAN.md +0 -0
  32. {kinemotion-0.10.1 → kinemotion-0.10.2}/examples/bulk/README.md +0 -0
  33. {kinemotion-0.10.1 → kinemotion-0.10.2}/examples/bulk/bulk_processing.py +0 -0
  34. {kinemotion-0.10.1 → kinemotion-0.10.2}/examples/bulk/simple_example.py +0 -0
  35. {kinemotion-0.10.1 → kinemotion-0.10.2}/examples/programmatic_usage.py +0 -0
  36. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/__init__.py +0 -0
  37. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/api.py +0 -0
  38. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/cli.py +0 -0
  39. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/core/__init__.py +0 -0
  40. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/core/auto_tuning.py +0 -0
  41. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/core/filtering.py +0 -0
  42. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/core/pose.py +0 -0
  43. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/core/smoothing.py +0 -0
  44. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/core/video_io.py +0 -0
  45. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/dropjump/__init__.py +0 -0
  46. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/dropjump/analysis.py +0 -0
  47. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/dropjump/cli.py +0 -0
  48. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/dropjump/debug_overlay.py +0 -0
  49. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/dropjump/kinematics.py +0 -0
  50. {kinemotion-0.10.1 → kinemotion-0.10.2}/src/kinemotion/py.typed +0 -0
  51. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/__init__.py +0 -0
  52. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_api.py +0 -0
  53. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_com_estimation.py +0 -0
  54. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_contact_detection.py +0 -0
  55. {kinemotion-0.10.1 → kinemotion-0.10.2}/tests/test_kinematics.py +0 -0
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  <!-- version list -->
9
9
 
10
+ ## v0.10.2 (2025-11-03)
11
+
12
+ ### Bug Fixes
13
+
14
+ - Replace legacy numpy random functions with Generator API
15
+ ([`5cfa31b`](https://github.com/feniix/kinemotion/commit/5cfa31bce040eadfc53d52654c2e75087ef087a5))
16
+
17
+
10
18
  ## v0.10.1 (2025-11-03)
11
19
 
12
20
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kinemotion
3
- Version: 0.10.1
3
+ Version: 0.10.2
4
4
  Summary: Video-based kinematic analysis for athletic performance
5
5
  Project-URL: Homepage, https://github.com/feniix/kinemotion
6
6
  Project-URL: Repository, https://github.com/feniix/kinemotion
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kinemotion"
3
- version = "0.10.1"
3
+ version = "0.10.2"
4
4
  description = "Video-based kinematic analysis for athletic performance"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.13"
@@ -14,8 +14,8 @@ def test_adaptive_threshold_basic() -> None:
14
14
  baseline_frames = int(3 * fps) # 90 frames
15
15
 
16
16
  # Baseline: small random noise around position 0.5
17
- np.random.seed(42)
18
- baseline_positions = 0.5 + np.random.normal(0, 0.005, baseline_frames)
17
+ rng = np.random.default_rng(42)
18
+ baseline_positions = 0.5 + rng.normal(0, 0.005, baseline_frames)
19
19
 
20
20
  # Movement: larger position changes
21
21
  movement_positions = np.linspace(0.5, 0.7, 60)
@@ -36,8 +36,8 @@ def test_adaptive_threshold_high_noise() -> None:
36
36
  baseline_frames = int(3 * fps)
37
37
 
38
38
  # High noise baseline
39
- np.random.seed(42)
40
- baseline_positions = 0.5 + np.random.normal(0, 0.015, baseline_frames)
39
+ rng = np.random.default_rng(42)
40
+ baseline_positions = 0.5 + rng.normal(0, 0.015, baseline_frames)
41
41
  movement_positions = np.linspace(0.5, 0.8, 60)
42
42
  positions = np.concatenate([baseline_positions, movement_positions])
43
43
 
@@ -56,8 +56,8 @@ def test_adaptive_threshold_low_noise() -> None:
56
56
  baseline_frames = int(3 * fps)
57
57
 
58
58
  # Very low noise baseline
59
- np.random.seed(42)
60
- baseline_positions = 0.5 + np.random.normal(0, 0.002, baseline_frames)
59
+ rng = np.random.default_rng(42)
60
+ baseline_positions = 0.5 + rng.normal(0, 0.002, baseline_frames)
61
61
  movement_positions = np.linspace(0.5, 0.7, 60)
62
62
  positions = np.concatenate([baseline_positions, movement_positions])
63
63
 
@@ -90,8 +90,8 @@ def test_adaptive_threshold_maximum_bound() -> None:
90
90
  baseline_frames = int(3 * fps)
91
91
 
92
92
  # Extreme noise baseline
93
- np.random.seed(42)
94
- baseline_positions = 0.5 + np.random.normal(0, 0.05, baseline_frames)
93
+ rng = np.random.default_rng(42)
94
+ baseline_positions = 0.5 + rng.normal(0, 0.05, baseline_frames)
95
95
  movement_positions = np.linspace(0.5, 0.8, 60)
96
96
  positions = np.concatenate([baseline_positions, movement_positions])
97
97
 
@@ -106,7 +106,8 @@ def test_adaptive_threshold_short_video() -> None:
106
106
  fps = 30.0
107
107
 
108
108
  # Only 60 frames (2 seconds) - less than 3 second baseline
109
- positions = 0.5 + np.random.normal(0, 0.01, 60)
109
+ rng = np.random.default_rng(42)
110
+ positions = 0.5 + rng.normal(0, 0.01, 60)
110
111
 
111
112
  threshold = calculate_adaptive_threshold(positions, fps, baseline_duration=3.0)
112
113
 
@@ -137,8 +138,8 @@ def test_adaptive_threshold_different_fps() -> None:
137
138
  fps = 60.0
138
139
  baseline_frames = int(3 * fps) # 180 frames
139
140
 
140
- np.random.seed(42)
141
- baseline_positions = 0.5 + np.random.normal(0, 0.008, baseline_frames)
141
+ rng = np.random.default_rng(42)
142
+ baseline_positions = 0.5 + rng.normal(0, 0.008, baseline_frames)
142
143
  movement_positions = np.linspace(0.5, 0.7, 120)
143
144
  positions = np.concatenate([baseline_positions, movement_positions])
144
145
 
@@ -153,8 +154,8 @@ def test_adaptive_threshold_custom_multiplier() -> None:
153
154
  fps = 30.0
154
155
  baseline_frames = int(3 * fps)
155
156
 
156
- np.random.seed(42)
157
- baseline_positions = 0.5 + np.random.normal(0, 0.005, baseline_frames)
157
+ rng = np.random.default_rng(42)
158
+ baseline_positions = 0.5 + rng.normal(0, 0.008, baseline_frames)
158
159
  movement_positions = np.linspace(0.5, 0.7, 60)
159
160
  positions = np.concatenate([baseline_positions, movement_positions])
160
161
 
@@ -181,9 +182,9 @@ def test_adaptive_threshold_baseline_duration() -> None:
181
182
  fps = 30.0
182
183
 
183
184
  # Long video with different noise in different sections
184
- np.random.seed(42)
185
- first_3s = 0.5 + np.random.normal(0, 0.005, int(3 * fps)) # Low noise
186
- next_2s = 0.5 + np.random.normal(0, 0.015, int(2 * fps)) # High noise
185
+ rng = np.random.default_rng(42)
186
+ first_3s = 0.5 + rng.normal(0, 0.005, int(3 * fps)) # Low noise
187
+ next_2s = 0.5 + rng.normal(0, 0.015, int(2 * fps)) # High noise
187
188
  movement = np.linspace(0.5, 0.7, 60)
188
189
 
189
190
  positions = np.concatenate([first_3s, next_2s, movement])
@@ -21,9 +21,10 @@ def create_test_video(
21
21
  fourcc = cv2.VideoWriter_fourcc(*"mp4v")
22
22
  writer = cv2.VideoWriter(temp_path, fourcc, fps, (width, height))
23
23
 
24
+ rng = np.random.default_rng(42)
24
25
  for _ in range(num_frames):
25
26
  # Create a random frame
26
- frame = np.random.randint(0, 255, (height, width, 3), dtype=np.uint8)
27
+ frame = rng.integers(0, 255, (height, width, 3), dtype=np.uint8)
27
28
  writer.write(frame)
28
29
 
29
30
  writer.release()
@@ -35,8 +35,9 @@ def test_detect_outliers_ransac_finds_glitches() -> None:
35
35
  def test_detect_outliers_ransac_handles_clean_data() -> None:
36
36
  """Test that RANSAC does not flag valid points as outliers."""
37
37
  # Create smooth motion with small noise
38
+ rng = np.random.default_rng(42)
38
39
  positions = np.array([0.5 + 0.001 * i**2 for i in range(30)])
39
- positions += np.random.normal(0, 0.001, 30) # Small noise
40
+ positions += rng.normal(0, 0.001, 30) # Small noise
40
41
 
41
42
  outliers = detect_outliers_ransac(
42
43
  positions, window_size=15, threshold=0.02, min_inliers=0.7
@@ -220,8 +221,9 @@ def test_bilateral_temporal_filter_preserves_edges() -> None:
220
221
  def test_bilateral_temporal_filter_smooths_noise() -> None:
221
222
  """Test that bilateral filter smooths noise within smooth regions."""
222
223
  # Noisy flat region
224
+ rng = np.random.default_rng(42)
223
225
  positions = np.array([0.5] * 30)
224
- positions += np.random.normal(0, 0.01, 30)
226
+ positions += rng.normal(0, 0.01, 30)
225
227
 
226
228
  filtered = bilateral_temporal_filter(
227
229
  positions, window_size=9, sigma_spatial=3.0, sigma_intensity=0.02
@@ -233,7 +235,8 @@ def test_bilateral_temporal_filter_smooths_noise() -> None:
233
235
 
234
236
  def test_bilateral_temporal_filter_window_size() -> None:
235
237
  """Test that bilateral filter handles even window sizes."""
236
- positions = np.random.rand(50)
238
+ rng = np.random.default_rng(42)
239
+ positions = rng.random(50)
237
240
 
238
241
  # Even window size should be adjusted to odd
239
242
  filtered_even = bilateral_temporal_filter(
@@ -284,10 +287,11 @@ def test_smooth_landmarks_advanced_with_bilateral() -> None:
284
287
  # Create landmark sequence with sharp transition (landing)
285
288
  n_frames = 40
286
289
  landmark_sequence = []
290
+ rng = np.random.default_rng(42)
287
291
 
288
292
  for i in range(n_frames):
289
293
  y = 0.8 if i < 20 else 0.5 # Sharp drop at frame 20
290
- y += np.random.normal(0, 0.005) # Add noise
294
+ y += rng.normal(0, 0.005) # Add noise
291
295
 
292
296
  landmark_sequence.append(
293
297
  {
@@ -322,10 +326,11 @@ def test_smooth_landmarks_advanced_combined() -> None:
322
326
  n_frames = 50
323
327
  landmark_sequence = []
324
328
 
329
+ rng = np.random.default_rng(42)
325
330
  for i in range(n_frames):
326
331
  # Parabolic motion
327
332
  y = 0.5 + 0.001 * (i - 25) ** 2
328
- y += np.random.normal(0, 0.005) # Noise
333
+ y += rng.normal(0, 0.005) # Noise
329
334
 
330
335
  # Add tracking glitch
331
336
  if i == 25:
@@ -15,10 +15,11 @@ def test_smooth_landmarks_polyorder2_vs_polyorder3() -> None:
15
15
  n_frames = 30
16
16
  landmark_sequence = []
17
17
 
18
+ rng = np.random.default_rng(42)
18
19
  for i in range(n_frames):
19
20
  # Smooth parabolic motion with noise
20
21
  base_y = 0.5 + 0.01 * (i - 15) ** 2 / 225 # Parabola
21
- noisy_y = base_y + np.random.normal(0, 0.01)
22
+ noisy_y = base_y + rng.normal(0, 0.01)
22
23
 
23
24
  landmark_sequence.append(
24
25
  {
@@ -49,9 +50,10 @@ def test_smooth_landmarks_polyorder2_vs_polyorder3() -> None:
49
50
  def test_velocity_from_derivative_polyorder() -> None:
50
51
  """Test velocity computation with different polynomial orders."""
51
52
  # Create synthetic position data with quadratic motion
53
+ rng = np.random.default_rng(42)
52
54
  t = np.linspace(0, 2, 60)
53
55
  positions = 0.5 + 0.1 * t**2 # Parabolic trajectory
54
- positions += np.random.normal(0, 0.005, len(positions)) # Add noise
56
+ positions += rng.normal(0, 0.005, len(positions)) # Add noise
55
57
 
56
58
  # Compute velocity with different polynomial orders
57
59
  velocity_2 = compute_velocity_from_derivative(
@@ -79,9 +81,10 @@ def test_velocity_from_derivative_polyorder() -> None:
79
81
  def test_acceleration_from_derivative_polyorder() -> None:
80
82
  """Test acceleration computation with different polynomial orders."""
81
83
  # Create synthetic position data with cubic motion (non-zero third derivative)
84
+ rng = np.random.default_rng(42)
82
85
  t = np.linspace(0, 2, 60)
83
86
  positions = 0.5 + 0.05 * t**3 # Cubic trajectory
84
- positions += np.random.normal(0, 0.003, len(positions)) # Add noise
87
+ positions += rng.normal(0, 0.003, len(positions)) # Add noise
85
88
 
86
89
  # Compute acceleration with different polynomial orders
87
90
  accel_2 = compute_acceleration_from_derivative(
@@ -111,7 +114,8 @@ def test_acceleration_from_derivative_polyorder() -> None:
111
114
 
112
115
  def test_polyorder_validation() -> None:
113
116
  """Test that polyorder must be less than window_length."""
114
- positions = np.random.rand(50)
117
+ rng = np.random.default_rng(42)
118
+ positions = rng.random(50)
115
119
 
116
120
  # polyorder=2 with window=5 should work (2 < 5)
117
121
  velocity_valid = compute_velocity_from_derivative(
@@ -603,7 +603,7 @@ wheels = [
603
603
 
604
604
  [[package]]
605
605
  name = "kinemotion"
606
- version = "0.10.0"
606
+ version = "0.10.1"
607
607
  source = { editable = "." }
608
608
  dependencies = [
609
609
  { name = "click" },
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -53,10 +53,10 @@ LABEL org.opencontainers.image.title="kinemotion" \
53
53
  # - ffmpeg: Video codec support for OpenCV
54
54
  # hadolint ignore=DL3008
55
55
  RUN apt-get update && apt-get install -y --no-install-recommends \
56
+ ffmpeg \
56
57
  libgl1 \
57
58
  libglib2.0-0 \
58
59
  libgomp1 \
59
- ffmpeg \
60
60
  && apt-get clean \
61
61
  && rm -rf /var/lib/apt/lists/*
62
62
 
File without changes
File without changes
File without changes
File without changes