backends
sleap_nn.inference.sam.backends
¶
SAM mask backends for prompted instance segmentation (PR-A).
A backend owns the model-specific half of mask production: loading the model,
preprocessing an image (grayscale -> CLAHE -> 3-channel), encoding it once, and
turning a list of :class:~sleap_nn.inference.sam.prompts.SamPrompt into one
boolean mask + a raw per-model score per prompt.
PR-A ships :class:SamBackend (SAM1, ViT-H, Apache-2.0, ungated; the
sleap_nn[sam] extra). PR-B adds :class:Sam3Backend (Meta SAM 3, gated
facebook/sam3 via transformers; the sleap_nn[sam3] extra). The
model-specific recipe constants (:data:SamBackend.pred_iou_min, the
candidate-rejection factor, the keypoint box margins, CLAHE) and the
candidate-selection / score helpers (:func:_pick, :func:own_containment,
:func:disjointify) are harvested from the closed #642
(sleap_nn/data/pseudomasks.py) and the exp-07 locked recipe, repurposed to
emit a raw score rather than to drive a drop-gate (PLAN §1).
Backend selection is explicit / required (PLAN L2): there is no default
mask_backend; the caller names "sam" (SAM1) or "sam3" (SAM3) and both
honor the same :class:MaskBackend interface. The heavy imports
(segment-anything / transformers) are lazy so the default sleap-nn
install never needs either.
SAM3 specifics (NEVER shared with SAM1; harvested from the closed #643): its
predicted-IoU is on a lower scale, so the per-model floor is recalibrated to
:attr:Sam3Backend.pred_iou_min (0.5, not SAM1's 0.88), and its raw
masks are speckly/fragmented, so each is passed through :func:_cleanup_speckle
(morphological open + close + keep-keypoint-component) before it is returned.
Classes:
| Name | Description |
|---|---|
MaskBackend |
Abstract prompted-mask backend (the :class: |
Sam3Backend |
SAM3 (Meta SAM 3) prompted-mask backend (the |
SamBackend |
SAM1 (ViT-H) prompted-mask backend (the |
Functions:
| Name | Description |
|---|---|
disjointify |
Make per-instance masks disjoint via keypoint-Voronoi assignment. |
own_containment |
Fraction of an instance's visible keypoints that fall inside |
MaskBackend
¶
Bases: ABC
Abstract prompted-mask backend (the :class:SamBackend / SAM3 interface).
A backend encodes one image and answers a batch of prompts on it. The
composed inference layer (:mod:sleap_nn.inference.sam.mask_layer) owns the
crop/frame geometry; the backend owns only the model call. Selection is
explicit (PLAN L2) — see :func:sleap_nn.inference.sam.get_mask_backend.
Methods:
| Name | Description |
|---|---|
masks |
Encode |
Source code in sleap_nn/inference/sam/backends.py
masks(image, prompts)
abstractmethod
¶
Encode image once and answer each prompt with a mask + raw score.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
ndarray
|
|
required |
prompts
|
Sequence[SamPrompt]
|
Per-instance prompts in image space. |
required |
Returns:
| Type | Description |
|---|---|
Tuple[List[ndarray], List[float]]
|
|
Source code in sleap_nn/inference/sam/backends.py
Sam3Backend
¶
Bases: MaskBackend
SAM3 (Meta SAM 3) prompted-mask backend (the sleap_nn[sam3] extra).
Wraps a lazily loaded transformers Sam3TrackerModel + Sam3TrackerProcessor
image visual-prompt pair. Honors the same :class:MaskBackend surface as
:class:SamBackend, but two SAM3 specifics are mandatory and NEVER shared
with SAM1 (PLAN §2.3, harvested from #643):
- Recalibrated floor. SAM3's
iou_scores(predicted-IoU) are on a LOWER scale than SAM1 (median ~0.68 vs SAM1's ~0.95). SAM1's0.88floor applied verbatim would drop ~100% of SAM3 masks as a pure calibration artifact, so the per-model :attr:pred_iou_mindefaults to0.5(~SAM1's0.88in percentile terms), never SAM1's0.88. As with SAM1 the raw chosen-candidate score is reported, not gated on. - Speckle cleanup. Raw SAM3 masks are speckly/fragmented (median ~14
connected components per mask vs SAM1's 1), with ~97% of the area in the
keypoint-connected component. The speckle is cosmetic, so each chosen mask
is passed through :func:
_cleanup_speckle(morphological open + close + keep-keypoint-component, -> median 1 component, ~97% area retained) before it is returned. Mandatory for SAM3; SAM1 masks are already solid.
Unlike SAM1's per-prompt loop, SAM3 runs all prompts for the frame in a
single batched forward pass (each prompt is one object), matching #643's
_sam3_instance_masks. The candidate selection (:func:_pick) and the
raw-score contract are identical to SAM1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
A ready |
required | |
processor
|
The matching |
required | |
device
|
str
|
Torch device the prompt tensors are moved to. |
'cuda'
|
clahe
|
bool
|
Whether to CLAHE-equalize before encoding. |
True
|
max_box_area_factor
|
float
|
Candidate-rejection factor (:func: |
1.5
|
clahe_clip_limit
|
float
|
CLAHE clip limit. |
3.0
|
clahe_tile_grid
|
Tuple[int, int]
|
CLAHE tile grid. |
(8, 8)
|
cleanup_radius
|
int
|
Speckle-cleanup morphological radius (px). |
3
|
pred_iou_min
|
float
|
Per-model nominal predicted-IoU floor (default |
0.5
|
Methods:
| Name | Description |
|---|---|
__init__ |
Stash the model/processor and the (SAM3-specific) recipe knobs. |
from_pretrained |
Build a backend by lazily loading the gated SAM3 model + processor. |
masks |
Encode |
Source code in sleap_nn/inference/sam/backends.py
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 | |
__init__(model, processor, device='cuda', clahe=True, max_box_area_factor=1.5, clahe_clip_limit=3.0, clahe_tile_grid=(8, 8), cleanup_radius=3, pred_iou_min=0.5)
¶
Stash the model/processor and the (SAM3-specific) recipe knobs.
The SAM1-shared recipe defaults match :class:SamBackend
(max_box_area_factor=1.5, clahe_clip_limit=3.0,
clahe_tile_grid=(8, 8)). The SAM3-specific defaults are
cleanup_radius=3 (the morphological open + close radius (px) for the
mandatory speckle cleanup) and pred_iou_min=0.5 (the recalibrated
floor; NEVER SAM1's 0.88, since SAM3's predicted-IoU is on a lower
scale).
Source code in sleap_nn/inference/sam/backends.py
from_pretrained(model_id='facebook/sam3', device='cuda', **kwargs)
classmethod
¶
Build a backend by lazily loading the gated SAM3 model + processor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_id
|
str
|
Hugging Face model id (default |
'facebook/sam3'
|
device
|
str
|
Torch device for the model. |
'cuda'
|
**kwargs
|
Forwarded to :class: |
{}
|
Returns:
| Type | Description |
|---|---|
'Sam3Backend'
|
A ready :class: |
Raises:
| Type | Description |
|---|---|
ImportError
|
If |
Source code in sleap_nn/inference/sam/backends.py
masks(image, prompts)
¶
Encode image once, run all prompts batched, return masks + scores.
Mirrors #643's _sam3_instance_masks: one batched forward pass over all
prompts (each prompt is an object), :func:_pick to choose a candidate,
:func:_cleanup_speckle to de-fragment, and the raw chosen predicted-IoU
as the per-mask score.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
ndarray
|
|
required |
prompts
|
Sequence[SamPrompt]
|
Per-instance :class: |
required |
Returns:
| Type | Description |
|---|---|
Tuple[List[ndarray], List[float]]
|
|
Source code in sleap_nn/inference/sam/backends.py
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 | |
SamBackend
¶
Bases: MaskBackend
SAM1 (ViT-H) prompted-mask backend (the sleap_nn[sam] extra).
Wraps a lazily loaded segment_anything.SamPredictor. For one frame:
CLAHE-equalize + 3-channel replicate, set_image once, then per prompt
call predict(..., multimask_output=True) and select via :func:_pick.
The raw SAM predicted-IoU of the chosen candidate is the mask score (PLAN
§2.3 — store the raw per-model score; no drop-gate).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predictor
|
A ready |
required | |
clahe
|
bool
|
Whether to CLAHE-equalize before encoding. |
True
|
max_box_area_factor
|
float
|
Candidate-rejection factor (:func: |
1.5
|
clahe_clip_limit
|
float
|
CLAHE clip limit. |
3.0
|
clahe_tile_grid
|
Tuple[int, int]
|
CLAHE tile grid. |
(8, 8)
|
pred_iou_min
|
float
|
Nominal predicted-IoU floor carried for parity with SAM3; SAM1 reports the raw score and does not gate on it. |
0.88
|
Methods:
| Name | Description |
|---|---|
__init__ |
Stash the predictor and the (model-specific) recipe knobs. |
from_checkpoint |
Build a backend by lazily loading a SAM checkpoint. |
masks |
Encode |
Source code in sleap_nn/inference/sam/backends.py
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | |
__init__(predictor, clahe=True, max_box_area_factor=1.5, clahe_clip_limit=3.0, clahe_tile_grid=(8, 8), pred_iou_min=0.88)
¶
Stash the predictor and the (model-specific) recipe knobs.
The recipe defaults are the locked SAM1 values (harvested from #642 /
exp-07; PLAN §1): max_box_area_factor=1.5 drops candidates whose area
exceeds 1.5 * box-area (kills SAM's over-confident whole-arena
candidate, see :func:_pick); clahe_clip_limit=3.0 /
clahe_tile_grid=(8, 8) are the CLAHE parameters applied to the
grayscale image before encoding; pred_iou_min=0.88 is SAM1's nominal
predicted-IoU floor, reported (not gated) and carried for SAM3 parity.
Source code in sleap_nn/inference/sam/backends.py
from_checkpoint(checkpoint, model_type='vit_h', device='cuda', **kwargs)
classmethod
¶
Build a backend by lazily loading a SAM checkpoint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
checkpoint
|
str
|
Path to the SAM checkpoint. |
required |
model_type
|
str
|
SAM model registry key. |
'vit_h'
|
device
|
str
|
Torch device for the model. |
'cuda'
|
**kwargs
|
Forwarded to :class: |
{}
|
Returns:
| Type | Description |
|---|---|
'SamBackend'
|
A ready :class: |
Source code in sleap_nn/inference/sam/backends.py
masks(image, prompts)
¶
Encode image once, run each prompt, return masks + raw scores.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
ndarray
|
|
required |
prompts
|
Sequence[SamPrompt]
|
Per-instance :class: |
required |
Returns:
| Type | Description |
|---|---|
Tuple[List[ndarray], List[float]]
|
|
Source code in sleap_nn/inference/sam/backends.py
disjointify(masks, kpts)
¶
Make per-instance masks disjoint via keypoint-Voronoi assignment.
Harvested verbatim from #642 _disjointify (multi-instance only). Any
pixel claimed by >=2 masks is assigned to the instance whose nearest visible
keypoint is closest, so the result is exactly disjoint and each instance
keeps its own keypoints (they are the Voronoi seeds).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
masks
|
Sequence[ndarray]
|
List of |
required |
kpts
|
Sequence[ndarray]
|
List of |
required |
Returns:
| Type | Description |
|---|---|
List[ndarray]
|
List of disjoint boolean masks (a shallow copy when uncontested). |
Source code in sleap_nn/inference/sam/backends.py
own_containment(mask, kpts, hw)
¶
Fraction of an instance's visible keypoints that fall inside mask.
Harvested from #642 _own_containment. In the inference stack this is a
score (a mask-quality signal surfaced for review), never a drop-gate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mask
|
ndarray
|
|
required |
kpts
|
ndarray
|
|
required |
hw
|
Tuple[int, int]
|
|
required |
Returns:
| Type | Description |
|---|---|
float
|
Containment in |