Install, capture a dataset, train a model, and run live detection. New tutorials get added here over time.
Gesto Labeller — download the latest release, unzip it anywhere, and run GestoLabeller.exe. No Python required. See the full feature guide.
The gesto package — install from PyPI into a fresh virtual environment:
python -m venv gesto_env # Windows gesto_env\Scripts\activate # macOS / Linux source gesto_env/bin/activate pip install gesto
Point it at a project folder, pick a mode and a region, and it handles the rest — loading, training, versioned model storage, and live detection that matches how the data was captured. See Dependencies for why the fresh environment matters.
The whole loop — capture, train, detect — in four moves:
gesto train static hands_one "C:\...\gesto_projects\my-signs" gesto detect static hands_one
A window opens with your webcam, the detected skeleton, and a live probability bar for the closest-matching classes.
No dataset yet? Download a hosted demo model and run detection right away:
gesto detect sequence hands_one --default
This fetches a pre-trained sequence/hands_one model the first time and caches it, so later runs start instantly.
| Mode | The gesture is… | Model | Example |
|---|---|---|---|
static | a held shape or posture | Dense network | thumbs up, alphabet letters, a stance |
sequence | a motion over time | stacked LSTM | waving, clapping, jogging |
Static needs far less data (every captured frame is a training sample) and predicts instantly with no warm-up. Reach for sequence only when two gestures share the same shape and differ by movement.
Both model types come in a lighter and a full-size variant. Small datasets automatically get the lighter one (an oversized network on little data overfits); force a choice with --small or --large. All use the Adam optimizer, softmax output, and sparse categorical cross-entropy loss, and save as model.keras.
Input is a single feature vector (63–258 values by region).
| Variant | Layers |
|---|---|
| Large | Dense(256) → Dropout(0.4) → Dense(128) → Dropout(0.3) → Dense(64) → Dropout(0.2) → softmax |
| Small | Dense(64) → Dropout(0.3) → Dense(32) → Dropout(0.2) → softmax |
Input is a window of frames (seq_len, dim). LSTM layers use tanh (enabling the fast cuDNN path).
| Variant | Layers |
|---|---|
| Large | LSTM(64, seq) → LSTM(128, seq) → LSTM(64) → Dense(64) → Dense(32) → softmax |
| Small | LSTM(32) → Dropout(0.4) → Dense(32) → Dropout(0.3) → softmax |
relu activation throughout.| Region | Dim | Tracks |
|---|---|---|
hands_one | 63 | one hand, 21 joints |
hands_two | 126 | both hands |
pose | 132 | full body, 33 points |
legs | 32 | lower body, 8 points |
full | 258 | body + both hands |
The region must match how the project was captured — gesto checks the feature dimension and tells you if it doesn't.
Use whichever you like. General — mode and region as arguments:
gesto train static hands_one ./gesto_projects/signs gesto detect sequence pose --source clip.mp4 gesto image hands_one photo.jpg
Per-combination — one command per mode+region (there's one for each):
gesto train-static-legs ./gesto_projects/stances --epochs 250 gesto detect-sequence-pose --source clip.mp4 gesto image-static-hands-one photo.jpg
--source takes a webcam index or a file path:
gesto detect static hands_one # default webcam (index 0) gesto detect static hands_one --source 1 # second camera gesto detect sequence pose --source walk.mp4 # a video file gesto detect sequence pose --source C:\clips\run.avi
The overlay shows the top matches ranked by confidence, closest first.
Static models can classify a still image:
gesto image hands_one photo.jpg # opens a window with the result gesto image hands_one photo.jpg --no-show # just print the prediction gesto image-static-pose posture.png --version 2 # a specific model version
Landmarks are drawn on the frame by default. Turn them off with --no-draw:
gesto detect static hands_one # skeleton drawn (default) gesto detect static hands_one --no-draw # clean video, no skeleton gesto image hands_one photo.jpg --no-draw
Epochs and other hyperparameters are adjustable on any train command:
gesto train sequence pose ./proj --epochs 400 --batch-size 32 --seq-len 30 gesto train-static-hands-one ./proj --epochs 150 --large # force full model
Everything the CLI does is available in code:
import gesto run = gesto.train("./gesto_projects/signs", region="hands_one", mode="static") gesto.detect("static", "hands_one") # camera gesto.detect("sequence", "pose", source="clip.mp4") # video # classify a single image with a static model from gesto.detect import predict_image label, confidence, probs = predict_image("static", "hands_one", "photo.jpg", show=False, draw_landmarks=False)
Or drive a model yourself:
from gesto.detect import Predictor predictor = Predictor.load("static", "hands_one") vector = predictor.features(holistic_result) # extract + normalize probs = predictor.predict(vector)
Everything lands under one artifacts/ folder, split by mode then region. Training never overwrites an earlier run — it versions:
artifacts/
static/
hands_one/ # model.keras, labels.json
hands_one_2/ # the next run
pose/
sequence/
pose/
pose_2/
gesto detect static pose picks the newest version; --version 1 picks a specific one. List everything you've trained with gesto list.
--version. Nothing is ever lost.Predictions are only correct when detection feeds the model the same kind of vector it trained on. gesto mirrors Gesto Labeller exactly:
--raw when training so detection knows to skip it.gesto applies class weights but balanced data is better.Run gesto inspect <project> to check all of this before training.
gesto uses MediaPipe's legacy solutions API, removed in MediaPipe 0.10.31. It also needs versions of TensorFlow, NumPy and protobuf that agree with that MediaPipe. The package pins a coherent, tested set:
| Package | Pinned range | Tested with |
|---|---|---|
| mediapipe | >=0.10,<0.10.30 | 0.10.21 |
| tensorflow | >=2.15,<2.18 | 2.17.1 |
| numpy | >=1.23,<2 | 1.26.4 |
| protobuf | >=3.20,<5 | 4.25.9 |
| opencv-python | >=4.8,<4.12 | 4.11.0 |
Install into a fresh virtual environment so these don't clash with other projects. To repair an existing environment, pin the set explicitly:
pip install "mediapipe==0.10.21" "tensorflow==2.17.1" \ "numpy==1.26.4" "protobuf==4.25.9" "opencv-python==4.11.0.86"
The legacy MediaPipe solutions API won't be maintained forever. A future release will move to MediaPipe's newer Tasks API (HandLandmarker, PoseLandmarker), which lifts the version ceiling. That API produces slightly different hand-landmark geometry, so models would need retraining — hence it's a deliberate, separate step rather than a drop-in change.
The two parts of Gesto are released under different open-source licenses:
| Component | License | What it means |
|---|---|---|
| gesto (Python package) | MIT | Free to use, modify, and redistribute — including in commercial and closed-source projects. |
| Gesto Labeller (desktop app) | Community Edition | Free to download and use. Built with PySide6 (Qt for Python) under the LGPL. |
The package's dependencies — TensorFlow, NumPy, OpenCV, MediaPipe, protobuf — are all permissively licensed (Apache 2.0 / BSD). The model architectures are standard Dense and LSTM networks with no proprietary components.