SAM-prompted instance segmentation (inference)¶
Predict a per-instance mask for every animal in an existing pose .slp by
prompting Segment Anything
(SAM) with the predicted keypoints / centroids. The masks are written as
sio.PredictedSegmentationMask so they import into the SLEAP GUI for review and
correction; you do not train a segmentation model.
This is the inference complement to
top-down (trained) segmentation: there the mask comes
from a trained centered_instance_segmentation head; here it comes from SAM,
prompted by poses you already have. Use it to bootstrap masks from a pose model
without training a mask model.
v1 is prompted-only. Three prompt modes — pose, centroid, and box. Unprompted ("everything") mask generation is deferred. The GUI correction round-trip is gated on upstream frontend work; v1 ships the masks plus a review-overlay PNG.
Install¶
SAM1 (ViT-H, Apache-2.0, ungated) is an optional, lazily imported extra so the default install never needs it:
Download a SAM checkpoint (e.g.
sam_vit_h_4b8939.pth)
and pass its path via sam_checkpoint=.
SAM3 (mask_backend="sam3") is a second, gated backend behind its own extra:
SAM3 lives in the gated facebook/sam3
Hugging Face repo and ships in transformers>=5. You must request access, then
authenticate (huggingface-cli login or set HF_TOKEN) with an approved
account. SAM3 also typically wants torch cu130, which may not co-install
with the rest of sleap-nn: keep it in its own environment, or run the SAM3 image
path out-of-process (write the raw masks + bookkeeping to an .npz) and assemble
the .slp back in the sleap-nn venv. Selecting mask_backend="sam3" without
transformers raises a clear, actionable ImportError pointing at this install
+ auth.
The backend is explicit — there is no default¶
mask_backend is required when you ask for SAM masks; nothing is selected
silently. "sam" is SAM1 (ungated, the sleap_nn[sam] extra); "sam3" is the
gated SAM3 image path (facebook/sam3 via transformers, the sleap_nn[sam3]
extra). Each backend stores its own raw per-model score in
PredictedSegmentationMask.score — and SAM3's score is on a lower scale than
SAM1's, so its recalibrated floor (0.5) is never SAM1's 0.88.
Predict masks for a pose .slp¶
from sleap_nn.inference.run import predict
labels = predict(
"poses.pkg.slp", # a .slp with predicted poses + image data
mask_backend="sam", # explicit, required
sam_checkpoint="/path/to/sam_vit_h_4b8939.pth",
sam_prompt_mode="pose", # "pose" | "centroid" | "box"
device="cuda",
output_path="poses_with_masks.pkg.slp",
overlay_path="review_frame0.png", # optional review overlay (PLAN L4)
)
When mask_backend is set, source is treated as a pose .slp and masks are
produced from its existing instances — no trained seg model, so you must not
also pass model_paths / export_dir.
Or call the producer directly:
from sleap_nn.inference.sam import run_sam_segmentation
labels = run_sam_segmentation(
"poses.pkg.slp",
mask_backend="sam",
prompt_mode="pose",
sam_checkpoint="/path/to/sam_vit_h_4b8939.pth",
device="cuda",
)
SAM3 backend¶
mask_backend="sam3" swaps SAM1 for Meta SAM 3's image visual-prompt path
(Sam3TrackerModel) behind the same interface and the same prompt modes:
labels = run_sam_segmentation(
"poses.pkg.slp",
mask_backend="sam3", # gated facebook/sam3, needs the [sam3] extra
prompt_mode="pose",
device="cuda",
# sam3_model_id="facebook/sam3", # the default
)
Two SAM3 specifics are handled automatically and are never shared with SAM1:
- Recalibrated score floor (
0.5). SAM3's predicted-IoU is on a lower scale, so its per-model floor (Sam3Backend.pred_iou_min) defaults to0.5(SAM1's0.88would reject ~100% of SAM3 masks as a pure calibration artifact). As with SAM1 the raw score is reported, not gated on. - Speckle cleanup. Raw SAM3 masks are fragmented (~14 connected components); each chosen mask is passed through a morphological open + close + keep-the- keypoint-connected-component cleanup (~1 component, ~97% area retained).
SAM3 also runs all instances of a frame in a single batched forward pass (SAM1 loops per instance). End-to-end SAM3 is GPU-only and needs the gated weights, so it is exercised manually / nightly; the recipe (floor, cleanup, batched call) is unit-tested against a mocked SAM3.
CLI¶
The same masks are produced from the sleap-nn predict command (and its hidden
infer alias) by passing --mask_backend. When set, the input .slp is treated
as a pose file and masks are produced from its existing instances — there is no
trained segmentation model, so --mask_backend is mutually exclusive with
--model_paths (do not pass it). The .slp output is saved like the regular
prediction path — by default images are not re-embedded, and the output
backreferences the input file itself (small output; a .pkg.slp input stays
matchable to itself, not to a pre-embedding source video that's often not on
disk), and the masks always serialize into the .slp. Only --output_format slp
is supported (the SLEAP Analysis HDF5 format stores poses/tracks, not
segmentation masks).
Controlling image embedding (--embed / --restore_source_videos)¶
Two independent flags (also embed / restore_source_videos API kwargs on
predict and run_sam_segmentation) control how the output .slp references
image data.
--embed(auto|true|false, defaultfalse): the embedding policy.falsenever embeds and backreferences the input file (default behavior);trueembeds images into a self-contained.pkg.slp-style output;autoembeds only when the input was itself an embedded.pkg.slp.--restore_source_videos/--no-restore_source_videos(default--no-restore_source_videos): on a non-embedding save, keep references to the input.pkg.slpfile(s) (default) — the pixels are already there, and the pre-embedding source video is often unavailable — or use--restore_source_videosto instead restore references to the original pre-embedding source video files, when recorded. Ignored when embedding. Maps to sleap-io'srestore_original_videos.
# Embed images into a self-contained output .pkg.slp:
sleap-nn predict -i poses.pkg.slp --mask_backend sam \
--sam_checkpoint /path/to/sam_vit_h_4b8939.pth \
--embed true -o poses_with_masks.pkg.slp
SAM1 (ungated):
sleap-nn predict \
-i poses.pkg.slp \
--mask_backend sam \
--sam_checkpoint /path/to/sam_vit_h_4b8939.pth \
--sam_prompt_mode pose \
--overlay_path review_frame0.png \
-o poses_with_masks.pkg.slp
SAM3 (gated facebook/sam3, needs the [sam3] extra):
sleap-nn predict \
-i poses.pkg.slp \
--mask_backend sam3 \
--sam3_model_id facebook/sam3 \
--sam_prompt_mode pose \
-o poses_with_masks.pkg.slp
Every flag also has a dash-spelled alias (--mask-backend, --sam-checkpoint,
--sam-model-type, --sam-prompt-mode, --sam-anchor-ind,
--sam-disjointify-masks, --sam3-model-id, --overlay-path).
Prompt modes¶
| Mode | Prompt | Needs | Notes |
|---|---|---|---|
| pose | every visible keypoint as a positive point + the padded keypoint box | a pose | cleanest; the product rule below |
| centroid | a single positive point (anchor node or the mean keypoint) | a centroid | under-covers; box kept only for candidate rejection |
| box | the padded pose box, no points | a pose | leaks between adjacent animals; secondary |
Product rule: in "pose" mode, an instance with no visible keypoints falls
back to its centroid as a single point. No negative points are used for
automatic prompting.
What gets written¶
Each instance produces one sio.PredictedSegmentationMask on
LabeledFrame.masks:
score— the raw SAM predicted-IoU of the chosen candidate (no drop-gate; low scores are surfaced, not dropped).instance/track/tracking_score— populated from the source pose when present, so a correction is referential (which instance) not positional.- full-frame masks use identity
scale/offset.
The original pose instances are retained alongside the masks (correction needs the pose).
Limitations¶
- SAM works best on compact animals (e.g. mice); it degrades on tiny / elongated ones (e.g. flies) — choose the mode per dataset, or skip SAM there.
- On extreme-low-light data a lone center point can under-segment; prefer the pose prompt when a pose exists.
- The GUI correction round-trip (predicted→user mask transition, mask editing) is upstream work; v1 is review-only.