WhiskiWrap
WhiskiWrap provides tools for running whisk (the Janelia whisker tracker) more easily and efficiently. It improves on whisk by:
- Robust input — it uses your system
ffmpegto read almost any video and to emit simple TIFF stacks that whisk traces reliably. - Speed — it runs many
traceprocesses in parallel on non-overlapping chunks of the video. - Portability / memory — results are collected into HDF5 (or Parquet) files readable from Python or MATLAB, and can be read partially.
The codebase is split into modules: base (core utilities), pipeline
(high-level workflows), io (video I/O), and wfile_io / mfile_io (ctypes
readers for whisk .whiskers / .measurements files).
Installation
Requirements: Python ≥ 3.10 and ffmpeg on your PATH (ffmpeg -version
should run). Windows, Linux and macOS are supported.
whisk is installed automatically as the whisk-janelia dependency — its
prebuilt trace/measure/classify binaries (including native Windows
.exes) are bundled in the wheel, so no separate whisk install or
WHISKPATH setup is needed.
Install with uv (recommended) or pip:
# isolated environment
uv venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
uv pip install -e . # editable; or: uv pip install .
# plain pip
pip install -e . # or: pip install whiskiwrap
Verify:
python -c "import WhiskiWrap; print('ok')"
Build tools are only needed if a dependency lacks a wheel for your platform (Debian/Ubuntu:
python3-dev build-essential; Fedora:python3-devel gcc; macOS:xcode-select --install; Windows: usually none, since wheels are used).
Quick start
import WhiskiWrap
# Copy the input next to a working directory — many temporary files are created.
input_video = 'test_video2.mp4'
output_file = 'output.hdf5'
# Trace (and optionally measure) in parallel chunks -> combined HDF5.
WhiskiWrap.pipeline_trace(input_video, output_file, n_trace_processes=4)
Read the per-frame summary (tip/follicle/angle/… of every whisker):
import tables, pandas
with tables.open_file(output_file) as fi:
summary = pandas.DataFrame.from_records(fi.root.summary.read())
For bilateral tracking with measurement per side, use
interleaved_split_trace_and_measure(...) (see WhiskiWrap/pipeline.py), which
crops each face side, traces in chunks, and writes a per-side Parquet/HDF5 file.
How it works
- Split the video into epochs (~100k frames) read into memory one at a time.
- For each epoch: split into chunks (~1000 frames, optionally cropped),
write each chunk as a TIFF stack, trace chunks with parallel
traceinstances, then append each chunk's.whiskersresults to the output file. - Optionally delete intermediate chunk files.
Key parameters:
n_trace_processes— paralleltraceinstances (≈ number of CPUs).epoch_sz_frames— frames per epoch; as large as memory allows (e.g. 100000).chunk_sz_frames— frames per chunk; ideallyepoch_sz_frames / (N * n_trace_processes).measure=True,face='left'|'right'— also runmeasurefor the given face side.
Whisker linking & the learned add-on
whisk identity classification (classify/HMM reclassify) only operates within
a chunk. Preserving whisker identity across chunks and across a whole
session — so each wid follows the same physical whisker in every frame — is
handled by the linking step in wwutils/classifiers/hmm_link.py
(link_whiskers_hmm): per-side whisk-HMM reclassify → cross-chunk stitch →
outlier filters.
The HMM linker is solid but hits two ceilings that hand-tuned heuristics can't clear: coverage (length/follicle/angle filters drop real, still-visible whiskers) and close-whisker identity (adjacent whiskers swap; they separate cleanly by length, which the position-keyed linker ignores). The learned add-on addresses both:
- a coverage model — a shipped real-vs-noise classifier
(
wwutils/classifiers/models/coverage.joblib) that replaces the outlier filters and re-admits dropped detections. Real-vs-noise is universal and the features are scale-free, so it is trained once (on two animals, sc013 + seg04) and applied to any clip. Cross-session held-out AP ≈ 0.999. - an identity re-ranker — a per-clip model (no labels needed: bootstrapped from the HMM's own high-confidence runs) that uses length + normalized follicle position to fix close-whisker swaps via a conservative, no-flicker Hungarian re-rank that only overrides the HMM when its margin is large.
Day-to-day use
The add-on ships with the package and is off by default. To enable it, pass
--learned to the tracking entry point (whisker_tracking.py in the
thigmotaxis repo, or call link_whiskers_hmm(..., coverage_mode="model", identity_mode="bootstrap") directly):
- Any new clip: add
--learned. Zero-shot it already beats the baseline linker (seg04: missing detections 59 → 20, identity accuracy 0.969 → 0.981) — no per-clip setup. - An important clip you want pristine: label a few minutes in the GUI, then
train a GT-backed identity model for that session — it drives id-switches down
hard (seg04 32 → 4). See
identity_model.train_identity(out, gt=...). - Tip: before labeling/seeking in the GUI, run the clip through a
re-encode to an all-intra stream (
ffmpeg -i in.mp4 -c:v libx264 -bf 0 -g 1 out.mp4) or trace with--enhance. Raw H.264 with B-frames over-reports the frame count and seeks inaccurately, so overlays can drift by a frame or two.
The add-on is additive and schema-preserving: with the flag off, the linker is byte-identical to before. Coverage is train-once-ship-everywhere; identity is per-session by design.
Requires
scikit-learnandjoblib(installed automatically as dependencies). The coverage model is bundled in the wheel.
Metadata
Release files for WhiskiWrap 1.2.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| whiskiwrap-1.2.9.tar.gz | 6.3 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| whiskiwrap-1.2.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.6 MB
Release files / whiskiwrap-1.2.9.tar.gz
| Download URL | whiskiwrap-1.2.9.tar.gz |
|---|---|
| Size | 6.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a6500e3cf781079cea72bcc707dcde296b0062112e67fa65b6a1b22e33de13d0
|
|
BLAKE2b-256 checksum How to use checksums |
24d4a0e61b77bfc3f0ab93dfbcd870c4449a106c1bd1c8c34f5a4b86b880c81f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / whiskiwrap-1.2.9-py3-none-any.whl
| Download URL | whiskiwrap-1.2.9-py3-none-any.whl |
|---|---|
| Size | 6.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
21fe6667aa7e5015b75df12a1a966e3b7160ad5c8fd8d078b20cb283e98425cf
|
|
BLAKE2b-256 checksum How to use checksums |
fe2296f31a03d4b1a71b6ee825e14a342a2ca94d244b3bd906097fa99a0a2d35
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|