animap-gpu / app /adapters /pose /__init__.py
bluman1's picture
Publish services/inference
4b98524 verified
Raw
History Blame Contribute Delete
4.59 kB
"""Quadruped pose to gait features: §24 from the keypoints onward.
The pose model is not here. What is here is everything a pose model feeds:
a keypoint vocabulary that more than one model can be mapped into
(`vocabulary`), a body frame that removes the animal's translation and its
changing apparent size (`tracks`), and the §24 features plus a screen that
cannot express a diagnosis (`gait`).
That boundary is drawn where it is because of the licences, which are the part of
§24 most likely to be discovered late.
## Licence positions, recorded because they decide what can be sold
**DeepLabCut SuperAnimal-Quadruped — Modified MIT, academic and non-commercial
use only.** The model card on Hugging Face states it plainly: use is restricted
to academic and non-commercial purposes, the model "may not be used to harm any
animal deliberately", and commercial licensing is available on application to
Prof. Mackenzie W. Mathis or EPFL's technology transfer office. §24 names this
model first, and nothing about that is a reason not to evaluate it — but Animap
is a commercial product, so shipping it would need that licence. Read on
2026-08-22 from
`https://huggingface.co/mwmathis/DeepLabCutModelZoo-SuperAnimal-Quadruped`.
**ViTPose — Apache-2.0 for the code and the Hugging Face ports.** The AP-10K
vocabulary it can be run against covers 54 species including cattle. It is the
alternative §36 requires to be tried, and it is the one with no commercial
obstacle.
`experiments/cattle_gait/README.md` records which of these actually ran and what
it produced. This docstring records only what their terms say.
"""
from __future__ import annotations
from app.adapters.base import (
Adapter,
AdapterSpec,
Availability,
Modality,
Placement,
Task,
)
from app.adapters.pose.gait import (
GaitFeatures,
GaitScreen,
LimbCycle,
PairAsymmetry,
STATEMENTS,
Verdict,
features,
screen,
)
from app.adapters.pose.tracks import (
BodyFrame,
PoseSequence,
TrackUnusable,
body_frame,
in_body_frame,
)
from app.adapters.pose.vocabulary import (
AP10K,
AP10K_ORDER,
CONTRALATERAL_PAIRS,
SUPERANIMAL_QUADRUPED,
VOCABULARIES,
Landmark,
missing,
)
GAIT_FEATURES_SPEC = AdapterSpec(
adapter_id="gait-features",
runtime="opencv-numpy",
tasks=(Task.MEASURE,),
modalities=(Modality.VIDEO,),
directive_role=(
"§24 cattle gait — stride timing, left/right symmetry, hoof "
"trajectories, back-line movement, head movement and stance duration, "
"derived from quadruped keypoint tracks. The pose model itself is a "
"separate adapter; this is the deterministic half §4 prefers."
),
requires_artefact=False,
placement=Placement.CPU_SERVICE,
placement_reason=(
"Gradients and one FFT over a few hundred frames of keypoints — "
"microseconds. It sits wherever the pose model does, and the pose model "
"is the thing that needs a GPU."
),
notes=(
"**No clinical threshold exists and none is offered.** `screen()` "
"requires the caller to supply the asymmetry index it judges against, "
"because deriving one needs cattle a vet locomotion-scored and this "
"code has never seen any. What `experiments/cattle_gait` measures "
"instead is the method's own resolution — the smallest asymmetry it can "
"separate from its noise — which is a different claim and is labelled "
"as one."
),
)
class GaitFeatureAdapter(Adapter):
"""§24 from the keypoints onward. Always available; never diagnoses."""
spec = GAIT_FEATURES_SPEC
def availability(self) -> Availability:
return Availability(True)
def load(self) -> "GaitFeatureAdapter":
return self
def measure(self, sequence: PoseSequence) -> GaitFeatures:
return features(sequence)
def screen(self, sequence: PoseSequence, *, threshold: float,
threshold_basis: str = "unstated") -> GaitScreen:
return screen(sequence, threshold=threshold, threshold_basis=threshold_basis)
__all__ = [
"AP10K",
"AP10K_ORDER",
"CONTRALATERAL_PAIRS",
"GAIT_FEATURES_SPEC",
"STATEMENTS",
"SUPERANIMAL_QUADRUPED",
"VOCABULARIES",
"BodyFrame",
"GaitFeatureAdapter",
"GaitFeatures",
"GaitScreen",
"Landmark",
"LimbCycle",
"PairAsymmetry",
"PoseSequence",
"TrackUnusable",
"Verdict",
"body_frame",
"features",
"in_body_frame",
"missing",
"screen",
]