opensportslib 0.3.3.dev3__tar.gz → 0.3.4.dev1__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.
- {opensportslib-0.3.3.dev3/opensportslib.egg-info → opensportslib-0.3.4.dev1}/PKG-INFO +17 -1
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/README.md +16 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/base_task_model.py +1 -1
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/classification.py +8 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/localization.py +9 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/loader.py +5 -1
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/classification_trainer.py +1 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/load_annotations.py +47 -11
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/classification_dataset.py +13 -8
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/hf_json.py +7 -4
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/hf_tracking.py +77 -11
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/localization_dataset.py +22 -7
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/utils/tracking.py +61 -10
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/hf_transfer.py +45 -18
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/osl_json_to_parquet.py +45 -60
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/parquet_to_osl_json.py +22 -13
- opensportslib-0.3.4.dev1/opensportslib/tracking/__init__.py +5 -0
- opensportslib-0.3.4.dev1/opensportslib/tracking/native.py +252 -0
- opensportslib-0.3.4.dev1/opensportslib/tracking/tracab.py +391 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1/opensportslib.egg-info}/PKG-INFO +17 -1
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/SOURCES.txt +5 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/pyproject.toml +1 -1
- opensportslib-0.3.4.dev1/tests/helpers/tracab.py +47 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_remote_sessions.py +23 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_architecture.py +10 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_hf_json_tracking_spotting.py +24 -11
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_hf_tracking_dataset.py +71 -4
- opensportslib-0.3.4.dev1/tests/unit/data/test_tracking_tracab.py +258 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_conversion.py +26 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_hf_transfer.py +164 -1
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/LICENSE +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/LICENSE-COMMERCIAL +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/MANIFEST.in +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/examples/quickstart/basic_classification.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/examples/quickstart/basic_localization.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/examples/quickstart/basic_vqa.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/adaptation/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/adaptation/spotta.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/config.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/configuration.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/vqa.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/cli.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/default.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/video.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/default.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/default.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/e2e_spotta.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/h5_header_distance.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/tracking_action_spotting.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/video_dali.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/video_ocv.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/default.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen3_vl_native.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen_lora.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/xvars.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/accessors.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/conflicts.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/editable.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/migrate.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/migrations/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/rule_variants.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/runtime_adapter.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schema.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schemas/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/validate.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/calf.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/ce.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/combine.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/nll.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/optimizer/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/optimizer/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/sampler/weighted_sampler.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/scheduler/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/scheduler/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/localization_trainer.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/vqa_trainer.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/checkpoint.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/config.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/config_normalize.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/data.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/ddp.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/default_args.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/direct_video.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/hf_runtime.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/lightning.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/seed.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/video_processing.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/wandb.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/utils/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/utils/h5_tracking.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/vqa_dataset.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/classification.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/metrics/classification_metric.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/metrics/localization_metric.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/metrics/vqa_metric.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/backbones/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/contextaware.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/e2e.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/learnablepooling.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/qwen_vl_native.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/qwen_xvars.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/rule_based.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/tracking.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/vars.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/video.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/video_mae.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/heads/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/neck/builder.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/common.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/asformer.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/calf.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/gsm.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/gtad.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/tsm.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/litebase.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/modules.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/shift.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/utils.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/vqa_prompting.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/xvars_clip_index.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/remote_registry.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/setup/setup.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/_common.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/dependency_links.txt +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/entry_points.txt +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/requires.txt +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/top_level.txt +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/redact_test_stream.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/release_versions.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/run_h5_header_rule_inference.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/summarize_test_report.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/verify_release_manifests.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/write_release_manifest.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/setup.cfg +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/conftest.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/causal_lm.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/configs.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/pipeline_stubs.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/classification/test_pipeline.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/localization/test_pipeline.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/localization/test_spotta.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/vqa/test_pipeline.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/__init__.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/_release_common.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_00_environment.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_classification_release.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_localization_release.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_vqa_release.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_cli.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_config_utils.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_environment.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_package.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_public_apis.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_remote_registry.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_server_jobs.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_server_registry.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_server_startup_scripts.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_task_model_contract.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_vqa.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_editable.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_optional_hf.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_pretrained_merge.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_split_overrides.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_architecture.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_dependencies.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_package.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_release_versions.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_runner_contract.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_classification_trainer.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_hf_runtime.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_localization_hf_backend.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_training_components.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_video_processing.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_classification_paths.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_h5_tracking.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_hf_json_spotting.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_localization_dali.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_localization_intervals.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_osl_formats.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_classification_metrics.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_header_rule_spotter.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_header_skeleton_spotter.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_localization_metrics.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_temporal_shift.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_metrics.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_qwen_xvars.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_training_lora.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_extract_xvars_features.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_release_manifest.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_report_summary.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_setup.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_spotting_classification.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_sngar_spotting.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_soccernet_gar.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_soccernet_gar_vqa.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_xvars_indexes.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/extract_xvars_clip_features.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/sngar_dataset_card.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/sngar_events.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/spotting_to_classification.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/spotting_tracking_to_classification.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/verify_sngar_spotting.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/download_hf_repo.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/download_osl_hf.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/push_sngar_spotting.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/upload_osl_hf.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/train/train_config.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/training/classification.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/training/localization.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/training/vqa.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/upload/upload_model_hf.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/upload/upload_sngar_tracking_full.py +0 -0
- {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/upload/upload_sngar_videos.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensportslib
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4.dev1
|
|
4
4
|
Summary: OpenSportsLib is the professional library, designed for advanced video understanding in sports. It provides state-of-the-art tools for action recognition, spotting, retrieval, and captioning, making it ideal for researchers, analysts, and developers working with sports video data.
|
|
5
5
|
Author: Jeet Vora
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -199,6 +199,12 @@ and [VQA guide](docs/tools/vqa.md).
|
|
|
199
199
|
|
|
200
200
|
OpenSportsLib provides APIs and scripts for downloading and uploading OSL datasets with Hugging Face.
|
|
201
201
|
|
|
202
|
+
For `tracking_tracab`, both transfer formats include the original DAT and all
|
|
203
|
+
referenced metadata JSON/TF05/TF08 XML files. Uploads reject missing tracking
|
|
204
|
+
assets; full downloads validate completeness. Annotation-only downloads defer
|
|
205
|
+
assets until a sample/input download or missing-file hydration is requested.
|
|
206
|
+
See [TRACAB transfer behavior](docs/tracking_tracab.md#dataset-loading-and-persistence).
|
|
207
|
+
|
|
202
208
|
For SN-GAR classification and action-spotting configurations, setup, caching,
|
|
203
209
|
and training commands, see the [SN-GAR examples](examples/sngar/README.md).
|
|
204
210
|
|
|
@@ -330,3 +336,13 @@ For synchronized native-FPS GAR action clips and optional exact frame reproducti
|
|
|
330
336
|
|
|
331
337
|
For full-rate tracking clips with the same classification sample IDs, see the
|
|
332
338
|
[tracking conversion script](docs/tools/spotting-tracking-to-classification.md).
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
### Raw TRACAB tracking
|
|
342
|
+
|
|
343
|
+
`tracking_tracab` is supported by classification and localization tracking loaders
|
|
344
|
+
for local OSL JSON, Hugging Face JSON and indexed WebDataset sources. Set the
|
|
345
|
+
input modality to `tracking_tracab`; reference the original metadata JSON with
|
|
346
|
+
`metadata_path` and retain UTC period calibration and team codes in each input. `params.annotation_head` selects a head such as
|
|
347
|
+
`action` or `headers`. See [the DAT contract and loading guide](docs/tracking_tracab.md) for the
|
|
348
|
+
schema, configuration, caching and backward-compatible Parquet behavior.
|
|
@@ -160,6 +160,12 @@ and [VQA guide](docs/tools/vqa.md).
|
|
|
160
160
|
|
|
161
161
|
OpenSportsLib provides APIs and scripts for downloading and uploading OSL datasets with Hugging Face.
|
|
162
162
|
|
|
163
|
+
For `tracking_tracab`, both transfer formats include the original DAT and all
|
|
164
|
+
referenced metadata JSON/TF05/TF08 XML files. Uploads reject missing tracking
|
|
165
|
+
assets; full downloads validate completeness. Annotation-only downloads defer
|
|
166
|
+
assets until a sample/input download or missing-file hydration is requested.
|
|
167
|
+
See [TRACAB transfer behavior](docs/tracking_tracab.md#dataset-loading-and-persistence).
|
|
168
|
+
|
|
163
169
|
For SN-GAR classification and action-spotting configurations, setup, caching,
|
|
164
170
|
and training commands, see the [SN-GAR examples](examples/sngar/README.md).
|
|
165
171
|
|
|
@@ -291,3 +297,13 @@ For synchronized native-FPS GAR action clips and optional exact frame reproducti
|
|
|
291
297
|
|
|
292
298
|
For full-rate tracking clips with the same classification sample IDs, see the
|
|
293
299
|
[tracking conversion script](docs/tools/spotting-tracking-to-classification.md).
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
### Raw TRACAB tracking
|
|
303
|
+
|
|
304
|
+
`tracking_tracab` is supported by classification and localization tracking loaders
|
|
305
|
+
for local OSL JSON, Hugging Face JSON and indexed WebDataset sources. Set the
|
|
306
|
+
input modality to `tracking_tracab`; reference the original metadata JSON with
|
|
307
|
+
`metadata_path` and retain UTC period calibration and team codes in each input. `params.annotation_head` selects a head such as
|
|
308
|
+
`action` or `headers`. See [the DAT contract and loading guide](docs/tracking_tracab.md) for the
|
|
309
|
+
schema, configuration, caching and backward-compatible Parquet behavior.
|
|
@@ -48,7 +48,7 @@ def _manifest_media_references(payload: dict[str, Any]):
|
|
|
48
48
|
for input_obj in inputs:
|
|
49
49
|
if not isinstance(input_obj, dict):
|
|
50
50
|
continue
|
|
51
|
-
for key in ("path", "ball_path"):
|
|
51
|
+
for key in ("path", "ball_path", "metadata_path", "tf05_path", "tf08_path"):
|
|
52
52
|
if isinstance(input_obj.get(key), str):
|
|
53
53
|
yield input_obj[key], lambda value, input_obj=input_obj, key=key: input_obj.__setitem__(key, value)
|
|
54
54
|
values = input_obj.get("paths")
|
|
@@ -23,6 +23,7 @@ def _is_tracking_graph_modality(modality):
|
|
|
23
23
|
return str(modality).lower() in {
|
|
24
24
|
"tracking",
|
|
25
25
|
"tracking_parquet",
|
|
26
|
+
"tracking_tracab",
|
|
26
27
|
"tracking_h5",
|
|
27
28
|
"player_centroids_h5",
|
|
28
29
|
"player_joints_h5",
|
|
@@ -49,6 +50,13 @@ class ClassificationModel(BaseTaskModel):
|
|
|
49
50
|
if override is not None:
|
|
50
51
|
return expand(override)
|
|
51
52
|
|
|
53
|
+
from opensportslib.datasets.hf_json import hf_json_source, prepare_hf_json_split
|
|
54
|
+
if not self.is_remote and hf_json_source(self.config):
|
|
55
|
+
from opensportslib.core.config.accessors import set_split_source_path
|
|
56
|
+
prepared = prepare_hf_json_split(self.config, split)
|
|
57
|
+
set_split_source_path(self.config, split, str(prepared.source_path))
|
|
58
|
+
return str(prepared.annotation_path)
|
|
59
|
+
|
|
52
60
|
path = get_split_annotation_path(self.config, split)
|
|
53
61
|
if path:
|
|
54
62
|
return expand(path)
|
|
@@ -59,6 +59,15 @@ class LocalizationModel(BaseTaskModel):
|
|
|
59
59
|
set_split_source_path(self.config, "valid_data_frames", str(prepared.source_path))
|
|
60
60
|
return str(prepared.annotation_path)
|
|
61
61
|
|
|
62
|
+
from opensportslib.datasets.hf_tracking import hf_tracking_source, prepare_hf_tracking_split, stage_tracking_files
|
|
63
|
+
if hf_tracking_source(self.config):
|
|
64
|
+
prepared = prepare_hf_tracking_split(self.config, split)
|
|
65
|
+
root = stage_tracking_files(prepared)
|
|
66
|
+
set_split_source_path(self.config, split, str(root))
|
|
67
|
+
if split == "valid":
|
|
68
|
+
set_split_source_path(self.config, "valid_data_frames", str(root))
|
|
69
|
+
return str(prepared.annotations_path)
|
|
70
|
+
|
|
62
71
|
path = get_split_annotation_path(self.config, split)
|
|
63
72
|
if path:
|
|
64
73
|
return expand(path)
|
|
@@ -145,7 +145,11 @@ def _torch_cuda_available() -> bool:
|
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
def _dali_available() -> bool:
|
|
148
|
-
|
|
148
|
+
try:
|
|
149
|
+
return importlib.util.find_spec("nvidia.dali") is not None
|
|
150
|
+
except ModuleNotFoundError:
|
|
151
|
+
# find_spec raises when the optional parent namespace is absent.
|
|
152
|
+
return False
|
|
149
153
|
|
|
150
154
|
|
|
151
155
|
# DALI decodes video; any other input modality (tracking parquets, features)
|
{opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/load_annotations.py
RENAMED
|
@@ -12,6 +12,14 @@ from opensportslib.core.utils.config import load_json
|
|
|
12
12
|
from collections import defaultdict
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
def select_annotation_head(document, requested=None):
|
|
16
|
+
heads = document["labels"]
|
|
17
|
+
selected = requested or ("action" if "action" in heads else next(iter(heads)) if len(heads) == 1 else None)
|
|
18
|
+
if selected not in heads:
|
|
19
|
+
raise ValueError(f"Select annotation_head from {list(heads)}; got {requested!r}")
|
|
20
|
+
return selected
|
|
21
|
+
|
|
22
|
+
|
|
15
23
|
LOCALIZATION_ANNOTATION_STATUSES = {"verified", "unlabeled", "excluded"}
|
|
16
24
|
|
|
17
25
|
|
|
@@ -164,7 +172,7 @@ def expand_localization_intervals(record):
|
|
|
164
172
|
|
|
165
173
|
def load_annotations(
|
|
166
174
|
annotations_path,
|
|
167
|
-
task_key=
|
|
175
|
+
task_key=None,
|
|
168
176
|
exclude_labels=None,
|
|
169
177
|
multiview=False,
|
|
170
178
|
input_type="video",
|
|
@@ -175,6 +183,10 @@ def load_annotations(
|
|
|
175
183
|
with open(annotations_path, "r") as f:
|
|
176
184
|
data = json.load(f)
|
|
177
185
|
|
|
186
|
+
if not isinstance(data["data"], list):
|
|
187
|
+
raise TypeError("OSL data must be a list")
|
|
188
|
+
task_key = select_annotation_head(data, task_key)
|
|
189
|
+
|
|
178
190
|
# this is used for data slicing experiments.
|
|
179
191
|
# and doesn't affect the validation and test sets.
|
|
180
192
|
# if you haven't added "data_scaling" to the config, this will be ignored.
|
|
@@ -517,7 +529,7 @@ def annotationstoe2eformat(
|
|
|
517
529
|
return labels_e2e, task_name_list[0]
|
|
518
530
|
|
|
519
531
|
|
|
520
|
-
def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
|
|
532
|
+
def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps, input_type="tracking_parquet", annotation_head=None):
|
|
521
533
|
"""
|
|
522
534
|
Adapt tracking-parquet action-spotting annotations to E2E format.
|
|
523
535
|
|
|
@@ -546,6 +558,7 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
|
|
|
546
558
|
classes use to slice windows out of the cached native features.
|
|
547
559
|
"""
|
|
548
560
|
from opensportslib.datasets.utils.tracking import load_or_build_game_cache
|
|
561
|
+
from opensportslib.tracking.tracab import parse_utc
|
|
549
562
|
|
|
550
563
|
if not isinstance(label_files, list):
|
|
551
564
|
label_files = [label_files]
|
|
@@ -562,20 +575,26 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
|
|
|
562
575
|
|
|
563
576
|
annotations = load_json(label_path)
|
|
564
577
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
578
|
+
task_name = select_annotation_head(annotations, annotation_head)
|
|
579
|
+
labels = annotations["labels"][task_name].get("labels", {})
|
|
580
|
+
task_name_list.append(task_name)
|
|
568
581
|
classes_by_label_dir.append(labels)
|
|
569
582
|
|
|
570
583
|
videos = annotations["data"]
|
|
571
584
|
|
|
572
585
|
for video in tqdm.tqdm(videos):
|
|
573
|
-
|
|
586
|
+
candidates = [i for i in video["inputs"] if i.get("type") == input_type]
|
|
587
|
+
if len(candidates) != 1:
|
|
588
|
+
raise ValueError(f"Expected one {input_type} input for {video.get('id')!r}; found {len(candidates)}")
|
|
589
|
+
video_input = dict(candidates[0])
|
|
590
|
+
for key in ("metadata_path", "tf05_path", "tf08_path"):
|
|
591
|
+
if video_input.get(key):
|
|
592
|
+
video_input[key] = os.path.abspath(os.path.join(video_dir, video_input[key]))
|
|
574
593
|
video_path = video_input["path"]
|
|
575
594
|
full_video_path = os.path.join(video_dir, video_path)
|
|
576
595
|
assert os.path.isfile(full_video_path), full_video_path
|
|
577
596
|
|
|
578
|
-
_, times, _ = load_or_build_game_cache(full_video_path)
|
|
597
|
+
_, times, _ = load_or_build_game_cache(full_video_path, descriptor=video_input)
|
|
579
598
|
num_frames = len(times)
|
|
580
599
|
|
|
581
600
|
native_fps = video_input.get("fps")
|
|
@@ -591,7 +610,18 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
|
|
|
591
610
|
|
|
592
611
|
events = []
|
|
593
612
|
for ann in video.get("events", []):
|
|
594
|
-
|
|
613
|
+
if ann.get("head", task_name) != task_name:
|
|
614
|
+
continue
|
|
615
|
+
if ann["label"] not in labels:
|
|
616
|
+
raise ValueError(f"Event label {ann['label']!r} absent from head {task_name!r}")
|
|
617
|
+
if ann.get("timestamp_utc"):
|
|
618
|
+
if not video_input.get("UTC_time_start"):
|
|
619
|
+
raise ValueError("UTC events require input.UTC_time_start")
|
|
620
|
+
position_ms = (parse_utc(ann["timestamp_utc"]) - parse_utc(video_input["UTC_time_start"])).total_seconds() * 1000
|
|
621
|
+
else:
|
|
622
|
+
position_ms = float(ann["position_ms"])
|
|
623
|
+
if position_ms < 0 or (video_input.get("duration_ms") and position_ms >= video_input["duration_ms"]):
|
|
624
|
+
raise ValueError(f"Event timestamp {position_ms} outside tracking timeline")
|
|
595
625
|
native_idx = int(np.searchsorted(times, position_ms))
|
|
596
626
|
native_idx = min(max(native_idx, 0), num_frames - 1)
|
|
597
627
|
adj_frame = native_idx // stride
|
|
@@ -614,6 +644,7 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
|
|
|
614
644
|
events.sort(key=lambda x: x["frame"])
|
|
615
645
|
|
|
616
646
|
labels_e2e.append({
|
|
647
|
+
"input": dict(video_input),
|
|
617
648
|
"events": events,
|
|
618
649
|
"fps": sample_fps,
|
|
619
650
|
"num_frames": num_frames_after,
|
|
@@ -834,7 +865,7 @@ def check_config(cfg, split="train"):
|
|
|
834
865
|
if get_loader_backend(cfg) == "dali":
|
|
835
866
|
cfg.TRAIN.execution.repartitions = get_repartition_gpu(cfg.SYSTEM.gpu.count)
|
|
836
867
|
primary_modality = get_data_modality(cfg)
|
|
837
|
-
assert primary_modality in ["rgb", "video", "tracking_parquet"]
|
|
868
|
+
assert primary_modality in ["rgb", "video", "tracking_parquet", "tracking_tracab"]
|
|
838
869
|
backbone_type = get_component_name_by_kind(cfg, "encoder")
|
|
839
870
|
assert backbone_type in [
|
|
840
871
|
# From torchvision
|
|
@@ -900,8 +931,13 @@ def check_config(cfg, split="train"):
|
|
|
900
931
|
and data_path.endswith(".json")
|
|
901
932
|
and "labels" in load_json(data_path).keys()
|
|
902
933
|
):
|
|
903
|
-
|
|
904
|
-
|
|
934
|
+
document = load_json(data_path)
|
|
935
|
+
if primary_modality in {"tracking_parquet", "tracking_tracab"}:
|
|
936
|
+
head = select_annotation_head(document, get_data_params(cfg).get("annotation_head"))
|
|
937
|
+
classes = document["labels"][head].get("labels", {})
|
|
938
|
+
else:
|
|
939
|
+
for task_data in document["labels"].values():
|
|
940
|
+
classes = task_data.get("labels", {})
|
|
905
941
|
else:
|
|
906
942
|
assert isinstance(cfg.DATA.common.classes, (list, ListConfig))
|
|
907
943
|
classes = cfg.DATA.common.classes
|
|
@@ -64,7 +64,7 @@ def build(config, annotations_path, processor=None, split="train"):
|
|
|
64
64
|
"""
|
|
65
65
|
modality = get_data_modality(config).lower()
|
|
66
66
|
|
|
67
|
-
if modality in ("tracking", "tracking_parquet"):
|
|
67
|
+
if modality in ("tracking", "tracking_parquet", "tracking_tracab"):
|
|
68
68
|
from opensportslib.datasets.hf_tracking import hf_tracking_source
|
|
69
69
|
|
|
70
70
|
if hf_tracking_source(config):
|
|
@@ -133,7 +133,8 @@ class ClassificationDataset(Dataset):
|
|
|
133
133
|
annotation_input_type = "frames_npy"
|
|
134
134
|
|
|
135
135
|
self.samples, self.label_map = load_annotations(
|
|
136
|
-
annotations_path,
|
|
136
|
+
annotations_path,
|
|
137
|
+
task_key=data_params.get("annotation_head"),
|
|
137
138
|
exclude_labels=self.exclude_labels,
|
|
138
139
|
multiview=is_multiview,
|
|
139
140
|
input_type=annotation_input_type,
|
|
@@ -540,7 +541,7 @@ class TrackingDataset(ClassificationDataset):
|
|
|
540
541
|
continue
|
|
541
542
|
|
|
542
543
|
clip_path = clip_paths[0]
|
|
543
|
-
df = self._load_tracking_clip(clip_path)
|
|
544
|
+
df = self._load_tracking_clip(clip_path, item["inputs"][0])
|
|
544
545
|
|
|
545
546
|
num_frames = len(df)
|
|
546
547
|
all_features = np.zeros(
|
|
@@ -568,7 +569,7 @@ class TrackingDataset(ClassificationDataset):
|
|
|
568
569
|
# regardless of transforms.
|
|
569
570
|
edge_indices = []
|
|
570
571
|
for t in range(num_frames):
|
|
571
|
-
edge_index = self.
|
|
572
|
+
edge_index = self._build_edge_index(
|
|
572
573
|
all_features[t],
|
|
573
574
|
all_positions[t],
|
|
574
575
|
self.edge_type,
|
|
@@ -587,7 +588,7 @@ class TrackingDataset(ClassificationDataset):
|
|
|
587
588
|
|
|
588
589
|
print(f"Loaded {len(self.processed_samples)} {self.split} samples")
|
|
589
590
|
|
|
590
|
-
def _load_tracking_clip(self, path):
|
|
591
|
+
def _load_tracking_clip(self, path, descriptor=None):
|
|
591
592
|
"""read a single parquet tracking clip.
|
|
592
593
|
|
|
593
594
|
Args:
|
|
@@ -600,6 +601,10 @@ class TrackingDataset(ClassificationDataset):
|
|
|
600
601
|
import pandas as pd
|
|
601
602
|
|
|
602
603
|
full_path = os.path.join(self.video_path, path)
|
|
604
|
+
if descriptor and descriptor.get("type") == "tracking_tracab":
|
|
605
|
+
from opensportslib.tracking import TracabTrackingReader
|
|
606
|
+
with TracabTrackingReader(full_path, descriptor, metadata_base_dir=self.video_path) as reader:
|
|
607
|
+
return pd.DataFrame(reader.iter_uniform_rows())
|
|
603
608
|
return pd.read_parquet(full_path)
|
|
604
609
|
|
|
605
610
|
def __getitem__(self, idx):
|
|
@@ -687,7 +692,7 @@ class TrackingDataset(ClassificationDataset):
|
|
|
687
692
|
raise ValueError(f"No tracking paths found for item {idx}")
|
|
688
693
|
|
|
689
694
|
clip_path = clip_paths[0]
|
|
690
|
-
df = self._load_tracking_clip(clip_path)
|
|
695
|
+
df = self._load_tracking_clip(clip_path, item["inputs"][0])
|
|
691
696
|
|
|
692
697
|
num_frames = len(df)
|
|
693
698
|
all_features = np.zeros(
|
|
@@ -765,8 +770,8 @@ class HFTrackingDataset(TrackingDataset):
|
|
|
765
770
|
self._hf_reader = HFTarTrackingReader(prepared)
|
|
766
771
|
super().__init__(config, str(prepared.annotations_path), split)
|
|
767
772
|
|
|
768
|
-
def _load_tracking_clip(self, path):
|
|
769
|
-
return self._hf_reader.
|
|
773
|
+
def _load_tracking_clip(self, path, descriptor=None):
|
|
774
|
+
return self._hf_reader.read_tracking(path, descriptor)
|
|
770
775
|
|
|
771
776
|
|
|
772
777
|
class H5TrackingDataset(ClassificationDataset):
|
|
@@ -130,10 +130,13 @@ def prepare_hf_json_split(config, split: str) -> PreparedHFJsonSplit:
|
|
|
130
130
|
f"Expected one {media_type!r} input for sample {sample.get('game_id', sample.get('id'))!r}"
|
|
131
131
|
)
|
|
132
132
|
item = dict(selected[0])
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
for key in ("path", "metadata_path", "tf05_path", "tf08_path"):
|
|
134
|
+
if key != "path" and not item.get(key):
|
|
135
|
+
continue
|
|
136
|
+
filename = _safe_path(str(item.get(key) or ""))
|
|
137
|
+
if key == "path" and not filename.startswith(f"{split}/"):
|
|
138
|
+
raise ValueError(f"Media path {filename!r} is outside split {split!r}")
|
|
139
|
+
filenames.add(filename)
|
|
137
140
|
sample["inputs"] = [item]
|
|
138
141
|
|
|
139
142
|
def stage_media(filename: str) -> None:
|
|
@@ -13,7 +13,7 @@ from collections import OrderedDict
|
|
|
13
13
|
from dataclasses import dataclass
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
|
-
from opensportslib.core.config.accessors import get_input_cfg
|
|
16
|
+
from opensportslib.core.config.accessors import get_input_cfg, get_data_modality
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
@@ -126,7 +126,14 @@ def prepare_hf_tracking_split(config, split: str) -> PreparedTrackingSplit:
|
|
|
126
126
|
|
|
127
127
|
_set_resolved_revision(config, resolved)
|
|
128
128
|
safe_repo = re.sub(r"[^A-Za-z0-9_.-]+", "--", repo_id)
|
|
129
|
+
media_type = str(source.get("input_type") or get_data_modality(config))
|
|
130
|
+
if media_type == "tracking":
|
|
131
|
+
media_type = "tracking_parquet"
|
|
132
|
+
if media_type not in {"tracking_parquet", "tracking_tracab"}:
|
|
133
|
+
raise ValueError(f"Unsupported tracking input type: {media_type}")
|
|
129
134
|
directory = cache_dir / safe_repo / resolved / split
|
|
135
|
+
if media_type != "tracking_parquet":
|
|
136
|
+
directory = directory / media_type
|
|
130
137
|
directory.mkdir(parents=True, exist_ok=True)
|
|
131
138
|
annotations_path = directory / "annotations.json"
|
|
132
139
|
index_path = directory / "index.json"
|
|
@@ -181,7 +188,7 @@ def prepare_hf_tracking_split(config, split: str) -> PreparedTrackingSplit:
|
|
|
181
188
|
|
|
182
189
|
manifest = {}
|
|
183
190
|
for row in rows("shard_manifest.parquet"):
|
|
184
|
-
if row.get("file_role") not in (None, "", "primary") or row.get("input_type") !=
|
|
191
|
+
if row.get("file_role") not in (None, "", "primary", "metadata", "tf05", "tf08") or row.get("input_type") != media_type:
|
|
185
192
|
continue
|
|
186
193
|
key = (str(row["sample_id"]), str(row["relative_path"]))
|
|
187
194
|
if row.get("status") == "ok" and row.get("wds_member"):
|
|
@@ -190,17 +197,20 @@ def prepare_hf_tracking_split(config, split: str) -> PreparedTrackingSplit:
|
|
|
190
197
|
members = {}
|
|
191
198
|
for sample_id, (shard_name, sample) in locations.items():
|
|
192
199
|
for input_item in sample.get("inputs", []):
|
|
193
|
-
if input_item.get("type") !=
|
|
200
|
+
if input_item.get("type") != media_type:
|
|
194
201
|
continue
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
+
for key in ("path", "metadata_path", "tf05_path", "tf08_path"):
|
|
203
|
+
if key != "path" and not input_item.get(key):
|
|
204
|
+
continue
|
|
205
|
+
path = str(input_item.get(key) or "")
|
|
206
|
+
location = manifest.get((sample_id, path))
|
|
207
|
+
if not path or location is None or location[0] != shard_name:
|
|
208
|
+
raise ValueError(f"Missing tracking TAR member for {sample_id!r} ({key}): {path!r}")
|
|
209
|
+
if path in members and members[path] != location:
|
|
210
|
+
raise ValueError(f"Tracking path maps to multiple TAR members: {path!r}")
|
|
211
|
+
members[path] = location
|
|
202
212
|
if not members:
|
|
203
|
-
raise ValueError(f"{split} contains no
|
|
213
|
+
raise ValueError(f"{split} contains no {media_type} inputs")
|
|
204
214
|
|
|
205
215
|
_write_json_atomic(annotations_path, {**header, "data": samples})
|
|
206
216
|
_write_json_atomic(index_path, {"members": members})
|
|
@@ -277,10 +287,33 @@ class HFTarTrackingReader:
|
|
|
277
287
|
return tar
|
|
278
288
|
|
|
279
289
|
def read_parquet(self, path: str):
|
|
290
|
+
return self.read_tracking(path)
|
|
291
|
+
|
|
292
|
+
def read_tracking(self, path: str, descriptor=None):
|
|
280
293
|
import pandas as pd
|
|
281
294
|
|
|
282
295
|
if path not in self.members:
|
|
283
296
|
raise FileNotFoundError(f"Tracking clip is absent from Hub manifest: {path}")
|
|
297
|
+
metadata = None
|
|
298
|
+
xml_metadata = {}
|
|
299
|
+
for key in ("metadata_path", "tf05_path", "tf08_path"):
|
|
300
|
+
if not descriptor or not descriptor.get(key):
|
|
301
|
+
continue
|
|
302
|
+
metadata_path = descriptor[key]
|
|
303
|
+
if metadata_path not in self.members:
|
|
304
|
+
raise FileNotFoundError(f"Tracking metadata is absent from Hub manifest: {metadata_path}")
|
|
305
|
+
metadata_shard, metadata_member = self.members[metadata_path]
|
|
306
|
+
try:
|
|
307
|
+
from opensportslib.tracking.native import read_document
|
|
308
|
+
with self._tar(metadata_shard).extractfile(metadata_member) as stream:
|
|
309
|
+
document = read_document(stream, format="json" if key == "metadata_path" else "xml")
|
|
310
|
+
document.source = metadata_path
|
|
311
|
+
if key == "metadata_path":
|
|
312
|
+
metadata = document
|
|
313
|
+
else:
|
|
314
|
+
xml_metadata[key] = document
|
|
315
|
+
except (KeyError, ValueError, TypeError) as exc:
|
|
316
|
+
raise ValueError(f"TRACAB metadata {metadata_path}: {exc}") from exc
|
|
284
317
|
shard_name, member_name = self.members[path]
|
|
285
318
|
tar = self._tar(shard_name)
|
|
286
319
|
try:
|
|
@@ -289,9 +322,42 @@ class HFTarTrackingReader:
|
|
|
289
322
|
if stream is None:
|
|
290
323
|
raise KeyError(member_name)
|
|
291
324
|
with stream:
|
|
325
|
+
if descriptor and descriptor.get("type") == "tracking_tracab":
|
|
326
|
+
from opensportslib.tracking import TracabTrackingReader
|
|
327
|
+
with TracabTrackingReader(stream, descriptor, metadata=metadata, xml_metadata=xml_metadata) as reader:
|
|
328
|
+
return pd.DataFrame(reader.iter_uniform_rows())
|
|
292
329
|
contents = stream.read()
|
|
293
330
|
except KeyError as exc:
|
|
294
331
|
raise FileNotFoundError(
|
|
295
332
|
f"Tracking TAR member {member_name!r} is missing from {shard_name!r}"
|
|
296
333
|
) from exc
|
|
297
334
|
return pd.read_parquet(io.BytesIO(contents))
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def stage_tracking_files(prepared):
|
|
338
|
+
"""Materialize raw members once for localization's mmap feature cache."""
|
|
339
|
+
import shutil
|
|
340
|
+
from opensportslib.datasets.hf_json import _safe_path
|
|
341
|
+
|
|
342
|
+
root = prepared.annotations_path.parent / "media"
|
|
343
|
+
root.mkdir(exist_ok=True)
|
|
344
|
+
with (root / ".stage.lock").open("w") as lock:
|
|
345
|
+
fcntl.flock(lock, fcntl.LOCK_EX)
|
|
346
|
+
reader = HFTarTrackingReader(prepared)
|
|
347
|
+
try:
|
|
348
|
+
for path, (shard, member) in reader.members.items():
|
|
349
|
+
destination = root / _safe_path(path)
|
|
350
|
+
if destination.is_file():
|
|
351
|
+
continue
|
|
352
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
353
|
+
temporary = destination.with_name(destination.name + f".tmp-{os.getpid()}")
|
|
354
|
+
try:
|
|
355
|
+
with reader._tar(shard).extractfile(member) as source, temporary.open("wb") as target:
|
|
356
|
+
shutil.copyfileobj(source, target)
|
|
357
|
+
os.replace(temporary, destination)
|
|
358
|
+
finally:
|
|
359
|
+
temporary.unlink(missing_ok=True)
|
|
360
|
+
finally:
|
|
361
|
+
for tar in reader._open_tars.values():
|
|
362
|
+
tar.close()
|
|
363
|
+
return root
|
{opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/localization_dataset.py
RENAMED
|
@@ -470,6 +470,8 @@ class LocalizationDataset(Dataset):
|
|
|
470
470
|
dilate_len=self.data_cfg.dilate_len,
|
|
471
471
|
augmentations=_build_tracking_spotting_augmentations(self.config),
|
|
472
472
|
normalize=normalize,
|
|
473
|
+
input_type=get_runtime_modality(self.config),
|
|
474
|
+
annotation_head=get_data_params(self.config).get("annotation_head"),
|
|
473
475
|
)
|
|
474
476
|
elif dataset_type == "TrackingActionSpotVideo":
|
|
475
477
|
encoder_params = get_component_params_by_kind(self.config, "encoder")
|
|
@@ -485,6 +487,8 @@ class LocalizationDataset(Dataset):
|
|
|
485
487
|
r=encoder_params.get("radius"),
|
|
486
488
|
overlap_len=getattr(cfg, "overlap_len", self.data_cfg.clip_len // 2),
|
|
487
489
|
normalize=normalize,
|
|
490
|
+
input_type=get_runtime_modality(self.config),
|
|
491
|
+
annotation_head=get_data_params(self.config).get("annotation_head"),
|
|
488
492
|
)
|
|
489
493
|
else:
|
|
490
494
|
dataset = None
|
|
@@ -1276,17 +1280,24 @@ class _TrackingGraphWindowMixin:
|
|
|
1276
1280
|
"""
|
|
1277
1281
|
return batch["frame"].to(device)
|
|
1278
1282
|
|
|
1279
|
-
def _get_game_cache(self, video_path):
|
|
1283
|
+
def _get_game_cache(self, video_path, descriptor=None):
|
|
1280
1284
|
"""lazily load (and memoize for the lifetime of this dataset
|
|
1281
1285
|
instance/worker) a game's cached whole-match features."""
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1286
|
+
companion_signatures = []
|
|
1287
|
+
if descriptor and descriptor.get("type") == "tracking_tracab":
|
|
1288
|
+
for field in ("metadata_path", "tf05_path", "tf08_path"):
|
|
1289
|
+
if descriptor.get(field):
|
|
1290
|
+
stat = os.stat(descriptor[field])
|
|
1291
|
+
companion_signatures.append((field, stat.st_size, stat.st_mtime_ns))
|
|
1292
|
+
key = (video_path, json.dumps(descriptor, sort_keys=True), tuple(companion_signatures))
|
|
1293
|
+
if key not in self._game_cache:
|
|
1294
|
+
self._game_cache[key] = self._load_or_build_game_cache(video_path, descriptor=descriptor)
|
|
1295
|
+
return self._game_cache[key]
|
|
1285
1296
|
|
|
1286
1297
|
def _slice_window(self, video_meta, base_idx):
|
|
1287
1298
|
"""Fetch the game cache and slice a decimated feature window +
|
|
1288
1299
|
per-frame position lists out of it (see tracking.slice_window)."""
|
|
1289
|
-
features_cache, _, positions_cache = self._get_game_cache(video_meta["video"])
|
|
1300
|
+
features_cache, _, positions_cache = self._get_game_cache(video_meta["video"], video_meta.get("input"))
|
|
1290
1301
|
return self._slice_window_fn(
|
|
1291
1302
|
features_cache, positions_cache, base_idx, self._clip_len, video_meta["stride"]
|
|
1292
1303
|
)
|
|
@@ -1364,12 +1375,14 @@ class TrackingActionSpotDataset(Dataset, _TrackingGraphWindowMixin):
|
|
|
1364
1375
|
fg_upsample=-1,
|
|
1365
1376
|
augmentations=None,
|
|
1366
1377
|
normalize=True,
|
|
1378
|
+
input_type="tracking_parquet",
|
|
1379
|
+
annotation_head=None,
|
|
1367
1380
|
):
|
|
1368
1381
|
from opensportslib.core.utils.load_annotations import annotationstoe2eformat_tracking
|
|
1369
1382
|
|
|
1370
1383
|
self._src_file = label_file
|
|
1371
1384
|
self._labels, self.task_name = annotationstoe2eformat_tracking(
|
|
1372
|
-
label_file, video_dir, extract_fps
|
|
1385
|
+
label_file, video_dir, extract_fps, input_type, annotation_head
|
|
1373
1386
|
)
|
|
1374
1387
|
self._class_dict = _normalize_class_dict(classes)
|
|
1375
1388
|
self._video_idxs = {x["video"]: i for i, x in enumerate(self._labels)}
|
|
@@ -1528,12 +1541,14 @@ class TrackingActionSpotVideoDataset(Dataset, _TrackingGraphWindowMixin, Dataset
|
|
|
1528
1541
|
pad_len=5,
|
|
1529
1542
|
skip_partial_end=True,
|
|
1530
1543
|
normalize=True,
|
|
1544
|
+
input_type="tracking_parquet",
|
|
1545
|
+
annotation_head=None,
|
|
1531
1546
|
):
|
|
1532
1547
|
from opensportslib.core.utils.load_annotations import annotationstoe2eformat_tracking
|
|
1533
1548
|
|
|
1534
1549
|
self._src_file = label_file
|
|
1535
1550
|
self._labels, self.task_name = annotationstoe2eformat_tracking(
|
|
1536
|
-
label_file, video_dir, extract_fps
|
|
1551
|
+
label_file, video_dir, extract_fps, input_type, annotation_head
|
|
1537
1552
|
)
|
|
1538
1553
|
self._class_dict = _normalize_class_dict(classes)
|
|
1539
1554
|
self._video_idxs = {x["path"]: i for i, x in enumerate(self._labels)}
|