kinemotion 0.70.0__py3-none-any.whl → 0.71.0__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.
Potentially problematic release.
This version of kinemotion might be problematic. Click here for more details.
- kinemotion/__init__.py +4 -1
- kinemotion/cmj/analysis.py +77 -26
- kinemotion/cmj/api.py +7 -32
- kinemotion/cmj/cli.py +0 -21
- kinemotion/cmj/metrics_validator.py +8 -22
- kinemotion/core/pose.py +29 -400
- kinemotion/dropjump/api.py +7 -27
- kinemotion/dropjump/cli.py +1 -27
- kinemotion/models/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.onnx +0 -0
- kinemotion/models/yolox_tiny_8xb8-300e_humanart-6f3252f9.onnx +0 -0
- {kinemotion-0.70.0.dist-info → kinemotion-0.71.0.dist-info}/METADATA +1 -4
- {kinemotion-0.70.0.dist-info → kinemotion-0.71.0.dist-info}/RECORD +15 -17
- kinemotion/core/rtmpose_cpu.py +0 -626
- kinemotion/core/rtmpose_wrapper.py +0 -190
- {kinemotion-0.70.0.dist-info → kinemotion-0.71.0.dist-info}/WHEEL +0 -0
- {kinemotion-0.70.0.dist-info → kinemotion-0.71.0.dist-info}/entry_points.txt +0 -0
- {kinemotion-0.70.0.dist-info → kinemotion-0.71.0.dist-info}/licenses/LICENSE +0 -0
kinemotion/core/pose.py
CHANGED
|
@@ -18,6 +18,8 @@ Configuration strategies for matching Solution API behavior:
|
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
21
23
|
import cv2
|
|
22
24
|
import mediapipe as mp
|
|
23
25
|
import numpy as np
|
|
@@ -159,358 +161,51 @@ class MediaPipePoseTracker:
|
|
|
159
161
|
|
|
160
162
|
|
|
161
163
|
class PoseTrackerFactory:
|
|
162
|
-
"""Factory for creating pose trackers
|
|
164
|
+
"""Factory for creating pose trackers.
|
|
163
165
|
|
|
164
|
-
|
|
165
|
-
- RTMPose CUDA: NVIDIA GPU acceleration (fastest, 133 FPS)
|
|
166
|
-
- RTMPose CoreML: Apple Silicon acceleration (42 FPS)
|
|
167
|
-
- RTMPose CPU: Optimized CPU implementation (40-68 FPS)
|
|
168
|
-
- MediaPipe: Fallback baseline (48 FPS)
|
|
166
|
+
Currently supports MediaPipe as the only backend.
|
|
169
167
|
|
|
170
168
|
Usage:
|
|
171
|
-
# Auto-detect best backend
|
|
172
169
|
tracker = PoseTrackerFactory.create()
|
|
173
|
-
|
|
174
|
-
# Force specific backend
|
|
175
|
-
tracker = PoseTrackerFactory.create(backend='rtmpose-cuda')
|
|
176
|
-
|
|
177
|
-
# Check available backends
|
|
178
|
-
available = PoseTrackerFactory.get_available_backends()
|
|
179
170
|
"""
|
|
180
171
|
|
|
181
|
-
# Backend class mappings
|
|
182
|
-
_BACKENDS: dict[str, type] = {}
|
|
183
|
-
|
|
184
172
|
@classmethod
|
|
185
173
|
def create(
|
|
186
174
|
cls,
|
|
187
|
-
backend: str = "
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
"""Create a pose tracker with the specified backend.
|
|
192
|
-
|
|
193
|
-
Args:
|
|
194
|
-
backend: Backend selection:
|
|
195
|
-
- 'auto': Auto-detect best available backend
|
|
196
|
-
- 'mediapipe': MediaPipe Tasks API (baseline)
|
|
197
|
-
- 'rtmpose-cpu': RTMPose optimized CPU
|
|
198
|
-
- 'rtmpose-cuda': RTMPose with CUDA (NVIDIA GPU)
|
|
199
|
-
- 'rtmpose-coreml': RTMPose with CoreML (Apple Silicon)
|
|
200
|
-
mode: RTMPose performance mode ('lightweight', 'balanced', 'performance')
|
|
201
|
-
Only used for RTMPose backends
|
|
202
|
-
**kwargs: Additional arguments passed to tracker constructor
|
|
203
|
-
|
|
204
|
-
Returns:
|
|
205
|
-
Configured pose tracker instance
|
|
206
|
-
|
|
207
|
-
Raises:
|
|
208
|
-
ValueError: If backend is not available or recognized
|
|
209
|
-
"""
|
|
210
|
-
# Auto-detect backend
|
|
211
|
-
if backend == "auto":
|
|
212
|
-
backend = cls._detect_best_backend()
|
|
213
|
-
backend = cls._check_backend_available(backend)
|
|
214
|
-
|
|
215
|
-
# Check environment variable override
|
|
216
|
-
import os
|
|
217
|
-
|
|
218
|
-
env_backend = os.environ.get("POSE_TRACKER_BACKEND")
|
|
219
|
-
if env_backend:
|
|
220
|
-
backend = cls._normalize_backend_name(env_backend)
|
|
221
|
-
|
|
222
|
-
# Verify backend is available
|
|
223
|
-
backend = cls._check_backend_available(backend)
|
|
224
|
-
|
|
225
|
-
# Get tracker class
|
|
226
|
-
tracker_class = cls._get_tracker_class(backend)
|
|
227
|
-
|
|
228
|
-
# Create tracker with appropriate arguments
|
|
229
|
-
return cls._create_tracker(tracker_class, backend, mode, kwargs)
|
|
230
|
-
|
|
231
|
-
@classmethod
|
|
232
|
-
def _detect_best_backend(cls) -> str:
|
|
233
|
-
"""Detect the best available backend.
|
|
234
|
-
|
|
235
|
-
Priority order:
|
|
236
|
-
1. CUDA (NVIDIA GPU) - fastest
|
|
237
|
-
2. CoreML (Apple Silicon) - good performance
|
|
238
|
-
3. RTMPose CPU - optimized CPU
|
|
239
|
-
4. MediaPipe - baseline fallback
|
|
240
|
-
|
|
241
|
-
Returns:
|
|
242
|
-
Backend name string
|
|
243
|
-
"""
|
|
244
|
-
# Check for CUDA (NVIDIA GPU)
|
|
245
|
-
try:
|
|
246
|
-
import torch
|
|
247
|
-
|
|
248
|
-
if torch.cuda.is_available():
|
|
249
|
-
return "rtmpose-cuda"
|
|
250
|
-
except ImportError:
|
|
251
|
-
pass
|
|
252
|
-
|
|
253
|
-
# Check for CoreML (Apple Silicon)
|
|
254
|
-
import sys
|
|
255
|
-
|
|
256
|
-
if sys.platform == "darwin":
|
|
257
|
-
return "rtmpose-coreml"
|
|
258
|
-
|
|
259
|
-
# Check for RTMPose CPU
|
|
260
|
-
try:
|
|
261
|
-
from kinemotion.core.rtmpose_cpu import (
|
|
262
|
-
OptimizedCPUTracker as _RTMPoseCPU, # type: ignore
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
_ = _RTMPoseCPU # Mark as intentionally used for availability check
|
|
266
|
-
|
|
267
|
-
return "rtmpose-cpu"
|
|
268
|
-
except ImportError:
|
|
269
|
-
pass
|
|
270
|
-
|
|
271
|
-
# Fallback to MediaPipe
|
|
272
|
-
return "mediapipe"
|
|
273
|
-
|
|
274
|
-
@classmethod
|
|
275
|
-
def _check_backend_available(cls, backend: str) -> str:
|
|
276
|
-
"""Check if a backend is available and return a fallback if not.
|
|
277
|
-
|
|
278
|
-
Args:
|
|
279
|
-
backend: Requested backend name
|
|
280
|
-
|
|
281
|
-
Returns:
|
|
282
|
-
Available backend name (may be different from requested)
|
|
283
|
-
|
|
284
|
-
Raises:
|
|
285
|
-
ValueError: If no backend is available
|
|
286
|
-
"""
|
|
287
|
-
normalized = cls._normalize_backend_name(backend)
|
|
288
|
-
|
|
289
|
-
# Check if specific backend can be imported
|
|
290
|
-
if normalized == "rtmpose-cuda":
|
|
291
|
-
try:
|
|
292
|
-
import torch # noqa: F401
|
|
293
|
-
|
|
294
|
-
if not torch.cuda.is_available():
|
|
295
|
-
# CUDA not available, fall back to CPU
|
|
296
|
-
return cls._check_backend_available("rtmpose-cpu")
|
|
297
|
-
# CUDA is available, use rtmpose-cuda
|
|
298
|
-
return normalized
|
|
299
|
-
except ImportError:
|
|
300
|
-
return cls._check_backend_available("rtmpose-cpu")
|
|
301
|
-
|
|
302
|
-
if normalized == "rtmpose-coreml":
|
|
303
|
-
import sys
|
|
304
|
-
|
|
305
|
-
if sys.platform != "darwin":
|
|
306
|
-
# Not macOS, fall back to CPU
|
|
307
|
-
return cls._check_backend_available("rtmpose-cpu")
|
|
308
|
-
|
|
309
|
-
if normalized == "rtmpose-cpu":
|
|
310
|
-
try:
|
|
311
|
-
from kinemotion.core.rtmpose_cpu import (
|
|
312
|
-
OptimizedCPUTracker as _RTMPoseCPU,
|
|
313
|
-
) # type: ignore
|
|
314
|
-
|
|
315
|
-
_ = _RTMPoseCPU # Mark as intentionally used for availability check
|
|
316
|
-
|
|
317
|
-
return normalized
|
|
318
|
-
except ImportError:
|
|
319
|
-
# RTMPose not available, fall back to MediaPipe
|
|
320
|
-
return "mediapipe"
|
|
321
|
-
|
|
322
|
-
if normalized == "mediapipe":
|
|
323
|
-
try:
|
|
324
|
-
import mediapipe as _mp # noqa: F401
|
|
325
|
-
|
|
326
|
-
_ = _mp # Mark as intentionally used for availability check
|
|
327
|
-
return normalized
|
|
328
|
-
except ImportError as err:
|
|
329
|
-
raise ValueError(
|
|
330
|
-
"No pose tracking backend available. Please install mediapipe or rtmlib."
|
|
331
|
-
) from err
|
|
332
|
-
|
|
333
|
-
raise ValueError(f"Unknown backend: {backend}")
|
|
334
|
-
|
|
335
|
-
@classmethod
|
|
336
|
-
def _normalize_backend_name(cls, backend: str) -> str:
|
|
337
|
-
"""Normalize backend name to canonical form.
|
|
338
|
-
|
|
339
|
-
Args:
|
|
340
|
-
backend: User-provided backend name
|
|
341
|
-
|
|
342
|
-
Returns:
|
|
343
|
-
Canonical backend name
|
|
344
|
-
"""
|
|
345
|
-
# Normalize various aliases to canonical names
|
|
346
|
-
aliases = {
|
|
347
|
-
"mp": "mediapipe",
|
|
348
|
-
"mediapipe": "mediapipe",
|
|
349
|
-
"rtmpose": "rtmpose-cpu",
|
|
350
|
-
"rtmpose-cpu": "rtmpose-cpu",
|
|
351
|
-
"rtmpose_cpu": "rtmpose-cpu",
|
|
352
|
-
"cpu": "rtmpose-cpu",
|
|
353
|
-
"cuda": "rtmpose-cuda",
|
|
354
|
-
"rtmpose-cuda": "rtmpose-cuda",
|
|
355
|
-
"rtmpose_cuda": "rtmpose-cuda",
|
|
356
|
-
"gpu": "rtmpose-cuda",
|
|
357
|
-
"mps": "rtmpose-coreml",
|
|
358
|
-
"coreml": "rtmpose-coreml",
|
|
359
|
-
"rtmpose-coreml": "rtmpose-coreml",
|
|
360
|
-
"rtmpose_coreml": "rtmpose-coreml",
|
|
361
|
-
}
|
|
362
|
-
return aliases.get(backend.lower(), backend)
|
|
363
|
-
|
|
364
|
-
@classmethod
|
|
365
|
-
def _get_tracker_class(cls, backend: str):
|
|
366
|
-
"""Get the tracker class for a backend.
|
|
175
|
+
backend: str = "mediapipe",
|
|
176
|
+
**kwargs: Any,
|
|
177
|
+
) -> MediaPipePoseTracker:
|
|
178
|
+
"""Create a MediaPipe pose tracker.
|
|
367
179
|
|
|
368
180
|
Args:
|
|
369
|
-
backend:
|
|
181
|
+
backend: Backend selection (only 'mediapipe' supported)
|
|
182
|
+
**kwargs: Arguments passed to MediaPipePoseTracker
|
|
370
183
|
|
|
371
184
|
Returns:
|
|
372
|
-
|
|
185
|
+
Configured MediaPipePoseTracker instance
|
|
373
186
|
|
|
374
187
|
Raises:
|
|
375
|
-
ValueError: If backend is not
|
|
188
|
+
ValueError: If backend is not 'mediapipe'
|
|
376
189
|
"""
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
try:
|
|
382
|
-
from kinemotion.core.rtmpose_cpu import OptimizedCPUTracker
|
|
383
|
-
|
|
384
|
-
return OptimizedCPUTracker
|
|
385
|
-
except ImportError as e:
|
|
386
|
-
raise ValueError(f"RTMPose CPU backend requested but not available: {e}") from e
|
|
190
|
+
# Normalize and validate backend
|
|
191
|
+
normalized = backend.lower()
|
|
192
|
+
if normalized not in ("mediapipe", "mp", "auto"):
|
|
193
|
+
raise ValueError(f"Unknown backend: {backend}. Only 'mediapipe' is supported.")
|
|
387
194
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
195
|
+
# Filter out any legacy kwargs that don't apply to MediaPipe
|
|
196
|
+
legacy_keys = {"mode", "backend", "device", "pose_input_size"}
|
|
197
|
+
filtered_kwargs = {k: v for k, v in kwargs.items() if k not in legacy_keys}
|
|
391
198
|
|
|
392
|
-
|
|
393
|
-
except ImportError as e:
|
|
394
|
-
raise ValueError(
|
|
395
|
-
f"RTMPose wrapper backend requested but not available: {e}"
|
|
396
|
-
) from e
|
|
397
|
-
|
|
398
|
-
raise ValueError(f"Unknown backend: {backend}")
|
|
399
|
-
|
|
400
|
-
@classmethod
|
|
401
|
-
def _create_tracker(
|
|
402
|
-
cls,
|
|
403
|
-
tracker_class: type,
|
|
404
|
-
backend: str,
|
|
405
|
-
mode: str,
|
|
406
|
-
kwargs: dict[str, object],
|
|
407
|
-
) -> object:
|
|
408
|
-
"""Create a tracker instance with appropriate arguments.
|
|
409
|
-
|
|
410
|
-
Args:
|
|
411
|
-
tracker_class: Tracker class to instantiate
|
|
412
|
-
backend: Backend name (for parameter mapping)
|
|
413
|
-
mode: RTMPose mode (only used for RTMPose backends)
|
|
414
|
-
kwargs: Additional arguments from user
|
|
415
|
-
|
|
416
|
-
Returns:
|
|
417
|
-
Tracker instance
|
|
418
|
-
"""
|
|
419
|
-
# MediaPipe-specific arguments
|
|
420
|
-
if backend == "mediapipe":
|
|
421
|
-
# Remove RTMPose-specific arguments
|
|
422
|
-
rttmpose_keys = {"mode", "backend", "device", "pose_input_size"}
|
|
423
|
-
filtered_kwargs = {k: v for k, v in kwargs.items() if k not in rttmpose_keys}
|
|
424
|
-
return tracker_class(**filtered_kwargs)
|
|
425
|
-
|
|
426
|
-
# OptimizedCPUTracker (CPU-only, doesn't accept device parameter)
|
|
427
|
-
if backend == "rtmpose-cpu":
|
|
428
|
-
# Remove RTMPoseWrapper-specific and MediaPipe-specific arguments
|
|
429
|
-
unsupported_keys = {
|
|
430
|
-
"backend",
|
|
431
|
-
"device",
|
|
432
|
-
"min_detection_confidence",
|
|
433
|
-
"min_tracking_confidence",
|
|
434
|
-
}
|
|
435
|
-
filtered_kwargs = {k: v for k, v in kwargs.items() if k not in unsupported_keys}
|
|
436
|
-
filtered_kwargs.setdefault("mode", mode)
|
|
437
|
-
return tracker_class(**filtered_kwargs)
|
|
438
|
-
|
|
439
|
-
# RTMPoseWrapper (CUDA/CoreML, requires device parameter)
|
|
440
|
-
# Remove MediaPipe-specific arguments
|
|
441
|
-
mediapipe_keys = {"min_detection_confidence", "min_tracking_confidence"}
|
|
442
|
-
filtered_kwargs = {k: v for k, v in kwargs.items() if k not in mediapipe_keys}
|
|
443
|
-
|
|
444
|
-
device = backend.split("-")[-1] # Extract 'cuda', 'cpu', 'coreml'
|
|
445
|
-
if device == "coreml":
|
|
446
|
-
device = "mps" # RTMLib uses 'mps' for Apple Silicon
|
|
447
|
-
|
|
448
|
-
filtered_kwargs.setdefault("device", device)
|
|
449
|
-
filtered_kwargs.setdefault("mode", mode)
|
|
450
|
-
|
|
451
|
-
return tracker_class(**filtered_kwargs)
|
|
199
|
+
return MediaPipePoseTracker(**filtered_kwargs)
|
|
452
200
|
|
|
453
201
|
@classmethod
|
|
454
202
|
def get_available_backends(cls) -> list[str]:
|
|
455
|
-
"""Get list of available backends
|
|
203
|
+
"""Get list of available backends.
|
|
456
204
|
|
|
457
205
|
Returns:
|
|
458
|
-
List
|
|
206
|
+
List containing 'mediapipe'
|
|
459
207
|
"""
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
# Always have MediaPipe as fallback
|
|
463
|
-
try:
|
|
464
|
-
import mediapipe as _mp # noqa: F401
|
|
465
|
-
|
|
466
|
-
_ = _mp # Mark as intentionally used for availability check
|
|
467
|
-
available.append("mediapipe")
|
|
468
|
-
except ImportError:
|
|
469
|
-
pass
|
|
470
|
-
|
|
471
|
-
# Check RTMPose CPU
|
|
472
|
-
try:
|
|
473
|
-
from kinemotion.core.rtmpose_cpu import (
|
|
474
|
-
OptimizedCPUTracker as _RTMPoseCPU,
|
|
475
|
-
) # type: ignore
|
|
476
|
-
|
|
477
|
-
_ = _RTMPoseCPU # Mark as intentionally used for availability check
|
|
478
|
-
|
|
479
|
-
available.append("rtmpose-cpu")
|
|
480
|
-
except ImportError:
|
|
481
|
-
pass
|
|
482
|
-
|
|
483
|
-
# Check CUDA
|
|
484
|
-
try:
|
|
485
|
-
import torch
|
|
486
|
-
|
|
487
|
-
if torch.cuda.is_available():
|
|
488
|
-
from kinemotion.core.rtmpose_wrapper import (
|
|
489
|
-
RTMPoseWrapper as _RTMPoseWrapper,
|
|
490
|
-
) # type: ignore
|
|
491
|
-
|
|
492
|
-
_ = _RTMPoseWrapper # Mark as intentionally used for availability check
|
|
493
|
-
|
|
494
|
-
available.append("rtmpose-cuda")
|
|
495
|
-
except ImportError:
|
|
496
|
-
pass
|
|
497
|
-
|
|
498
|
-
# Check CoreML (Apple Silicon)
|
|
499
|
-
import sys
|
|
500
|
-
|
|
501
|
-
if sys.platform == "darwin":
|
|
502
|
-
try:
|
|
503
|
-
from kinemotion.core.rtmpose_wrapper import (
|
|
504
|
-
RTMPoseWrapper as _RTMPoseWrapperMPS,
|
|
505
|
-
) # type: ignore
|
|
506
|
-
|
|
507
|
-
_ = _RTMPoseWrapperMPS # Mark as intentionally used for availability check
|
|
508
|
-
|
|
509
|
-
available.append("rtmpose-coreml")
|
|
510
|
-
except ImportError:
|
|
511
|
-
pass
|
|
512
|
-
|
|
513
|
-
return available
|
|
208
|
+
return ["mediapipe"]
|
|
514
209
|
|
|
515
210
|
@classmethod
|
|
516
211
|
def get_backend_info(cls, backend: str) -> dict[str, str]:
|
|
@@ -522,39 +217,15 @@ class PoseTrackerFactory:
|
|
|
522
217
|
Returns:
|
|
523
218
|
Dictionary with backend information
|
|
524
219
|
"""
|
|
525
|
-
|
|
526
|
-
|
|
220
|
+
if backend.lower() in ("mediapipe", "mp"):
|
|
221
|
+
return {
|
|
527
222
|
"name": "MediaPipe",
|
|
528
|
-
"description": "
|
|
223
|
+
"description": "Pose tracking using MediaPipe Tasks API",
|
|
529
224
|
"performance": "~48 FPS",
|
|
530
|
-
"accuracy": "
|
|
225
|
+
"accuracy": "Reference (validated for jumps)",
|
|
531
226
|
"requirements": "mediapipe package",
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
"name": "RTMPose CPU",
|
|
535
|
-
"description": "Optimized CPU implementation with ONNX Runtime",
|
|
536
|
-
"performance": "~40-68 FPS (134% of MediaPipe)",
|
|
537
|
-
"accuracy": "9-12px mean difference (1-5% metric accuracy)",
|
|
538
|
-
"requirements": "rtmlib package",
|
|
539
|
-
},
|
|
540
|
-
"rtmpose-cuda": {
|
|
541
|
-
"name": "RTMPose CUDA",
|
|
542
|
-
"description": "NVIDIA GPU acceleration with CUDA",
|
|
543
|
-
"performance": "~133 FPS (271% of MediaPipe)",
|
|
544
|
-
"accuracy": "9-12px mean difference (1-5% metric accuracy)",
|
|
545
|
-
"requirements": "rtmlib + CUDA-capable GPU",
|
|
546
|
-
},
|
|
547
|
-
"rtmpose-coreml": {
|
|
548
|
-
"name": "RTMPose CoreML",
|
|
549
|
-
"description": "Apple Silicon acceleration with CoreML",
|
|
550
|
-
"performance": "~42 FPS (94% of MediaPipe)",
|
|
551
|
-
"accuracy": "9-12px mean difference (1-5% metric accuracy)",
|
|
552
|
-
"requirements": "rtmlib + Apple Silicon",
|
|
553
|
-
},
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
normalized = cls._normalize_backend_name(backend)
|
|
557
|
-
return info.get(normalized, {})
|
|
227
|
+
}
|
|
228
|
+
return {}
|
|
558
229
|
|
|
559
230
|
|
|
560
231
|
def get_tracker_info(tracker: object) -> str:
|
|
@@ -571,50 +242,8 @@ def get_tracker_info(tracker: object) -> str:
|
|
|
571
242
|
|
|
572
243
|
info = f"{tracker_class} (from {module})"
|
|
573
244
|
|
|
574
|
-
# Add backend-specific details
|
|
575
245
|
if tracker_class == "MediaPipePoseTracker":
|
|
576
246
|
info += " [MediaPipe Tasks API]"
|
|
577
|
-
elif tracker_class == "OptimizedCPUTracker":
|
|
578
|
-
# Check if ONNX Runtime has CUDA
|
|
579
|
-
try:
|
|
580
|
-
import onnxruntime as ort
|
|
581
|
-
|
|
582
|
-
providers = ort.get_available_providers()
|
|
583
|
-
if "CUDAExecutionProvider" in providers:
|
|
584
|
-
# Check what providers the session is actually using
|
|
585
|
-
det_session = getattr(tracker, "det_session", None)
|
|
586
|
-
if det_session is not None:
|
|
587
|
-
active_providers = det_session.get_providers()
|
|
588
|
-
if "CUDAExecutionProvider" in active_providers:
|
|
589
|
-
info += " [ONNX Runtime: CUDA]"
|
|
590
|
-
else:
|
|
591
|
-
info += " [ONNX Runtime: CPU]"
|
|
592
|
-
else:
|
|
593
|
-
info += " [ONNX Runtime]"
|
|
594
|
-
else:
|
|
595
|
-
info += " [ONNX Runtime: CPU]"
|
|
596
|
-
except ImportError:
|
|
597
|
-
info += " [ONNX Runtime]"
|
|
598
|
-
elif tracker_class == "RTMPoseWrapper":
|
|
599
|
-
device = getattr(tracker, "device", None)
|
|
600
|
-
if device:
|
|
601
|
-
if device == "cuda":
|
|
602
|
-
try:
|
|
603
|
-
import torch
|
|
604
|
-
|
|
605
|
-
if torch.cuda.is_available():
|
|
606
|
-
device_name = torch.cuda.get_device_name(0)
|
|
607
|
-
info += f" [PyTorch CUDA: {device_name}]"
|
|
608
|
-
else:
|
|
609
|
-
info += " [PyTorch: CPU fallback]"
|
|
610
|
-
except ImportError:
|
|
611
|
-
info += " [PyTorch CUDA]"
|
|
612
|
-
elif device == "mps":
|
|
613
|
-
info += " [PyTorch: Apple Silicon GPU]"
|
|
614
|
-
else:
|
|
615
|
-
info += f" [PyTorch: {device}]"
|
|
616
|
-
else:
|
|
617
|
-
info += " [PyTorch]"
|
|
618
247
|
|
|
619
248
|
return info
|
|
620
249
|
|
kinemotion/dropjump/api.py
CHANGED
|
@@ -90,7 +90,6 @@ class DropJumpVideoConfig:
|
|
|
90
90
|
overrides: AnalysisOverrides | None = None
|
|
91
91
|
detection_confidence: float | None = None
|
|
92
92
|
tracking_confidence: float | None = None
|
|
93
|
-
pose_backend: str | None = None
|
|
94
93
|
|
|
95
94
|
|
|
96
95
|
def _assess_dropjump_quality(
|
|
@@ -237,7 +236,6 @@ def _setup_pose_tracker(
|
|
|
237
236
|
detection_confidence: float | None,
|
|
238
237
|
tracking_confidence: float | None,
|
|
239
238
|
pose_tracker: "MediaPipePoseTracker | None",
|
|
240
|
-
pose_backend: str | None,
|
|
241
239
|
timer: Timer,
|
|
242
240
|
verbose: bool = False,
|
|
243
241
|
) -> tuple["MediaPipePoseTracker", bool]:
|
|
@@ -250,29 +248,13 @@ def _setup_pose_tracker(
|
|
|
250
248
|
should_close_tracker = False
|
|
251
249
|
|
|
252
250
|
if tracker is None:
|
|
253
|
-
if
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
tracker = PoseTrackerFactory.create(
|
|
261
|
-
backend=pose_backend,
|
|
262
|
-
timer=timer,
|
|
263
|
-
)
|
|
264
|
-
init_time = time.perf_counter() - init_start
|
|
265
|
-
|
|
266
|
-
if verbose:
|
|
267
|
-
print(f"Using pose backend: {pose_backend}")
|
|
268
|
-
print(f" → {get_tracker_info(tracker)}")
|
|
269
|
-
print(f" → Initialized in {init_time * 1000:.1f} ms")
|
|
270
|
-
else:
|
|
271
|
-
tracker = MediaPipePoseTracker(
|
|
272
|
-
min_detection_confidence=detection_conf,
|
|
273
|
-
min_tracking_confidence=tracking_conf,
|
|
274
|
-
timer=timer,
|
|
275
|
-
)
|
|
251
|
+
if verbose:
|
|
252
|
+
print("Processing all frames with MediaPipe pose tracking...")
|
|
253
|
+
tracker = MediaPipePoseTracker(
|
|
254
|
+
min_detection_confidence=detection_conf,
|
|
255
|
+
min_tracking_confidence=tracking_conf,
|
|
256
|
+
timer=timer,
|
|
257
|
+
)
|
|
276
258
|
should_close_tracker = True
|
|
277
259
|
|
|
278
260
|
return tracker, should_close_tracker
|
|
@@ -509,7 +491,6 @@ def process_dropjump_video(
|
|
|
509
491
|
verbose: bool = False,
|
|
510
492
|
timer: Timer | None = None,
|
|
511
493
|
pose_tracker: "MediaPipePoseTracker | None" = None,
|
|
512
|
-
pose_backend: str | None = None,
|
|
513
494
|
) -> DropJumpMetrics:
|
|
514
495
|
"""
|
|
515
496
|
Process a single drop jump video and return metrics.
|
|
@@ -554,7 +535,6 @@ def process_dropjump_video(
|
|
|
554
535
|
detection_confidence,
|
|
555
536
|
tracking_confidence,
|
|
556
537
|
pose_tracker,
|
|
557
|
-
pose_backend,
|
|
558
538
|
timer,
|
|
559
539
|
verbose,
|
|
560
540
|
)
|
kinemotion/dropjump/cli.py
CHANGED
|
@@ -31,7 +31,6 @@ class AnalysisParameters:
|
|
|
31
31
|
visibility_threshold: float | None = None
|
|
32
32
|
detection_confidence: float | None = None
|
|
33
33
|
tracking_confidence: float | None = None
|
|
34
|
-
pose_backend: str | None = None
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
@click.command(name="dropjump-analyze")
|
|
@@ -66,23 +65,6 @@ class AnalysisParameters:
|
|
|
66
65
|
is_flag=True,
|
|
67
66
|
help="Show auto-selected parameters and analysis details",
|
|
68
67
|
)
|
|
69
|
-
@click.option(
|
|
70
|
-
"--pose-backend",
|
|
71
|
-
type=click.Choice(
|
|
72
|
-
["auto", "mediapipe", "rtmpose-cpu", "rtmpose-cuda", "rtmpose-coreml"],
|
|
73
|
-
case_sensitive=False,
|
|
74
|
-
),
|
|
75
|
-
default="auto",
|
|
76
|
-
help=(
|
|
77
|
-
"Pose tracking backend: "
|
|
78
|
-
"auto (detect best), "
|
|
79
|
-
"mediapipe (baseline), "
|
|
80
|
-
"rtmpose-cpu (optimized CPU), "
|
|
81
|
-
"rtmpose-cuda (NVIDIA GPU), "
|
|
82
|
-
"rtmpose-coreml (Apple Silicon)"
|
|
83
|
-
),
|
|
84
|
-
show_default=True,
|
|
85
|
-
)
|
|
86
68
|
# Batch processing options
|
|
87
69
|
@click.option(
|
|
88
70
|
"--batch",
|
|
@@ -161,7 +143,6 @@ def dropjump_analyze( # NOSONAR(S107) - Click CLI requires individual
|
|
|
161
143
|
json_output: str | None,
|
|
162
144
|
quality: str,
|
|
163
145
|
verbose: bool,
|
|
164
|
-
pose_backend: str,
|
|
165
146
|
batch: bool,
|
|
166
147
|
workers: int,
|
|
167
148
|
output_dir: str | None,
|
|
@@ -231,7 +212,6 @@ def dropjump_analyze( # NOSONAR(S107) - Click CLI requires individual
|
|
|
231
212
|
json_output_dir,
|
|
232
213
|
csv_summary,
|
|
233
214
|
expert_params,
|
|
234
|
-
pose_backend,
|
|
235
215
|
)
|
|
236
216
|
else:
|
|
237
217
|
# Single video mode (original behavior)
|
|
@@ -242,7 +222,6 @@ def dropjump_analyze( # NOSONAR(S107) - Click CLI requires individual
|
|
|
242
222
|
quality,
|
|
243
223
|
verbose,
|
|
244
224
|
expert_params,
|
|
245
|
-
pose_backend,
|
|
246
225
|
)
|
|
247
226
|
|
|
248
227
|
|
|
@@ -253,7 +232,6 @@ def _process_single(
|
|
|
253
232
|
quality: str,
|
|
254
233
|
verbose: bool,
|
|
255
234
|
expert_params: AnalysisParameters,
|
|
256
|
-
pose_backend: str,
|
|
257
235
|
) -> None:
|
|
258
236
|
"""Process a single video by calling the API."""
|
|
259
237
|
click.echo(f"Analyzing video: {video_path}", err=True)
|
|
@@ -288,7 +266,6 @@ def _process_single(
|
|
|
288
266
|
overrides=overrides,
|
|
289
267
|
detection_confidence=expert_params.detection_confidence,
|
|
290
268
|
tracking_confidence=expert_params.tracking_confidence,
|
|
291
|
-
pose_backend=pose_backend,
|
|
292
269
|
verbose=verbose,
|
|
293
270
|
)
|
|
294
271
|
|
|
@@ -332,7 +309,6 @@ def _create_video_configs(
|
|
|
332
309
|
output_dir: str | None,
|
|
333
310
|
json_output_dir: str | None,
|
|
334
311
|
expert_params: AnalysisParameters,
|
|
335
|
-
pose_backend: str,
|
|
336
312
|
) -> list[DropJumpVideoConfig]:
|
|
337
313
|
"""Build configuration objects for each video.
|
|
338
314
|
|
|
@@ -380,7 +356,6 @@ def _create_video_configs(
|
|
|
380
356
|
overrides=overrides,
|
|
381
357
|
detection_confidence=expert_params.detection_confidence,
|
|
382
358
|
tracking_confidence=expert_params.tracking_confidence,
|
|
383
|
-
pose_backend=expert_params.pose_backend,
|
|
384
359
|
)
|
|
385
360
|
configs.append(config)
|
|
386
361
|
|
|
@@ -545,7 +520,6 @@ def _process_batch(
|
|
|
545
520
|
json_output_dir: str | None,
|
|
546
521
|
csv_summary: str | None,
|
|
547
522
|
expert_params: AnalysisParameters,
|
|
548
|
-
pose_backend: str,
|
|
549
523
|
) -> None:
|
|
550
524
|
"""Process multiple videos in batch mode using parallel processing."""
|
|
551
525
|
click.echo(f"\nBatch processing {len(video_files)} videos with {workers} workers", err=True)
|
|
@@ -556,7 +530,7 @@ def _process_batch(
|
|
|
556
530
|
|
|
557
531
|
# Create video configurations
|
|
558
532
|
configs = _create_video_configs(
|
|
559
|
-
video_files, quality, output_dir, json_output_dir, expert_params
|
|
533
|
+
video_files, quality, output_dir, json_output_dir, expert_params
|
|
560
534
|
)
|
|
561
535
|
|
|
562
536
|
# Progress callback
|
kinemotion/models/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.onnx
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kinemotion
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.71.0
|
|
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
|
|
@@ -23,12 +23,9 @@ Requires-Python: <3.13,>=3.10
|
|
|
23
23
|
Requires-Dist: click>=8.1.7
|
|
24
24
|
Requires-Dist: mediapipe>=0.10.30
|
|
25
25
|
Requires-Dist: numpy>=1.26.0
|
|
26
|
-
Requires-Dist: onnxruntime-gpu>=1.23.2
|
|
27
26
|
Requires-Dist: opencv-python>=4.9.0
|
|
28
27
|
Requires-Dist: platformdirs>=4.0.0
|
|
29
|
-
Requires-Dist: rtmlib>=0.0.13
|
|
30
28
|
Requires-Dist: scipy>=1.11.0
|
|
31
|
-
Requires-Dist: torch>=2.0.0
|
|
32
29
|
Requires-Dist: tqdm>=4.67.1
|
|
33
30
|
Requires-Dist: typing-extensions>=4.15.0
|
|
34
31
|
Description-Content-Type: text/markdown
|