Skip to main content

SegProbe

SegProbe makes box-prompt experiments reproducible across medical image segmentation models. It generates prompt protocols, records the manual effort, and evaluates the resulting masks through one small API.

SegProbe overview

It started as code i used while testing MedSAM. i wanted to answer simple questions without rewriting the evaluation each time:

  • How many boxes must be drawn manually?
  • What happens if boxes are sparse, larger, or slightly misplaced?
  • Can the same protocol be compared across different models?

SegProbe has one runtime dependency: NumPy. It does not download a model or a dataset.

Install

python -m pip install segprobe

For development, install it from a local clone:

python -m pip install -e .

Quick start

from segprobe import evaluate, sparse_boxes

plan = sparse_boxes(target_mask, every=3, padding=5)

def predictor(volume, z_index, box_xyxy):
    image_slice = volume[z_index]
    return my_model.predict(image_slice, box=box_xyxy)

result = evaluate(predictor, image_volume, target_mask, plan)

print(result.dice)
print(result.manual_boxes)
print(result.generated_boxes)

The predictor function is the only model-specific part. It can call MedSAM, SAM2, nnInteractive, or your own slice-based model.

Prompt protocols

from segprobe import global_box, slice_boxes, sparse_boxes

dense = slice_boxes(mask, padding=5)
global_prompt = global_box(mask, padding=5)
sparse = sparse_boxes(mask, every=3, padding=5)
Protocol Manual effort Boxes sent to the model
slice_boxes one per positive slice one manual box on each slice
global_box one per volume the same box reused on all positive slices
sparse_boxes one every N positive slices, plus the last manual anchors and interpolated boxes

Each plan reports manual_boxes, generated_boxes, and manual_fraction. plan.to_dict() returns the boxes and protocol parameters as plain Python values ready for JSON. PromptPlan.from_dict() restores the same plan later.

Interpolate boxes you already have

You do not need a reference mask if the boxes were drawn manually or produced by another tool:

from segprobe import interpolate_boxes

plan = interpolate_boxes(
    {
        10: (40, 50, 90, 100),
        20: (45, 55, 96, 108),
    },
    shape_zyx=(30, 512, 512),
)

By default, this returns one box on every slice from the first anchor to the last. Pass slices=[10, 12, 14, 16, 18, 20] to generate boxes only on selected slices. The anchors stay marked as manual and the interpolated boxes as generated.

Sparse prompts

Here, only five boxes are drawn manually. The other fifteen are interpolated.

Sparse box interpolation through a CT volume

Blue boxes are manual anchors. Orange dashed boxes are generated between them. The green line is the reference-mask contour.

Prompt robustness

Box size and placement can change a promptable model's result. SegProbe can add padding or apply deterministic perturbations, so the same stress test can be run again with the same seed. A non-empty sample_key keeps the perturbations different across cases, and the sampled box always overlaps its source box.

from segprobe import jitter_plan

noisy = jitter_plan(
    dense,
    max_translate=5,
    max_expand=10,
    seed=42,
    sample_key="case-001",
)

Box size, translation, and expansion

Public MedSAM example

examples/medsam_lidc.py connects SegProbe to the official MedSAM ViT-B model. It expects one folder per case containing image.nii.gz and mask.nii.gz.

Run it from an environment where MedSAM, PyTorch, NiBabel, and scikit-image are available:

python examples/medsam_lidc.py \
  --cases-root /path/to/lidc_crops \
  --one-per-patient \
  --limit 5 \
  --medsam-repo /path/to/MedSAM \
  --checkpoint /path/to/medsam_vit_b.pth \
  --output-dir medsam_results \
  --device cpu

The script saves results.csv and results.json after every protocol. Running the same command again resumes from the saved results.

We used it for a small public check with five LIDC-IDRI nodules, one per patient. The run used the official MedSAM checkpoint, no private fine-tuning, no postprocessing, and an oracle positive z-range from the reference mask.

Prompt density with padding=5

Protocol Mean manual boxes Mean generated boxes Mean Dice ± SD
Global 1.0 16.0 0.372 ± 0.173
Sparse every 5 slices 4.4 12.6 0.515 ± 0.267
Sparse every 3 slices 7.0 10.0 0.508 ± 0.270
Sparse every 2 slices 9.2 7.8 0.510 ± 0.270
Dense 17.0 0.0 0.511 ± 0.271

In this small run, sparse prompting every five slices used about 74% fewer manual boxes than dense prompting, with nearly the same mean Dice.

Dense prompt geometry

Box Mean Dice ± SD
Tight, padding=0 0.843 ± 0.031
padding=5 0.511 ± 0.271
Large, padding=10 0.310 ± 0.224
padding=5 with deterministic jitter 0.363 ± 0.263

The tight box is derived directly from the reference mask, so it is a strong oracle prompt. These five cases are a reproducibility example, not a model comparison or a clinical result.

Inputs and image formats

SegProbe works with arrays, not a specific medical file format. CT, MRI, PET, and other 3D images can use the same API after they are loaded into NumPy.

  • The mask must have shape (z, y, x).
  • The image must start with the same dimensions: (z, y, x) or (z, y, x, channels).
  • Boxes use (x_min, y_min, x_max, y_max), with exclusive maximum coordinates.

NIfTI, DICOM, NRRD, and other files can be loaded with tools such as NiBabel, SimpleITK, or pydicom. File loading stays outside SegProbe so the core package remains small and does not impose an imaging stack.

Evaluation output

evaluate returns the predicted 3D mask together with:

  • Dice and IoU;
  • target and prediction voxel counts;
  • manual and generated box counts;
  • number of prompted slices.

The scalar values are available with result.to_dict() for a CSV or JSON report.

Scope

The mask-based prompt generators are made for controlled oracle-prompt evaluation, not automatic lesion localization. interpolate_boxes can instead use boxes supplied directly by a reader, detector, or annotation tool.

With the mask-based generators, only reference-positive slices receive a box, so the positive z-range is known. Those results should be described as prompt-effort or prompt-robustness experiments, not end-to-end detection results.

The manual-box count is an effort proxy. It is not a measurement of annotation time. SegProbe is a research evaluation tool and is not intended for clinical decision-making.

Development

python -m pip install -e ".[dev]"
ruff check .
pytest -q
python -m build

Tests use small synthetic masks. They do not download images, checkpoints, or patient data.

Citation

If SegProbe supports your work, please cite the software using CITATION.cff.

The images in this README use a cropped, windowed, and annotated case from the public LIDC-IDRI collection:

Armato III, S. G., McLennan, G., Bidaut, L., et al. (2015). Data From LIDC-IDRI. The Cancer Imaging Archive. https://doi.org/10.7937/K9/TCIA.2015.LO9QL9SX

LIDC-IDRI is available under the Creative Commons Attribution 3.0 license.

License

SegProbe is released under the Apache-2.0 license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

segprobe-0.1.1.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

segprobe-0.1.1-py3-none-any.whl (15.2 kB view details)

Uploaded Python 3

File details

Details for the file segprobe-0.1.1.tar.gz.

File metadata

  • Download URL: segprobe-0.1.1.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for segprobe-0.1.1.tar.gz
Algorithm Hash digest
SHA256 977bd727727664013ccb15f33995a08e6853599ab8e6a353bd3c9a9874043bad
MD5 2d2e1f7f241dce926c05c720d0c5af03
BLAKE2b-256 77d8f9685061d86e90c557a0d7997891e6a938496b5e9c635227f1088c69db65

See more details on using hashes here.

Provenance

The following attestation bundles were made for segprobe-0.1.1.tar.gz:

Publisher: release.yml on hajteyib/segprobe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file segprobe-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: segprobe-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 15.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for segprobe-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 287741e78cb14913d3046ed1f84f2d4bbd4b9915001185318d70dbf5ad543a34
MD5 7355d14b73c7c0a7d44c1676e3414b2b
BLAKE2b-256 e8c02e0df297ef5bc286ed47c0320b5f9363b7dc32e882452ca053e4b924f11f

See more details on using hashes here.

Provenance

The following attestation bundles were made for segprobe-0.1.1-py3-none-any.whl:

Publisher: release.yml on hajteyib/segprobe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page