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
310 lines
13 KiB
ReStructuredText
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
|