Files
wehub-resource-sync 3a2c66702c
Tests on CPU (scheduled) / check-skip (push) Has been cancelled
Tests on CPU (scheduled) / pre-tests (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-ubuntu (float32) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-ubuntu (float64) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.11, float32, 2.5.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.11, float32, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.11, float64, 2.5.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.11, float64, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.12, float32, 2.5.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.12, float32, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.12, float64, 2.5.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.12, float64, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.13, float32, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-windows (3.13, float64, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-mac (3.11, float32, 2.5.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-mac (3.11, float32, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-mac (3.12, float32, 2.5.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-mac (3.12, float32, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / tests-cpu-mac (3.13, float32, 2.9.1) (push) Has been cancelled
Tests on CPU (scheduled) / coverage (push) Has been cancelled
Tests on CPU (scheduled) / typing (push) Has been cancelled
Tests on CPU (scheduled) / tutorials (push) Has been cancelled
Tests on CPU (scheduled) / docs (push) Has been cancelled
Lint / TOML Format (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:49:27 +08:00

310 lines
13 KiB
ReStructuredText

Segment Anything (SAM)
======================
The Segment Anything Model (SAM) produces high quality object masks from input prompts such as points or boxes, and it
can be used to generate masks for all objects in an image.
.. card::
:link: https://segment-anything.com/
**Segment Anything**
^^^
**Abstract:** We introduce the Segment Anything (SAM) project: a new task, model, and dataset for image
segmentation. Using our efficient model in a data collection loop, we built the largest segmentation
dataset to date (by far), with over 1 billion masks on 11M licensed and privacy respecting images. The
model is designed and trained to be promptable, so it can transfer zero-shot to new image distributions
and tasks. We evaluate its capabilities on numerous tasks and find that its zero-shot performance is impressive
-- often competitive with or even superior to prior fully supervised results. We are releasing the Segment Anything
Model (SAM) and corresponding dataset (SA-1B) of 1B masks and 11M images at https://segment-anything.com to foster
research into foundation models for computer vision.
**Tasks:** Segmentation
**Datasets:** SA-1B
**Licence:** Apache
+++
**Authors:** Alexander Kirillov and Eric Mintun and Nikhila Ravi and Hanzi Mao and Chloe Rolland and Laura
Gustafson and Alex Berg and Wan-Yen Lo and Piotr Dollar and Ross Girshick
How to use SAM from Kornia
--------------------------
The Kornia API for SAM try to provide a simple API to access initialize the model and load/download the weights. Also,
providing it to a high-level API called :code:`VisualPrompter`, which allow the users to set an image and run multiple
queries multiple times.
The :code:`VisualPrompter` works querying on a single image, if you want to explore and query into a batch of images,
you can use the :code:`Sam` directly. But, for it you will need to write the boilerplate to preprocess and postprocess to
use it. This boilerplate, is already handle on the high-level API :code:`VisualPrompter`.
Visual Prompter
^^^^^^^^^^^^^^^
.. _anchor Prompter:
The High level API :code:`VisualPrompter` handle with the image and prompt transformation, preprocessing and prediction for
a given SAM model.
About the :code:`VisualPrompter`:
#. From a `ModelConfig` loads the desired model with the desired checkpoint to be used as the model to receive the query
prompts. For know we just support Segment Anything model, where the *SAM-h* is the default option.
#. Based on the model, the :code:`VisualPrompter` will handle with the necessary transformations to be done into the image
and prompts before apply it to the model. These transformations are done using PyTorch backed, by our API of
augmentations. Where we use the :class:`kornia.geometry.augmentation.AugmentationSequential` to handle with the different
data formats (keypoints, boxes, masks, image).
#. When you use :code:`prompter.set_image(...)`, the prompter will preprocess this image, then pass it to the encoder,
and cache the embeddings to query it after. Note that the image should be scaled within the range [0,1].
* The preprocess steps are: 1) Resize the image to have its longer side the same size as :code:`image_encoder` image size
input. 2) Cache the information of this transformation to apply into the prompts. 3) normalize the image based on the
passed mean and standard deviation, or with the values of the SAM dataset. 4) pad on the bottom and right for the image
have the encoder expected resolution: :math:`(\text{image_encoder.img_size}, \text{image_encoder.img_size})`.
* The best image to be used will always have the shape equals to
:math:`(\text{image_encoder.img_size}, \text{image_encoder.img_size})`.
#. When you use :code:`prompter.predict(...)`, the prompter will apply the cached transformations on the coordinates of the
prompts, and then query this prompts into the cached embeddings.
* If :code:`output_original_size=True`, the results structure will upsample the logits from it's resolution into the
image input original resolution. The output logits has the height and width equals to 256.
#. You can benefit from using the :code:`torch.compile(...)` API (dynamo) for torch >= 2.0.0 version. To compile with dynamo
we provide the method :code:`prompter.compile(...)` which will optimize the right parts of the backend model and the
prompter itself.
--------------
Example of using the :code:`VisualPrompter`:
Exploring how to simple initialize the :code:`VisualPrompter`, automatically load the weights from a URL,
read the image and set it to be query, how to write the prompts, and the multiple ways we can use these prompts
to query the image masks from the SAM model.
.. code-block:: python
import torch
from kornia.models.sam import SamConfig
from kornia.contrib.visual_prompter import VisualPrompter
from kornia.io import load_image, ImageLoadType
from kornia.geometry.keypoints import Keypoints
from kornia.geometry.boxes import Boxes
from kornia.core.utils import get_cuda_or_mps_device_if_available
model_type = 'vit_h'
checkpoint = './https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth'
device = get_cuda_or_mps_device_if_available
# Load image
image = load_image('./example.jpg', ImageLoadType.RGB32, device)
# Define the model config
config = SamConfig(model_type, checkpoint)
# Load the prompter
prompter = VisualPrompter(config, device=device)
# You can use torch dynamo/compile API with:
# prompter.compile()
# set the image: This will preprocess the image and already generate the embeddings of it
prompter.set_image(image)
# Generate the prompts
keypoints = Keypoints(torch.tensor([[[500, 375]]], device=device, dtype=torch.float32)) # BxNx2
# For the keypoints label: 1 indicates a foreground point; 0 indicates a background point
keypoints_labels = torch.tensor([[1]], device=device) # BxN
boxes = Boxes(
torch.tensor([[[[425, 600], [425, 875], [700, 600], [700, 875]]]], device=device, dtype=torch.float32), mode='xyxy'
)
# Runs the prediction with all prompts
prediction = prompter.predict(
keypoints=keypoints,
keypoints_labels=keypoints_labels,
boxes=boxes,
multimask_output=True,
)
#----------------------------------------------
# or run the prediction with just the keypoints
prediction = prompter.predict(
keypoints=keypoints,
keypoints_labels=keypoints_labels,
multimask_output=True,
)
#----------------------------------------------
# or run the prediction with just the box
prediction = prompter.predict(
boxes=boxes,
multimask_output=True,
)
#----------------------------------------------
# or run the prediction without prompts
prediction = prompter.predict(
multimask_output=True,
)
#------------------------------------------------
# or run the prediction using the previous logits
prediction = prompter.predict(
masks=prediction.logits
multimask_output=True,
)
# The `prediction` is a SegmentationResults dataclass with the masks, scores and logits
print(prediction.masks.shape)
print(prediction.scores)
print(prediction.logits.shape)
Read more about the :code:`SegmentationResults` on :ref:`the official docs<anchor SegmentationResults>`
Load from config
^^^^^^^^^^^^^^^^
You can build a SAM model by specifying the encoder parameters on the :code:`SamConfig`, or from the model type. The
:code:`from_config` method will first try to build the model based on the model type, otherwise will try from the specified
parameters. If a checkpoint URL or path for a file is seted, the method will automatically load it.
.. code-block:: python
from kornia.models.sam import Sam, SamConfig
from kornia.core.utils import get_cuda_or_mps_device_if_available
# model_type can be:
# 0, 'vit_h' or `kornia.models.sam.SamModelType.vit_h`
# 1, 'vit_l' or `kornia.models.sam.SamModelType.vit_l`
# 2, 'vit_b' or `kornia.models.sam.SamModelType.vit_b`
model_type = 'vit_b'
# The checkpoint can be a filepath or a url
checkpoint = './path_for_the_model_checkpoint.pth'
device = get_cuda_or_mps_device_if_available()
# Load config
config = SamConfig(model_type, checkpoint)
# Load the model with checkpoint
sam_model = Sam.from_config(config)
# Move to desired device
sam_model = sam_model.to(device)
Load checkpoint
^^^^^^^^^^^^^^^
With the load checkpoint method you can load from a file or directly from a URL. The official (by meta) model weights are:
#. `vit_h`: `ViT-H SAM model - https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth <https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth>`_.
#. `vit_l`: `ViT-L SAM model - https://dl.fbaipublicfiles.com/segment_anything/sam_vit_l_0b3195.pth <https://dl.fbaipublicfiles.com/segment_anything/sam_vit_l_0b3195.pth>`_.
#. `vit_b`: `ViT-B SAM model - https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth <https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth>`_.
If a URL is passed the model will automatically download and cache the weights using
:code:`torch.hub.load_state_dict_from_url`
.. code-block:: python
from kornia.models.sam import Sam, SamConfig
from kornia.core.utils import get_cuda_or_mps_device_if_available
model_type = 'vit_b'
# The checkpoint can be a filepath or a url
checkpoint = './path_for_the_model_checkpoint.pth'
device = get_cuda_or_mps_device_if_available()
# Load/build the model
sam_model = Sam.from_config(SamConfig(model_type))
# Load the checkpoint
sam_model.load_checkpoint(checkpoint, device)
.. Mask Generator
.. ^^^^^^^^^^^^^^
Example of how to use the SAM model without API
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is a simple example, of how to directly use the SAM model loaded. We recommend the use of
:ref:`Prompter API<anchor Prompter>` to handle/prepare the inputs.
.. code-block:: python
from kornia.models.sam import Sam
from kornia.models.structures import SegmentationResults
from kornia.io import load_image, ImageLoadType
from kornia.core.utils import get_cuda_or_mps_device_if_available
from kornia.geometry import resize
from kornia.enhance import normalize
model_type = 'vit_b' # or can be a number `2` or the enum sam.SamModelType.vit_b
checkpoint_path = './path_for_the_model_checkpoint.pth'
device = get_cuda_or_mps_device_if_available()
# Load the model
sam_model = Sam.from_pretrained(model_type, checkpoint_path, device)
# Load image
image = load_image('./example.jpg', ImageLoadType.RGB32, device)
# Transform the image (CxHxW) into a batched input (BxCxHxW)
image = image[None, ...]
# Resize the image to have the maximum size 1024 on its largest side
data = resize(image, 1024, side='long')
# Embed prompts -- ATTENTION: should match the coordinates after the resize of the image
sparse_embeddings, dense_embeddings = sam_model.prompt_encoder(points=None, boxes=None, masks=None)
# define the info for normalize the input
pixel_mean = torch.tensor(...)
pixel_std = torch.tensor(...)
# Preprocess input
data = normalize(data, pixel_mean, pixel_std)
padh = model_sam.image_encoder.img_size - h
padw = model_sam.image_encoder.img_size - w
data = pad(data, (0, padw, 0, padh))
#--------------------------------------------------------------------
# Option A: Manually calling each API
#--------------------------------------------------------------------
low_res_logits, iou_predictions = sam_model.mask_decoder(
image_embeddings=sam_model.image_encoder(data),
image_pe=sam_model.prompt_encoder.get_dense_pe(),
sparse_prompt_embeddings=sparse_embeddings,
dense_prompt_embeddings=dense_embeddings,
multimask_output=True,
)
prediction = SegmentationResults(low_res_logits, iou_predictions)
#--------------------------------------------------------------------
# Option B: Calling the model itself
#--------------------------------------------------------------------
prediction = sam_model(data[None, ...], [{}], multimask_output=True)
#--------------------------------------------------------------------
# Post processing
#--------------------------------------------------------------------
# Upscale the masks to the original image resolution
input_size = (data.shape[-2], data.shape[-1])
original_size = (image.shape[-2], image.shape[-1])
image_size_encoder = (model_sam.image_encoder.img_size, model_sam.image_encoder.img_size)
prediction.original_res_logits(input_size, original_size, image_size_encoder)
# If wants to check the binary masks
masks = prediction.binary_masks