kodokan
Study Kodokan Judo throws from video via body-pose analysis: download technique demonstrations, extract two-person (tori/uke) skeletons, split each clip into its repeated demonstrations, visualize them, and compare/score demonstrations.
from kodokan.acquire import download_techniques
from kodokan.track import estimate_poses_tracked
from kodokan.segment import segment_demonstrations
from kodokan.viz import render_skeleton_video
res = download_techniques(playlist_items="2")[0] # Seoi-nage (#002), with metadata
seq = estimate_poses_tracked(
res.path, source_url=res.info["webpage_url"]
) # tracked tori/uke COCO-17
demos = segment_demonstrations(
seq, min_two_person_frac=0.3
) # per-demo (start_s, end_s)
render_skeleton_video(
seq, out_path="overlay.mp4", source_video=res.path
) # skeletons on the video
render_skeleton_video(
seq, out_path="skeleton.mp4", blank_canvas=True
) # skeletons on blank canvas
What it does
A functional pipeline over the official Kodokan 100 Techniques YouTube playlist:
acquire (yb) ─► pose (rtmlib / YOLO, tracked tori/uke) ─► segment (motion-energy)
└─► dol stores (Parquet pose + JSON segments) ─► visualize (overlay / blank / Rerun)
└─► compare two demos (joint-angle DTW) ─► score + eval harness
YouTube acquisition lives in the yb package
(download_youtube_playlist); kodokan is the analysis layer on top.
Install
import kodokan needs only numpy; everything heavy is an optional extra (imported
lazily on first use), so the import never fails for a missing one:
pip install -e '.[all]' # or pick extras: .[pose,track,viz,analysis,storage,acquire]
| extra | for | brings | licence |
|---|---|---|---|
pose |
pose estimation (RTMPose, the default backend) | rtmlib, onnxruntime | permissive |
track |
stable tori/uke identity (estimate_poses_tracked) |
ultralytics (+ ultralytics-thop, ultralytics-platform) |
AGPL-3.0-or-later |
viz |
rendering | opencv-python, rerun-sdk, supervision, matplotlib | permissive |
analysis |
segment / compare / score | scipy, dtaidistance, pandas, pyarrow | permissive |
storage |
dol stores | dol | permissive |
acquire |
YouTube download | yb | permissive |
track is separated from pose on purpose — see
Licensing of extras. The example at the top of this README
uses estimate_poses_tracked, so it needs track; estimate_poses alone does not.
You also need ffmpeg on PATH (acquisition/merge). The optional 3D lift
(scripts/lift_3d_mediapipe.py) runs in a separate venv, because MediaPipe is
ABI-incompatible with numpy 2.x:
python -m venv ~/.kodokan_mp
~/.kodokan_mp/bin/pip install 'mediapipe==0.10.18' 'numpy<2' 'opencv-python-headless==4.10.0.84'
Data (videos, keypoints, renders, weights) lives outside the repo under
~/kodokan_data (override with KODOKAN_DATA_DIR).
Licensing of extras
kodokan itself is MIT, and pip install kodokan installs numpy and nothing
else — no copyleft reaches you through the core package.
One extra is different, and it is worth reading before you type it:
kodokan[track]installs ultralytics, which is licensed AGPL-3.0-or-later.kodokan[all]includes it too.
It is three distributions, not one — ultralytics pulls two more of its own, and both carry the same licence, so listing only the first would understate what lands in your environment:
| distribution | licence | how it arrives |
|---|---|---|
ultralytics |
AGPL-3.0-or-later | declared by the track extra |
ultralytics-thop |
AGPL-3.0-or-later | hard dependency of ultralytics |
ultralytics-platform |
AGPL-3.0-only | dependency of ultralytics on Python ≥ 3.11 |
kodokan imports only the first; the other two arrive with it and are covered by the same adjudication.
The AGPL is not "the GPL but for Python". Its section 13 adds a network clause:
if you modify the work and let users interact with it over a network, those users
are entitled to the complete corresponding source of the whole combined work — even
though you never distributed a copy to anyone. Deploying a judo-analysis service
built on kodokan[track] is exactly that situation. The obligation attaches to the
combined work, not to ultralytics alone. That is the conservative reading — the one
this project plans around — rather than settled case law, but "we only import it" is
not a position worth betting a product on.
If that is not compatible with what you are building, you have two options:
- Do not install
track. Everything below still works. - Buy an Ultralytics Enterprise License, which Ultralytics sells precisely for commercial use that cannot accept the AGPL.
What you can do without it. Everything except identity tracking:
estimate_poses(...)— the defaultbackend="rtmlib"(RTMPose over onnxruntime) is AGPL-free and is whatkodokan[pose]installs. It keeps the two highest-confidence people per frame, ordered left→right per frame.segment,compare,score,store,viz,acquire— all permissive.
What you give up. kodokan.track.estimate_poses_tracked runs Ultralytics'
built-in BoT-SORT/ByteTrack so tori and uke keep persistent identities across a
clip instead of swapping whenever they cross. rtmlib is a pose estimator with no
multi-object tracker, so this is a real feature difference, not a packaging one.
estimate_poses(backend="ultralytics") — the non-default YOLO11-pose backend —
also needs it. Both raise an ImportError naming the extra and the licence rather
than a bare ModuleNotFoundError.
The decision to keep this dependency, and the conditions that should reopen it,
are recorded in [tool.wads.licence] in pyproject.toml.
The pipeline
| module | purpose |
|---|---|
kodokan.acquire |
download techniques (wraps yb), skip the PV, keep source URLs |
kodokan.pose |
estimate_poses facade (rtmlib / ultralytics backends), COCO-17, PoseSequence |
kodokan.track |
estimate_poses_tracked — stable tori/uke identity (BoT-SORT + spatial continuity) |
kodokan.segment |
hysteresis motion-energy segmentation + two-person gate + self-similarity |
kodokan.store |
pose_store (tidy Parquet) / segments_store (JSON), the analysis SSOT |
kodokan.viz |
overlay / blank-canvas MP4 + Rerun logging |
kodokan.compare |
joint-angle (soft-)DTW comparison of two demonstrations |
kodokan.score |
reference-based 0–100 scoring + per-joint/per-phase feedback |
kodokan.descriptors |
experimental feature descriptors (for the eval harness) |
Runnable end-to-end examples live in examples/ (warmup_seoinage.py,
batch_pipeline.py, segment_review.py, compare_demos.py, score_demos.py,
eval_features.py).
Dataset
examples/batch_pipeline.py builds a small dataset (10 techniques · 84
demonstrations · 18.3k frames) into the dol stores. Load it:
from kodokan.store import pose_store, segments_store, load_all_tidy
seq = pose_store()["zIq0xI0ogxk"] # (F, 2, 17, 3) COCO-17 (x, y, conf)
demos = segments_store()["zIq0xI0ogxk"] # demo intervals + source_url
df = load_all_tidy() # tidy DataFrame across all clips
See misc/docs/dataset.md.
Status & honest limits
Works well: acquisition, tracked two-person pose, demo segmentation, the dol stores, visualization, and same-technique demo comparison (joint-angle DTW is speed-invariant) with interpretable per-joint/per-phase feedback.
Does not work yet — and this is measured, not assumed: technique recognition /
cross-demo scoring. A feature bake-off (misc/docs/feature-bakeoff.md)
shows every 2D descriptor and MediaPipe 3D joint angles sit at chance (separation
AUC ≈ 0.49–0.56). The blockers are noisy monocular 3D under grappling occlusion,
tori/uke role inconsistency, and the weakness of hand-crafted angle-DTW for few
examples — not viewpoint alone. Recognition needs a learned skeleton representation
(few-shot JEANIE, or trained PoseC3D/CTR-GCN) and/or cleaner multi-person 3D with
role-consistent features. The eval harness (examples/eval_features*.py) is ready to
validate those.
Background & rationale
misc/docs/research-architecture.md— cited tools/architecture research (75 refs).misc/docs/dataset.md— dataset card.misc/docs/feature-bakeoff.md— why hand-crafted features don't discriminate techniques (the empirical finding).
Metadata
Release files for kodokan 0.0.19
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kodokan-0.0.19.tar.gz | 135.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kodokan-0.0.19-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 191.7 kB
Release files / kodokan-0.0.19.tar.gz
| Download URL | kodokan-0.0.19.tar.gz |
|---|---|
| Size | 135.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4382f7b105b190aa881c0440f55857d619f2668ad5d8b49d836d97aec42a4f96
|
|
BLAKE2b-256 checksum How to use checksums |
061bbeba1361ab29caff5e3d04950377f870d1292fb96d334d09b99bb009f8d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / kodokan-0.0.19-py3-none-any.whl
| Download URL | kodokan-0.0.19-py3-none-any.whl |
|---|---|
| Size | 56.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eb9135d9bb79b28b544f4c0e457f69513b1f097a800304a10250916d8615f979
|
|
BLAKE2b-256 checksum How to use checksums |
282632da9c5aabe6223e0e4b0edcda469e28e4cd19a79af2d484951ffe9173fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|