kinemotion 0.71.0__py3-none-any.whl → 0.71.1__py3-none-any.whl

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.
@@ -5,6 +5,7 @@ import json
5
5
  import sys
6
6
  from dataclasses import dataclass
7
7
  from pathlib import Path
8
+ from typing import TYPE_CHECKING
8
9
 
9
10
  import click
10
11
 
@@ -19,6 +20,9 @@ from .api import (
19
20
  process_dropjump_videos_bulk,
20
21
  )
21
22
 
23
+ if TYPE_CHECKING:
24
+ from .api import AnalysisOverrides
25
+
22
26
 
23
27
  @dataclass
24
28
  class AnalysisParameters:
@@ -225,6 +229,34 @@ def dropjump_analyze( # NOSONAR(S107) - Click CLI requires individual
225
229
  )
226
230
 
227
231
 
232
+ def _create_overrides_if_needed(params: AnalysisParameters) -> "AnalysisOverrides | None":
233
+ """Create AnalysisOverrides if any override parameters are set.
234
+
235
+ Args:
236
+ params: Expert parameters from CLI
237
+
238
+ Returns:
239
+ AnalysisOverrides if any relevant parameters are non-None, else None
240
+ """
241
+ from .api import AnalysisOverrides
242
+
243
+ if any(
244
+ [
245
+ params.smoothing_window is not None,
246
+ params.velocity_threshold is not None,
247
+ params.min_contact_frames is not None,
248
+ params.visibility_threshold is not None,
249
+ ]
250
+ ):
251
+ return AnalysisOverrides(
252
+ smoothing_window=params.smoothing_window,
253
+ velocity_threshold=params.velocity_threshold,
254
+ min_contact_frames=params.min_contact_frames,
255
+ visibility_threshold=params.visibility_threshold,
256
+ )
257
+ return None
258
+
259
+
228
260
  def _process_single(
229
261
  video_path: str,
230
262
  output: str | None,
@@ -237,24 +269,7 @@ def _process_single(
237
269
  click.echo(f"Analyzing video: {video_path}", err=True)
238
270
 
239
271
  try:
240
- # Create AnalysisOverrides if any expert parameters are set
241
- from .api import AnalysisOverrides
242
-
243
- overrides = None
244
- if any(
245
- [
246
- expert_params.smoothing_window is not None,
247
- expert_params.velocity_threshold is not None,
248
- expert_params.min_contact_frames is not None,
249
- expert_params.visibility_threshold is not None,
250
- ]
251
- ):
252
- overrides = AnalysisOverrides(
253
- smoothing_window=expert_params.smoothing_window,
254
- velocity_threshold=expert_params.velocity_threshold,
255
- min_contact_frames=expert_params.min_contact_frames,
256
- visibility_threshold=expert_params.visibility_threshold,
257
- )
272
+ overrides = _create_overrides_if_needed(expert_params)
258
273
 
259
274
  # Call the API function (handles all processing logic)
260
275
  metrics = process_dropjump_video(
@@ -328,24 +343,7 @@ def _create_video_configs(
328
343
  video_file, output_dir, json_output_dir
329
344
  )
330
345
 
331
- # Create AnalysisOverrides if any expert parameters are set
332
- from .api import AnalysisOverrides
333
-
334
- overrides = None
335
- if any(
336
- [
337
- expert_params.smoothing_window is not None,
338
- expert_params.velocity_threshold is not None,
339
- expert_params.min_contact_frames is not None,
340
- expert_params.visibility_threshold is not None,
341
- ]
342
- ):
343
- overrides = AnalysisOverrides(
344
- smoothing_window=expert_params.smoothing_window,
345
- velocity_threshold=expert_params.velocity_threshold,
346
- min_contact_frames=expert_params.min_contact_frames,
347
- visibility_threshold=expert_params.visibility_threshold,
348
- )
346
+ overrides = _create_overrides_if_needed(expert_params)
349
347
 
350
348
  config = DropJumpVideoConfig(
351
349
  video_path=video_file,
@@ -380,35 +378,33 @@ def _compute_batch_statistics(results: list[DropJumpVideoResult]) -> None:
380
378
  click.echo(f"Failed: {len(failed)}", err=True)
381
379
 
382
380
  if successful:
383
- # Calculate average metrics
384
- with_gct = [
385
- r for r in successful if r.metrics and r.metrics.ground_contact_time is not None
381
+ # Calculate average metrics from results with non-None values
382
+ gct_values = [
383
+ r.metrics.ground_contact_time * 1000
384
+ for r in successful
385
+ if r.metrics and r.metrics.ground_contact_time is not None
386
+ ]
387
+ flight_values = [
388
+ r.metrics.flight_time * 1000
389
+ for r in successful
390
+ if r.metrics and r.metrics.flight_time is not None
386
391
  ]
387
- with_flight = [r for r in successful if r.metrics and r.metrics.flight_time is not None]
388
- with_jump = [r for r in successful if r.metrics and r.metrics.jump_height is not None]
389
-
390
- if with_gct:
391
- avg_gct = sum(
392
- r.metrics.ground_contact_time * 1000
393
- for r in with_gct
394
- if r.metrics and r.metrics.ground_contact_time is not None
395
- ) / len(with_gct)
392
+ jump_values = [
393
+ r.metrics.jump_height
394
+ for r in successful
395
+ if r.metrics and r.metrics.jump_height is not None
396
+ ]
397
+
398
+ if gct_values:
399
+ avg_gct = sum(gct_values) / len(gct_values)
396
400
  click.echo(f"\nAverage ground contact time: {avg_gct:.1f} ms", err=True)
397
401
 
398
- if with_flight:
399
- avg_flight = sum(
400
- r.metrics.flight_time * 1000
401
- for r in with_flight
402
- if r.metrics and r.metrics.flight_time is not None
403
- ) / len(with_flight)
402
+ if flight_values:
403
+ avg_flight = sum(flight_values) / len(flight_values)
404
404
  click.echo(f"Average flight time: {avg_flight:.1f} ms", err=True)
405
405
 
406
- if with_jump:
407
- avg_jump = sum(
408
- r.metrics.jump_height
409
- for r in with_jump
410
- if r.metrics and r.metrics.jump_height is not None
411
- ) / len(with_jump)
406
+ if jump_values:
407
+ avg_jump = sum(jump_values) / len(jump_values)
412
408
  click.echo(
413
409
  f"Average jump height: {avg_jump:.3f} m ({avg_jump * 100:.1f} cm)",
414
410
  err=True,
@@ -453,38 +449,27 @@ def _create_csv_row_from_result(result: DropJumpVideoResult) -> list[str]:
453
449
  processing_time = f"{result.processing_time:.2f}"
454
450
 
455
451
  if result.success and result.metrics:
456
- return [
457
- video_name,
452
+ metrics_data = [
458
453
  _format_time_metric(result.metrics.ground_contact_time),
459
454
  _format_time_metric(result.metrics.flight_time),
460
455
  _format_distance_metric(result.metrics.jump_height),
461
- processing_time,
462
- "Success",
463
- ]
464
- else:
465
- return [
466
- video_name,
467
- "N/A",
468
- "N/A",
469
- "N/A",
470
- processing_time,
471
- f"Failed: {result.error}",
472
456
  ]
457
+ return [video_name, *metrics_data, processing_time, "Success"]
458
+
459
+ return [video_name, "N/A", "N/A", "N/A", processing_time, f"Failed: {result.error}"]
473
460
 
474
461
 
475
462
  def _write_csv_summary(
476
463
  csv_summary: str | None,
477
464
  results: list[DropJumpVideoResult],
478
- successful: list[DropJumpVideoResult],
479
465
  ) -> None:
480
466
  """Write CSV summary of batch processing results.
481
467
 
482
468
  Args:
483
469
  csv_summary: Path to CSV output file
484
470
  results: All processing results
485
- successful: Successful processing results
486
471
  """
487
- if not csv_summary or not successful:
472
+ if not csv_summary:
488
473
  return
489
474
 
490
475
  click.echo(f"\nExporting CSV summary to: {csv_summary}", err=True)
@@ -558,7 +543,6 @@ def _process_batch(
558
543
  _compute_batch_statistics(results)
559
544
 
560
545
  # Export CSV summary if requested
561
- successful = [r for r in results if r.success]
562
- _write_csv_summary(csv_summary, results, successful)
546
+ _write_csv_summary(csv_summary, results)
563
547
 
564
548
  click.echo("\nBatch processing complete!", err=True)
@@ -4,61 +4,80 @@ import cv2
4
4
  import numpy as np
5
5
 
6
6
  from ..core.debug_overlay_utils import BaseDebugOverlayRenderer
7
+ from ..core.overlay_constants import (
8
+ BLACK,
9
+ COM_CIRCLE_RADIUS,
10
+ COM_OUTLINE_RADIUS,
11
+ CYAN,
12
+ FOOT_CIRCLE_RADIUS,
13
+ FOOT_LANDMARK_RADIUS,
14
+ FOOT_VISIBILITY_THRESHOLD,
15
+ GREEN,
16
+ HIP_MARKER_RADIUS,
17
+ METRICS_BOX_WIDTH,
18
+ ORANGE,
19
+ PHASE_LABEL_LINE_HEIGHT,
20
+ PHASE_LABEL_START_Y,
21
+ RED,
22
+ WHITE,
23
+ Color,
24
+ LandmarkDict,
25
+ )
7
26
  from ..core.pose import compute_center_of_mass
8
27
  from .analysis import ContactState, compute_average_foot_position
9
28
  from .kinematics import DropJumpMetrics
10
29
 
11
30
 
12
- class DebugOverlayRenderer(BaseDebugOverlayRenderer):
31
+ class DropJumpDebugOverlayRenderer(BaseDebugOverlayRenderer):
13
32
  """Renders debug information on video frames."""
14
33
 
34
+ def _get_contact_state_color(self, contact_state: ContactState) -> Color:
35
+ """Get color based on ground contact state."""
36
+ return GREEN if contact_state == ContactState.ON_GROUND else RED
37
+
15
38
  def _draw_com_visualization(
16
39
  self,
17
40
  frame: np.ndarray,
18
- landmarks: dict[str, tuple[float, float, float]],
41
+ landmarks: LandmarkDict,
19
42
  contact_state: ContactState,
20
43
  ) -> None:
21
44
  """Draw center of mass visualization on frame."""
22
45
  com_x, com_y, _ = compute_center_of_mass(landmarks)
23
- px = int(com_x * self.width)
24
- py = int(com_y * self.height)
46
+ px, py = self._normalize_to_pixels(com_x, com_y)
25
47
 
26
- color = (0, 255, 0) if contact_state == ContactState.ON_GROUND else (0, 0, 255)
27
- cv2.circle(frame, (px, py), 15, color, -1)
28
- cv2.circle(frame, (px, py), 17, (255, 255, 255), 2)
48
+ color = self._get_contact_state_color(contact_state)
49
+ cv2.circle(frame, (px, py), COM_CIRCLE_RADIUS, color, -1)
50
+ cv2.circle(frame, (px, py), COM_OUTLINE_RADIUS, WHITE, 2)
29
51
 
30
52
  # Draw hip midpoint reference
31
53
  if "left_hip" in landmarks and "right_hip" in landmarks:
32
54
  lh_x, lh_y, _ = landmarks["left_hip"]
33
55
  rh_x, rh_y, _ = landmarks["right_hip"]
34
- hip_x = int((lh_x + rh_x) / 2 * self.width)
35
- hip_y = int((lh_y + rh_y) / 2 * self.height)
36
- cv2.circle(frame, (hip_x, hip_y), 8, (255, 165, 0), -1)
37
- cv2.line(frame, (hip_x, hip_y), (px, py), (255, 165, 0), 2)
56
+ hip_x, hip_y = self._normalize_to_pixels((lh_x + rh_x) / 2, (lh_y + rh_y) / 2)
57
+ cv2.circle(frame, (hip_x, hip_y), HIP_MARKER_RADIUS, ORANGE, -1)
58
+ cv2.line(frame, (hip_x, hip_y), (px, py), ORANGE, 2)
38
59
 
39
60
  def _draw_foot_visualization(
40
61
  self,
41
62
  frame: np.ndarray,
42
- landmarks: dict[str, tuple[float, float, float]],
63
+ landmarks: LandmarkDict,
43
64
  contact_state: ContactState,
44
65
  ) -> None:
45
66
  """Draw foot position visualization on frame."""
46
67
  foot_x, foot_y = compute_average_foot_position(landmarks)
47
- px = int(foot_x * self.width)
48
- py = int(foot_y * self.height)
68
+ px, py = self._normalize_to_pixels(foot_x, foot_y)
49
69
 
50
- color = (0, 255, 0) if contact_state == ContactState.ON_GROUND else (0, 0, 255)
51
- cv2.circle(frame, (px, py), 10, color, -1)
70
+ color = self._get_contact_state_color(contact_state)
71
+ cv2.circle(frame, (px, py), FOOT_CIRCLE_RADIUS, color, -1)
52
72
 
53
73
  # Draw individual foot landmarks
54
74
  foot_keys = ["left_ankle", "right_ankle", "left_heel", "right_heel"]
55
75
  for key in foot_keys:
56
76
  if key in landmarks:
57
77
  x, y, vis = landmarks[key]
58
- if vis > 0.5:
59
- lx = int(x * self.width)
60
- ly = int(y * self.height)
61
- cv2.circle(frame, (lx, ly), 5, (255, 255, 0), -1)
78
+ if vis > FOOT_VISIBILITY_THRESHOLD:
79
+ lx, ly = self._normalize_to_pixels(x, y)
80
+ cv2.circle(frame, (lx, ly), FOOT_LANDMARK_RADIUS, CYAN, -1)
62
81
 
63
82
  def _draw_phase_labels(
64
83
  self,
@@ -67,58 +86,99 @@ class DebugOverlayRenderer(BaseDebugOverlayRenderer):
67
86
  metrics: DropJumpMetrics,
68
87
  ) -> None:
69
88
  """Draw phase labels (ground contact, flight, peak) on frame."""
70
- y_offset = 110
71
-
72
- # Ground contact phase
73
- if (
74
- metrics.contact_start_frame
75
- and metrics.contact_end_frame
76
- and metrics.contact_start_frame <= frame_idx <= metrics.contact_end_frame
77
- ):
89
+ # Phase configurations: (start_frame, end_frame, label, color)
90
+ # For range-based phases (ground contact, flight)
91
+ range_phase_configs = [
92
+ (metrics.contact_start_frame, metrics.contact_end_frame, "GROUND CONTACT", GREEN),
93
+ (metrics.flight_start_frame, metrics.flight_end_frame, "FLIGHT PHASE", RED),
94
+ ]
95
+
96
+ y_offset = PHASE_LABEL_START_Y
97
+ for start_frame, end_frame, label, color in range_phase_configs:
98
+ if start_frame and end_frame and start_frame <= frame_idx <= end_frame:
99
+ cv2.putText(
100
+ frame,
101
+ label,
102
+ (10, y_offset),
103
+ cv2.FONT_HERSHEY_SIMPLEX,
104
+ 0.7,
105
+ color,
106
+ 2,
107
+ )
108
+ y_offset += PHASE_LABEL_LINE_HEIGHT
109
+
110
+ # Single-frame indicator (peak height)
111
+ if metrics.peak_height_frame == frame_idx:
78
112
  cv2.putText(
79
113
  frame,
80
- "GROUND CONTACT",
114
+ "PEAK HEIGHT",
81
115
  (10, y_offset),
82
116
  cv2.FONT_HERSHEY_SIMPLEX,
83
117
  0.7,
84
- (0, 255, 0),
118
+ (255, 0, 255), # Magenta
85
119
  2,
86
120
  )
87
- y_offset += 40
88
121
 
89
- # Flight phase
122
+ def _draw_info_box(
123
+ self,
124
+ frame: np.ndarray,
125
+ top_left: tuple[int, int],
126
+ bottom_right: tuple[int, int],
127
+ border_color: Color,
128
+ ) -> None:
129
+ """Draw a filled box with border for displaying information."""
130
+ cv2.rectangle(frame, top_left, bottom_right, BLACK, -1)
131
+ cv2.rectangle(frame, top_left, bottom_right, border_color, 2)
132
+
133
+ def _draw_metrics_summary(
134
+ self, frame: np.ndarray, frame_idx: int, metrics: DropJumpMetrics
135
+ ) -> None:
136
+ """Draw metrics summary in bottom right after flight phase ends."""
137
+ if metrics.flight_end_frame is None or frame_idx < metrics.flight_end_frame:
138
+ return
139
+
140
+ # Build metrics text list
141
+ metrics_text: list[str] = []
142
+
143
+ if metrics.ground_contact_time is not None:
144
+ metrics_text.append(f"Contact Time: {metrics.ground_contact_time * 1000:.0f}ms")
145
+
146
+ if metrics.flight_time is not None:
147
+ metrics_text.append(f"Flight Time: {metrics.flight_time * 1000:.0f}ms")
148
+
149
+ if metrics.jump_height is not None:
150
+ metrics_text.append(f"Jump Height: {metrics.jump_height:.3f}m")
151
+
152
+ # Calculate RSI (Reactive Strength Index)
90
153
  if (
91
- metrics.flight_start_frame
92
- and metrics.flight_end_frame
93
- and metrics.flight_start_frame <= frame_idx <= metrics.flight_end_frame
154
+ metrics.jump_height is not None
155
+ and metrics.ground_contact_time is not None
156
+ and metrics.ground_contact_time > 0
94
157
  ):
95
- cv2.putText(
96
- frame,
97
- "FLIGHT PHASE",
98
- (10, y_offset),
99
- cv2.FONT_HERSHEY_SIMPLEX,
100
- 0.7,
101
- (0, 0, 255),
102
- 2,
103
- )
104
- y_offset += 40
158
+ rsi = metrics.jump_height / metrics.ground_contact_time
159
+ metrics_text.append(f"RSI: {rsi:.2f}")
105
160
 
106
- # Peak height
107
- if metrics.peak_height_frame == frame_idx:
108
- cv2.putText(
109
- frame,
110
- "PEAK HEIGHT",
111
- (10, y_offset),
112
- cv2.FONT_HERSHEY_SIMPLEX,
113
- 0.7,
114
- (255, 0, 255),
115
- 2,
116
- )
161
+ if not metrics_text:
162
+ return
163
+
164
+ # Calculate box dimensions
165
+ box_height = len(metrics_text) * 30 + 20
166
+ top_left = (self.width - METRICS_BOX_WIDTH, self.height - box_height - 10)
167
+ bottom_right = (self.width - 10, self.height - 10)
168
+
169
+ self._draw_info_box(frame, top_left, bottom_right, GREEN)
170
+
171
+ # Draw metrics text
172
+ text_x = self.width - METRICS_BOX_WIDTH + 10
173
+ text_y = self.height - box_height + 10
174
+ for text in metrics_text:
175
+ cv2.putText(frame, text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, WHITE, 1)
176
+ text_y += 30
117
177
 
118
178
  def render_frame(
119
179
  self,
120
180
  frame: np.ndarray,
121
- landmarks: dict[str, tuple[float, float, float]] | None,
181
+ landmarks: LandmarkDict | None,
122
182
  contact_state: ContactState,
123
183
  frame_idx: int,
124
184
  metrics: DropJumpMetrics | None = None,
@@ -141,16 +201,17 @@ class DebugOverlayRenderer(BaseDebugOverlayRenderer):
141
201
  with self.timer.measure("debug_video_copy"):
142
202
  annotated = frame.copy()
143
203
 
144
- def _draw_overlays() -> None:
145
- # Draw landmarks
204
+ with self.timer.measure("debug_video_draw"):
205
+ # Draw skeleton and landmarks
146
206
  if landmarks:
207
+ self._draw_skeleton(annotated, landmarks)
147
208
  if use_com:
148
209
  self._draw_com_visualization(annotated, landmarks, contact_state)
149
210
  else:
150
211
  self._draw_foot_visualization(annotated, landmarks, contact_state)
151
212
 
152
213
  # Draw contact state
153
- state_color = (0, 255, 0) if contact_state == ContactState.ON_GROUND else (0, 0, 255)
214
+ state_color = self._get_contact_state_color(contact_state)
154
215
  cv2.putText(
155
216
  annotated,
156
217
  f"State: {contact_state.value}",
@@ -168,15 +229,13 @@ class DebugOverlayRenderer(BaseDebugOverlayRenderer):
168
229
  (10, 70),
169
230
  cv2.FONT_HERSHEY_SIMPLEX,
170
231
  0.7,
171
- (255, 255, 255),
232
+ WHITE,
172
233
  2,
173
234
  )
174
235
 
175
- # Draw phase labels
236
+ # Draw phase labels and metrics summary
176
237
  if metrics:
177
238
  self._draw_phase_labels(annotated, frame_idx, metrics)
178
-
179
- with self.timer.measure("debug_video_draw"):
180
- _draw_overlays()
239
+ self._draw_metrics_summary(annotated, frame_idx, metrics)
181
240
 
182
241
  return annotated
@@ -124,7 +124,7 @@ def _classify_combined_score(combined_score: float) -> AthleteProfile:
124
124
  return AthleteProfile.ELITE
125
125
 
126
126
 
127
- def estimate_athlete_profile(metrics: MetricsDict, gender: str | None = None) -> AthleteProfile:
127
+ def estimate_athlete_profile(metrics: MetricsDict, _gender: str | None = None) -> AthleteProfile:
128
128
  """Estimate athlete profile from drop jump metrics.
129
129
 
130
130
  Uses jump_height and contact_time to classify athlete level.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kinemotion
3
- Version: 0.71.0
3
+ Version: 0.71.1
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
@@ -0,0 +1,50 @@
1
+ kinemotion/__init__.py,sha256=HkD8habCcfxGobxZcACOStla-L1nYHMIZp0th00Q3E8,1061
2
+ kinemotion/api.py,sha256=uG1e4bTnj2c-6cbZJEZ_LjMwFdaG32ba2KcK_XjE_NI,1040
3
+ kinemotion/cli.py,sha256=_Us9krSce4GUKtlLIPrFUhKmPWURzeJ1-ydR_YU2VGw,626
4
+ kinemotion/cmj/__init__.py,sha256=SkAw9ka8Yd1Qfv9hcvk22m3EfucROzYrSNGNF5kDzho,113
5
+ kinemotion/cmj/analysis.py,sha256=EQydClIbNkIj-FmCZGaPQe-COVW8fbO3139i9z1vomA,23643
6
+ kinemotion/cmj/api.py,sha256=P_lbqEqAKPO5n1Xn4IQZKNj9nLaO3ljkN2PgqvExGXU,18435
7
+ kinemotion/cmj/cli.py,sha256=P2b77IIw6kqTSIkncxlShzhmjIwqMFBNd-pZxYP-TsI,9918
8
+ kinemotion/cmj/debug_overlay.py,sha256=vF5Apiz8zDRpgrVzf52manLW99m1kHQAPSdUkar5rPs,11474
9
+ kinemotion/cmj/joint_angles.py,sha256=by5M4LDtUfd2_Z9DmcgUl0nsvarsBYjgsE8KWWYcn08,11255
10
+ kinemotion/cmj/kinematics.py,sha256=KwA8uSj3g1SeNf0NXMSHsp3gIw6Gfa-6QWIwdYdRXYw,13362
11
+ kinemotion/cmj/metrics_validator.py,sha256=IQofafpwLCXER3ucZXNfiJKFFKPOVxXnC4BNLHOMnNY,30013
12
+ kinemotion/cmj/validation_bounds.py,sha256=-0iXDhH-RntiGZi_Co22V6qtA5D-hLzkrPkVcfoNd2U,11343
13
+ kinemotion/core/__init__.py,sha256=8hMvfNK7v_eqswuk_J5s5FRGvPtp2-R4kasVMGchFkM,1766
14
+ kinemotion/core/auto_tuning.py,sha256=dF2opupuphbTd6sZIDyXX8hwedLaNlMiH-hT7PGqnfU,10251
15
+ kinemotion/core/cli_utils.py,sha256=sQPbT6XWWau-sm9yuN5c3eS5xNzoQGGXwSz6hQXtRvM,1859
16
+ kinemotion/core/debug_overlay_utils.py,sha256=QaVkHuFZpXUrdiMlm8ylQn6baJOj8jcZeiV4kDqODt0,17441
17
+ kinemotion/core/determinism.py,sha256=Frw-KAOvAxTL_XtxoWpXCjMbQPUKEAusK6JctlkeuRo,2509
18
+ kinemotion/core/experimental.py,sha256=G1EpkmWQ8d-rPaN1n0P7mF6XUzrbW0Br3nVkIzJ1D9M,3694
19
+ kinemotion/core/filtering.py,sha256=7KUeclXqZpNQA8WKNocDwhCxZpwwtizI3wvAEyq9SBo,11603
20
+ kinemotion/core/formatting.py,sha256=G_3eqgOtym9RFOZVEwCxye4A2cyrmgvtQ214vIshowU,2480
21
+ kinemotion/core/metadata.py,sha256=bJAVa4nym__zx1hNowSZduMGKBSGOPxTbBQkjm6N0D0,7207
22
+ kinemotion/core/model_downloader.py,sha256=mqhJBHGaNe0aN9qbcBqvcTk9FDd7xaHqEcwD-fyP89c,5205
23
+ kinemotion/core/overlay_constants.py,sha256=zZreHHWe00p2XuCJsbRFqN6g-AAUAnx53LwKqHm1Bl8,1438
24
+ kinemotion/core/pipeline_utils.py,sha256=B5jMXoiLaTh02uGA2MIe1uZLVSRGZ5nxbARuvdrjDrQ,15161
25
+ kinemotion/core/pose.py,sha256=Z795p0EnaTUeWHO8FuApFcMGTLwZ47JOjs5f5TzRvdk,14224
26
+ kinemotion/core/pose_landmarks.py,sha256=LcEbL5K5xKia6dCzWf6Ft18UIE1CLMMqCZ3KUjwUDzM,1558
27
+ kinemotion/core/quality.py,sha256=VUkRL2N6B7lfIZ2pE9han_U68JwarmZz1U0ygHkgkhE,13022
28
+ kinemotion/core/smoothing.py,sha256=F1DCsnvPBi62XJLygOJ5MkNlRa7BCLg_E9ORtCWcoKk,16562
29
+ kinemotion/core/timing.py,sha256=ITX77q4hbtajRuWfgwYhws8nCvOeKFlEdKjCu8lD9_w,7938
30
+ kinemotion/core/types.py,sha256=m141buSkEsqflt5VFaTHtRq_IcimjI3_T_EfaNpIVxY,1652
31
+ kinemotion/core/validation.py,sha256=rrhpI24Iq8WGtNaMg0beTWMbEGccdKF-f-pk-FCKJzI,6749
32
+ kinemotion/core/video_io.py,sha256=84IxC1n3HvYK28MSa5fqumdzlPDhP8k9IPB3OCvWku0,9198
33
+ kinemotion/dropjump/__init__.py,sha256=yBbEbPdY6sqozWtTvfbvuUZnrVWSSjBp61xK34M29F4,878
34
+ kinemotion/dropjump/analysis.py,sha256=Tc41jVctG4zJZOyYqM1SiM95mnF2xz4vcieGJ6vYi2M,29099
35
+ kinemotion/dropjump/api.py,sha256=5qBj05e6Zo-H4-UjBOIt_CYyDqLVcPhwyyLG04eJYMU,20639
36
+ kinemotion/dropjump/cli.py,sha256=FaBX637x7VcLcB8HupaZCkVS7sp8C0YuaKM0h-DBNIA,15906
37
+ kinemotion/dropjump/debug_overlay.py,sha256=X4mvCi5Qi1gnvSZZAsUs-0ZRUx9mVBbEUznOFO21HO8,8470
38
+ kinemotion/dropjump/kinematics.py,sha256=dx4PuXKfKMKcsc_HX6sXj8rHXf9ksiZIOAIkJ4vBlY4,19637
39
+ kinemotion/dropjump/metrics_validator.py,sha256=lSfo4Lm5FHccl8ijUP6SA-kcSh50LS9hF8UIyWxcnW8,9243
40
+ kinemotion/dropjump/validation_bounds.py,sha256=k31qy-kCXTiCTx0RPo2t8yZ-faLxqGO-AeF05QfBFb0,5125
41
+ kinemotion/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ kinemotion/models/pose_landmarker_lite.task,sha256=WZKeHR7pUodzXd2DOxnPSsRtKbx6_du_Z1PEWWkNV0o,5777746
43
+ kinemotion/models/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.onnx,sha256=dfZTq8kbhv8RxWiXS0HUIJNCUpxYTBN45dFIorPflEs,133
44
+ kinemotion/models/yolox_tiny_8xb8-300e_humanart-6f3252f9.onnx,sha256=UsutHVQ6GP3X5pCcp52EN8q7o2J3d-TnxZqlF48kY6I,133
45
+ kinemotion/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ kinemotion-0.71.1.dist-info/METADATA,sha256=D2ZS9pNSi3NAaSkYKoQ09PZaJ-B3qWDHPLChu3oxdbY,26125
47
+ kinemotion-0.71.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
48
+ kinemotion-0.71.1.dist-info/entry_points.txt,sha256=zaqnAnjLvcdrk1Qvj5nvXZCZ2gp0prS7it1zTJygcIY,50
49
+ kinemotion-0.71.1.dist-info/licenses/LICENSE,sha256=KZajvqsHw0NoOHOi2q0FZ4NBe9HdV6oey-IPYAtHXfg,1088
50
+ kinemotion-0.71.1.dist-info/RECORD,,
@@ -1,49 +0,0 @@
1
- kinemotion/__init__.py,sha256=HkD8habCcfxGobxZcACOStla-L1nYHMIZp0th00Q3E8,1061
2
- kinemotion/api.py,sha256=uG1e4bTnj2c-6cbZJEZ_LjMwFdaG32ba2KcK_XjE_NI,1040
3
- kinemotion/cli.py,sha256=_Us9krSce4GUKtlLIPrFUhKmPWURzeJ1-ydR_YU2VGw,626
4
- kinemotion/cmj/__init__.py,sha256=SkAw9ka8Yd1Qfv9hcvk22m3EfucROzYrSNGNF5kDzho,113
5
- kinemotion/cmj/analysis.py,sha256=WcFNJVd9zpwvDrbe41VshXqP9MFfptlgYD4Nph5mHLA,23675
6
- kinemotion/cmj/api.py,sha256=5PDV_vX3k63Ko4OEttyUkV4fWyklyy-CG_UyNKgNoyY,18476
7
- kinemotion/cmj/cli.py,sha256=P2b77IIw6kqTSIkncxlShzhmjIwqMFBNd-pZxYP-TsI,9918
8
- kinemotion/cmj/debug_overlay.py,sha256=bX9aPLhXiLCCMZW9v8Y4OiOAaZO0i-UGr-Pl8HCsmbI,15810
9
- kinemotion/cmj/joint_angles.py,sha256=HmheIEiKcQz39cRezk4h-htorOhGNPsqKIR9RsAEKts,9960
10
- kinemotion/cmj/kinematics.py,sha256=KwA8uSj3g1SeNf0NXMSHsp3gIw6Gfa-6QWIwdYdRXYw,13362
11
- kinemotion/cmj/metrics_validator.py,sha256=JWuWFfDXyZMTHXFWVdI0MhaQjMR3cjd01tTrDy_if2U,30290
12
- kinemotion/cmj/validation_bounds.py,sha256=Ry915JdInPXbqjaVGNY_urnDO1PAkCSJqHwNKRq-VkU,12048
13
- kinemotion/core/__init__.py,sha256=8WB7tAJPKOxgNzbhIEOnGnkRr0CcdNeTnz91Jsiyafo,1812
14
- kinemotion/core/auto_tuning.py,sha256=lhAqPc-eLjMYx9BCvKdECE7TD2Dweb9KcifV6JHaXOE,11278
15
- kinemotion/core/cli_utils.py,sha256=sQPbT6XWWau-sm9yuN5c3eS5xNzoQGGXwSz6hQXtRvM,1859
16
- kinemotion/core/debug_overlay_utils.py,sha256=D4aT8xstThPcV2i5D4KJZJEttW6E_4GE5QiERqe1MwI,13049
17
- kinemotion/core/determinism.py,sha256=Frw-KAOvAxTL_XtxoWpXCjMbQPUKEAusK6JctlkeuRo,2509
18
- kinemotion/core/experimental.py,sha256=IK05AF4aZS15ke85hF3TWCqRIXU1AlD_XKzFz735Ua8,3640
19
- kinemotion/core/filtering.py,sha256=Oc__pV6iHEGyyovbqa5SUi-6v8QyvaRVwA0LRayM884,11355
20
- kinemotion/core/formatting.py,sha256=G_3eqgOtym9RFOZVEwCxye4A2cyrmgvtQ214vIshowU,2480
21
- kinemotion/core/metadata.py,sha256=bJAVa4nym__zx1hNowSZduMGKBSGOPxTbBQkjm6N0D0,7207
22
- kinemotion/core/model_downloader.py,sha256=mqhJBHGaNe0aN9qbcBqvcTk9FDd7xaHqEcwD-fyP89c,5205
23
- kinemotion/core/pipeline_utils.py,sha256=B5jMXoiLaTh02uGA2MIe1uZLVSRGZ5nxbARuvdrjDrQ,15161
24
- kinemotion/core/pose.py,sha256=_qC4cbFD0Mp2JAGftZcY5AEDLgD2yRnTyRKD9bkqLI8,15306
25
- kinemotion/core/pose_landmarks.py,sha256=LcEbL5K5xKia6dCzWf6Ft18UIE1CLMMqCZ3KUjwUDzM,1558
26
- kinemotion/core/quality.py,sha256=VUkRL2N6B7lfIZ2pE9han_U68JwarmZz1U0ygHkgkhE,13022
27
- kinemotion/core/smoothing.py,sha256=ELMHL7pzSqYffjnLDBUMBJIgt1AwOssDInE8IiXBbig,15942
28
- kinemotion/core/timing.py,sha256=ITX77q4hbtajRuWfgwYhws8nCvOeKFlEdKjCu8lD9_w,7938
29
- kinemotion/core/types.py,sha256=A_HclzKpf3By5DiJ0wY9B-dQJrIVAAhUfGab7qTSIL8,1279
30
- kinemotion/core/validation.py,sha256=0xVv-ftWveV60fJ97kmZMuy2Qqqb5aZLR50dDIrjnhg,6773
31
- kinemotion/core/video_io.py,sha256=TxdLUEpekGytesL3X3k78WWgZTOd5fuge30hU4Uy48Y,9198
32
- kinemotion/dropjump/__init__.py,sha256=tC3H3BrCg8Oj-db-Vrtx4PH_llR1Ppkd5jwaOjhQcLg,862
33
- kinemotion/dropjump/analysis.py,sha256=YomuoJF_peyrBSpeT89Q5_sBgY0kEDyq7TFrtEnRLjs,28049
34
- kinemotion/dropjump/api.py,sha256=QlZxCrjOg78PXXip6Krb91RSYqH37x1AbBUy6U8uFt8,20833
35
- kinemotion/dropjump/cli.py,sha256=gUef9nmyR5952h1WnfBGyCdFXQvzVTlCKYAjJGcO4sE,16819
36
- kinemotion/dropjump/debug_overlay.py,sha256=9RQYXPRf0q2wdy6y2Ak2R4tpRceDwC8aJrXZzkmh3Wo,5942
37
- kinemotion/dropjump/kinematics.py,sha256=dx4PuXKfKMKcsc_HX6sXj8rHXf9ksiZIOAIkJ4vBlY4,19637
38
- kinemotion/dropjump/metrics_validator.py,sha256=lSfo4Lm5FHccl8ijUP6SA-kcSh50LS9hF8UIyWxcnW8,9243
39
- kinemotion/dropjump/validation_bounds.py,sha256=x4yjcFxyvdMp5e7MkcoUosGLeGsxBh1Lft6h__AQ2G8,5124
40
- kinemotion/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- kinemotion/models/pose_landmarker_lite.task,sha256=WZKeHR7pUodzXd2DOxnPSsRtKbx6_du_Z1PEWWkNV0o,5777746
42
- kinemotion/models/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.onnx,sha256=dfZTq8kbhv8RxWiXS0HUIJNCUpxYTBN45dFIorPflEs,133
43
- kinemotion/models/yolox_tiny_8xb8-300e_humanart-6f3252f9.onnx,sha256=UsutHVQ6GP3X5pCcp52EN8q7o2J3d-TnxZqlF48kY6I,133
44
- kinemotion/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- kinemotion-0.71.0.dist-info/METADATA,sha256=sKhmkomkzrmp1YnX0SC9dzsRvDNlrVtVQ5npxSPWVeI,26125
46
- kinemotion-0.71.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
47
- kinemotion-0.71.0.dist-info/entry_points.txt,sha256=zaqnAnjLvcdrk1Qvj5nvXZCZ2gp0prS7it1zTJygcIY,50
48
- kinemotion-0.71.0.dist-info/licenses/LICENSE,sha256=KZajvqsHw0NoOHOi2q0FZ4NBe9HdV6oey-IPYAtHXfg,1088
49
- kinemotion-0.71.0.dist-info/RECORD,,