Views
No views yet
1import torch
2#################################### For Image ####################################
3from PIL import Image
4from sam3.model_builder import build_sam3_image_model
5from sam3.model.sam3_image_processor import Sam3Processor
6# Load the model
7model = build_sam3_image_model()
8processor = Sam3Processor(model)
9# Load an image
10image = Image.open("<YOUR_IMAGE_PATH.jpg>")
11inference_state = processor.set_image(image)
12# Prompt the model with text
13output = processor.set_text_prompt(state=inference_state, prompt="<YOUR_TEXT_PROMPT>")
14
15# Get the masks, bounding boxes, and scores
16masks, boxes, scores = output["masks"], output["boxes"], output["scores"]
17
18#################################### For Video ####################################
19
20from sam3.model_builder import build_sam3_video_predictor
21
22video_predictor = build_sam3_video_predictor()
23video_path = "<YOUR_VIDEO_PATH>" # a JPEG folder or an MP4 video file
24# Start a session
25response = video_predictor.handle_request(
26 request=dict(
27 type="start_session",
28 resource_path=video_path,
29 )
30)
31response = video_predictor.handle_request(
32 request=dict(
33 type="add_prompt",
34 session_id=response["session_id"],
35 frame_index=0, # Arbitrary frame index
36 text="<YOUR_TEXT_PROMPT>",
37 )
38)
39output = response["outputs"]1>>> from transformers import Sam3Processor, Sam3Model
2>>> import torch
3>>> from PIL import Image
4>>> import requests
5
6>>> device = "cuda" if torch.cuda.is_available() else "cpu"
7
8>>> model = Sam3Model.from_pretrained("facebook/sam3").to(device)
9>>> processor = Sam3Processor.from_pretrained("facebook/sam3")
10
11>>> # Load image
12>>> image_url = "http://images.cocodataset.org/val2017/000000077595.jpg"
13>>> image = Image.open(requests.get(image_url, stream=True).raw).convert("RGB")
14
15>>> # Segment using text prompt
16>>> inputs = processor(images=image, text="ear", return_tensors="pt").to(device)
17
18>>> with torch.no_grad():
19... outputs = model(**inputs)
20
21>>> # Post-process results
22>>> results = processor.post_process_instance_segmentation(
23... outputs,
24... threshold=0.5,
25... mask_threshold=0.5,
26... target_sizes=inputs.get("original_sizes").tolist()
27... )[0]
28
29>>> print(f"Found {len(results['masks'])} objects")
30>>> # Results contain:
31>>> # - masks: Binary masks resized to original image size
32>>> # - boxes: Bounding boxes in absolute pixel coordinates (xyxy format)
33>>> # - scores: Confidence scores1import numpy as np
2import matplotlib
3
4def overlay_masks(image, masks):
5 image = image.convert("RGBA")
6 masks = 255 * masks.cpu().numpy().astype(np.uint8)
7
8 n_masks = masks.shape[0]
9 cmap = matplotlib.colormaps.get_cmap("rainbow").resampled(n_masks)
10 colors = [
11 tuple(int(c * 255) for c in cmap(i)[:3])
12 for i in range(n_masks)
13 ]
14
15 for mask, color in zip(masks, colors):
16 mask = Image.fromarray(mask)
17 overlay = Image.new("RGBA", image.size, color + (0,))
18 alpha = mask.point(lambda v: int(v * 0.5))
19 overlay.putalpha(alpha)
20 image = Image.alpha_composite(image, overlay)
21 return image>>> overlay_masks(image, results["masks"])1>>> # Box in xyxy format: [x1, y1, x2, y2] in pixel coordinates
2>>> # Example: laptop region
3>>> box_xyxy = [100, 150, 500, 450]
4>>> input_boxes = [[box_xyxy]] # [batch, num_boxes, 4]
5>>> input_boxes_labels = [[1]] # 1 = positive box
6
7>>> inputs = processor(
8... images=image,
9... input_boxes=input_boxes,
10... input_boxes_labels=input_boxes_labels,
11... return_tensors="pt"
12... ).to(device)
13
14>>> with torch.no_grad():
15... outputs = model(**inputs)
16
17>>> # Post-process results
18>>> results = processor.post_process_instance_segmentation(
19... outputs,
20... threshold=0.5,
21... mask_threshold=0.5,
22... target_sizes=inputs.get("original_sizes").tolist()
23... )[0]1>>> # Load kitchen image
2>>> kitchen_url = "http://images.cocodataset.org/val2017/000000136466.jpg"
3>>> kitchen_image = Image.open(requests.get(kitchen_url, stream=True).raw).convert("RGB")
4
5>>> # Define two positive boxes (e.g., dial and button on oven)
6>>> # Boxes are in xyxy format [x1, y1, x2, y2] in pixel coordinates
7>>> box1_xyxy = [59, 144, 76, 163] # Dial box
8>>> box2_xyxy = [87, 148, 104, 159] # Button box
9>>> input_boxes = [[box1_xyxy, box2_xyxy]]
10>>> input_boxes_labels = [[1, 1]] # Both positive
11
12>>> inputs = processor(
13... images=kitchen_image,
14... input_boxes=input_boxes,
15... input_boxes_labels=input_boxes_labels,
16... return_tensors="pt"
17... ).to(device)
18
19>>> with torch.no_grad():
20... outputs = model(**inputs)
21
22>>> # Post-process results
23>>> results = processor.post_process_instance_segmentation(
24... outputs,
25... threshold=0.5,
26... mask_threshold=0.5,
27... target_sizes=inputs.get("original_sizes").tolist()
28... )[0]
29>>> overlay_masks(kitchen_image, results["masks"])1>>> # Segment "handle" but exclude the oven handle using a negative box
2>>> text = "handle"
3>>> # Negative box covering oven handle area (xyxy): [40, 183, 318, 204]
4>>> oven_handle_box = [40, 183, 318, 204]
5>>> input_boxes = [[oven_handle_box]]
6
7>>> inputs = processor(
8... images=kitchen_image,
9... text=text,
10... input_boxes=input_boxes,
11... input_boxes_labels=[[0]], # 0 = negative (exclude this region)
12... return_tensors="pt"
13... ).to(device)
14
15>>> with torch.no_grad():
16... outputs = model(**inputs)
17
18>>> # Post-process results
19>>> results = processor.post_process_instance_segmentation(
20... outputs,
21... threshold=0.5,
22... mask_threshold=0.5,
23... target_sizes=inputs.get("original_sizes").tolist()
24... )[0]
25>>> # This will segment pot handles but exclude the oven handle1>>> cat_url = "http://images.cocodataset.org/val2017/000000077595.jpg"
2>>> kitchen_url = "http://images.cocodataset.org/val2017/000000136466.jpg"
3>>> images = [
4... Image.open(requests.get(cat_url, stream=True).raw).convert("RGB"),
5... Image.open(requests.get(kitchen_url, stream=True).raw).convert("RGB")
6... ]
7
8>>> text_prompts = ["ear", "dial"]
9
10>>> inputs = processor(images=images, text=text_prompts, return_tensors="pt").to(device)
11
12>>> with torch.no_grad():
13... outputs = model(**inputs)
14
15>>> # Post-process results for both images
16>>> results = processor.post_process_instance_segmentation(
17... outputs,
18... threshold=0.5,
19... mask_threshold=0.5,
20... target_sizes=inputs.get("original_sizes").tolist()
21... )
22
23>>> print(f"Image 1: {len(results[0]['masks'])} objects found")
24>>> print(f"Image 2: {len(results[1]['masks'])} objects found")1>>> # Image 1: text prompt "laptop"
2>>> # Image 2: visual prompt (dial box)
3>>> box2_xyxy = [59, 144, 76, 163]
4
5>>> inputs = processor(
6... images=images,
7... text=["laptop", None], # Only first image has text
8... input_boxes=[None, [box2_xyxy]], # Only second image has box
9... input_boxes_labels=[None, [1]], # Positive box for second image
10... return_tensors="pt"
11... ).to(device)
12
13>>> with torch.no_grad():
14... outputs = model(**inputs)
15
16>>> # Post-process results for both images
17>>> results = processor.post_process_instance_segmentation(
18... outputs,
19... threshold=0.5,
20... mask_threshold=0.5,
21... target_sizes=inputs.get("original_sizes").tolist()
22... )
23>>> # Both images processed in single forward pass1>>> inputs = processor(images=image, text="ear", return_tensors="pt").to(device)
2
3>>> with torch.no_grad():
4... outputs = model(**inputs)
5
6>>> # Instance segmentation masks
7>>> instance_masks = torch.sigmoid(outputs.pred_masks) # [batch, num_queries, H, W]
8
9>>> # Semantic segmentation (single channel)
10>>> semantic_seg = outputs.semantic_seg # [batch, 1, H, W]
11
12>>> print(f"Instance masks: {instance_masks.shape}")
13>>> print(f"Semantic segmentation: {semantic_seg.shape}")1>>> from transformers import Sam3VideoModel, Sam3VideoProcessor
2>>> from accelerate import Accelerator
3>>> import torch
4
5>>> device = Accelerator().device
6>>> model = Sam3VideoModel.from_pretrained("facebook/sam3").to(device, dtype=torch.bfloat16)
7>>> processor = Sam3VideoProcessor.from_pretrained("facebook/sam3")
8
9>>> # Load video frames
10>>> from transformers.video_utils import load_video
11>>> video_url = "https://huggingface.co/datasets/hf-internal-testing/sam2-fixtures/resolve/main/bedroom.mp4"
12>>> video_frames, _ = load_video(video_url)
13
14>>> # Initialize video inference session
15>>> inference_session = processor.init_video_session(
16... video=video_frames,
17... inference_device=device,
18... processing_device="cpu",
19... video_storage_device="cpu",
20... dtype=torch.bfloat16,
21... )
22
23>>> # Add text prompt to detect and track objects
24>>> text = "person"
25>>> inference_session = processor.add_text_prompt(
26... inference_session=inference_session,
27... text=text,
28... )
29
30>>> # Process all frames in the video
31>>> outputs_per_frame = {}
32>>> for model_outputs in model.propagate_in_video_iterator(
33... inference_session=inference_session, max_frame_num_to_track=50
34... ):
35... processed_outputs = processor.postprocess_outputs(inference_session, model_outputs)
36... outputs_per_frame[model_outputs.frame_idx] = processed_outputs
37
38>>> print(f"Processed {len(outputs_per_frame)} frames")
39Processed 51 frames
40
41>>> # Access results for a specific frame
42>>> frame_0_outputs = outputs_per_frame[0]
43>>> print(f"Detected {len(frame_0_outputs['object_ids'])} objects")
44>>> print(f"Object IDs: {frame_0_outputs['object_ids'].tolist()}")
45>>> print(f"Scores: {frame_0_outputs['scores'].tolist()}")
46>>> print(f"Boxes shape (XYXY format, absolute coordinates): {frame_0_outputs['boxes'].shape}")
47>>> print(f"Masks shape: {frame_0_outputs['masks'].shape}")1>>> # Initialize session for streaming
2>>> streaming_inference_session = processor.init_video_session(
3... inference_device=device,
4... processing_device="cpu",
5... video_storage_device="cpu",
6... dtype=torch.bfloat16,
7... )
8
9>>> # Add text prompt
10>>> text = "person"
11>>> streaming_inference_session = processor.add_text_prompt(
12... inference_session=streaming_inference_session,
13... text=text,
14... )
15
16>>> # Process frames one by one (streaming mode)
17>>> streaming_outputs_per_frame = {}
18>>> for frame_idx, frame in enumerate(video_frames[:50]): # Process first 50 frames
19... # First, process the frame using the processor
20... inputs = processor(images=frame, device=device, return_tensors="pt")
21...
22... # Process frame using streaming inference - pass the processed pixel_values
23... model_outputs = model(
24... inference_session=streaming_inference_session,
25... frame=inputs.pixel_values[0], # Provide processed frame - this enables streaming mode
26... reverse=False,
27... )
28...
29... # Post-process outputs with original_sizes for proper resolution handling
30... processed_outputs = processor.postprocess_outputs(
31... streaming_inference_session,
32... model_outputs,
33... original_sizes=inputs.original_sizes, # Required for streaming inference
34... )
35... streaming_outputs_per_frame[frame_idx] = processed_outputs
36...
37... if (frame_idx + 1) % 10 == 0:
38... print(f"Processed {frame_idx + 1} frames...")
39
40>>> print(f"✓ Streaming inference complete! Processed {len(streaming_outputs_per_frame)} frames")
41✓ Streaming inference complete! Processed 50 frames
42
43>>> # Access results
44>>> frame_0_outputs = streaming_outputs_per_frame[0]
45>>> print(f"Detected {len(frame_0_outputs['object_ids'])} objects in first frame")
46>>> print(f"Boxes are in XYXY format (absolute pixel coordinates): {frame_0_outputs['boxes'].shape}")
47>>> print(f"Masks are at original video resolution: {frame_0_outputs['masks'].shape}")1>>> from transformers import pipeline
2
3>>> generator = pipeline("mask-generation", model="facebook/sam3", device=0)
4>>> image_url = "https://huggingface.co/datasets/hf-internal-testing/sam2-fixtures/resolve/main/truck.jpg"
5>>> outputs = generator(image_url, points_per_batch=64)
6
7>>> len(outputs["masks"]) # Number of masks generated1>>> from transformers import Sam3TrackerProcessor, Sam3TrackerModel
2>>> from accelerate import Accelerator
3>>> import torch
4>>> from PIL import Image
5>>> import requests
6
7>>> device = Accelerator().device
8
9>>> model = Sam3TrackerModel.from_pretrained("facebook/sam3").to(device)
10>>> processor = Sam3TrackerProcessor.from_pretrained("facebook/sam3")
11
12>>> image_url = "https://huggingface.co/datasets/hf-internal-testing/sam2-fixtures/resolve/main/truck.jpg"
13>>> raw_image = Image.open(requests.get(image_url, stream=True).raw).convert("RGB")
14
15>>> input_points = [[[[500, 375]]]] # Single point click, 4 dimensions (image_dim, object_dim, point_per_object_dim, coordinates)
16>>> input_labels = [[[1]]] # 1 for positive click, 0 for negative click, 3 dimensions (image_dim, object_dim, point_label)
17
18>>> inputs = processor(images=raw_image, input_points=input_points, input_labels=input_labels, return_tensors="pt").to(model.device)
19
20>>> with torch.no_grad():
21... outputs = model(**inputs)
22
23>>> masks = processor.post_process_masks(outputs.pred_masks.cpu(), inputs["original_sizes"])[0]
24
25>>> # The model outputs multiple mask predictions ranked by quality score
26>>> print(f"Generated {masks.shape[1]} masks with shape {masks.shape}")1>>> # Add both positive and negative points to refine the mask
2>>> input_points = [[[[500, 375], [1125, 625]]]] # Multiple points for refinement
3>>> input_labels = [[[1, 1]]] # Both positive clicks
4
5>>> inputs = processor(images=raw_image, input_points=input_points, input_labels=input_labels, return_tensors="pt").to(device)
6
7>>> with torch.no_grad():
8... outputs = model(**inputs)
9
10>>> masks = processor.post_process_masks(outputs.pred_masks.cpu(), inputs["original_sizes"])[0]1>>> # Define bounding box as [x_min, y_min, x_max, y_max]
2>>> input_boxes = [[[75, 275, 1725, 850]]]
3
4>>> inputs = processor(images=raw_image, input_boxes=input_boxes, return_tensors="pt").to(device)
5
6>>> with torch.no_grad():
7... outputs = model(**inputs)
8
9>>> masks = processor.post_process_masks(outputs.pred_masks.cpu(), inputs["original_sizes"])[0]1>>> # Define points for two different objects
2>>> input_points = [[[[500, 375]], [[650, 750]]]] # Points for two objects in same image
3>>> input_labels = [[[1], [1]]] # Positive clicks for both objects
4
5>>> inputs = processor(images=raw_image, input_points=input_points, input_labels=input_labels, return_tensors="pt").to(model.device)
6
7>>> with torch.no_grad():
8... outputs = model(**inputs, multimask_output=False)
9
10>>> # Each object gets its own mask
11>>> masks = processor.post_process_masks(outputs.pred_masks.cpu(), inputs["original_sizes"])[0]
12>>> print(f"Generated masks for {masks.shape[0]} objects")
13Generated masks for 2 objects1>>> # Load multiple images
2>>> image_urls = [
3... "https://huggingface.co/datasets/hf-internal-testing/sam2-fixtures/resolve/main/truck.jpg",
4... "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/dog-sam.png"
5... ]
6>>> raw_images = [Image.open(requests.get(url, stream=True).raw).convert("RGB") for url in image_urls]
7
8>>> # Single point per image
9>>> input_points = [[[[500, 375]]], [[[770, 200]]]] # One point for each image
10>>> input_labels = [[[1]], [[1]]] # Positive clicks for both images
11
12>>> inputs = processor(images=raw_images, input_points=input_points, input_labels=input_labels, return_tensors="pt").to(model.device)
13
14>>> with torch.no_grad():
15... outputs = model(**inputs, multimask_output=False)
16
17>>> # Post-process masks for each image
18>>> all_masks = processor.post_process_masks(outputs.pred_masks.cpu(), inputs["original_sizes"])
19>>> print(f"Processed {len(all_masks)} images, each with {all_masks[0].shape[0]} objects")1>>> from transformers import Sam3TrackerVideoModel, Sam3TrackerVideoProcessor
2>>> from accelerate import Accelerator
3>>> import torch
4
5>>> device = Accelerator().device
6>>> model = Sam3TrackerVideoModel.from_pretrained("facebook/sam3").to(device, dtype=torch.bfloat16)
7>>> processor = Sam3TrackerVideoProcessor.from_pretrained("facebook/sam3")
8
9>>> # Load video frames
10>>> from transformers.video_utils import load_video
11>>> video_url = "https://huggingface.co/datasets/hf-internal-testing/sam2-fixtures/resolve/main/bedroom.mp4"
12>>> video_frames, _ = load_video(video_url)
13
14>>> # Initialize video inference session
15>>> inference_session = processor.init_video_session(
16... video=video_frames,
17... inference_device=device,
18... dtype=torch.bfloat16,
19... )
20
21>>> # Add click on first frame to select object
22>>> ann_frame_idx = 0
23>>> ann_obj_id = 1
24>>> points = [[[[210, 350]]]]
25>>> labels = [[[1]]]
26
27>>> processor.add_inputs_to_inference_session(
28... inference_session=inference_session,
29... frame_idx=ann_frame_idx,
30... obj_ids=ann_obj_id,
31... input_points=points,
32... input_labels=labels,
33... )
34
35>>> # Segment the object on the first frame (optional, you can also propagate the masks through the video directly)
36>>> outputs = model(
37... inference_session=inference_session,
38... frame_idx=ann_frame_idx,
39... )
40>>> video_res_masks = processor.post_process_masks(
41... [outputs.pred_masks], original_sizes=[[inference_session.video_height, inference_session.video_width]], binarize=False
42... )[0]
43>>> print(f"Segmentation shape: {video_res_masks.shape}")
44Segmentation shape: torch.Size([1, 1, 480, 854])
45
46>>> # Propagate through the entire video
47>>> video_segments = {}
48>>> for sam3_tracker_video_output in model.propagate_in_video_iterator(inference_session):
49... video_res_masks = processor.post_process_masks(
50... [sam3_tracker_video_output.pred_masks], original_sizes=[[inference_session.video_height, inference_session.video_width]], binarize=False
51... )[0]
52... video_segments[sam3_tracker_video_output.frame_idx] = video_res_masks
53
54>>> print(f"Tracked object through {len(video_segments)} frames")
55Tracked object through 180 frames1>>> # Reset for new tracking session
2>>> inference_session.reset_inference_session()
3
4>>> # Add multiple objects on the first frame
5>>> ann_frame_idx = 0
6>>> obj_ids = [2, 3]
7>>> input_points = [[[[200, 300]], [[400, 150]]]] # Points for two objects (batched)
8>>> input_labels = [[[1], [1]]]
9
10>>> processor.add_inputs_to_inference_session(
11... inference_session=inference_session,
12... frame_idx=ann_frame_idx,
13... obj_ids=obj_ids,
14... input_points=input_points,
15... input_labels=input_labels,
16... )
17
18>>> # Get masks for both objects on first frame (optional, you can also propagate the masks through the video directly)
19>>> outputs = model(
20... inference_session=inference_session,
21... frame_idx=ann_frame_idx,
22... )
23
24>>> # Propagate both objects through video
25>>> video_segments = {}
26>>> for sam3_tracker_video_output in model.propagate_in_video_iterator(inference_session):
27... video_res_masks = processor.post_process_masks(
28... [sam3_tracker_video_output.pred_masks], original_sizes=[[inference_session.video_height, inference_session.video_width]], binarize=False
29... )[0]
30... video_segments[sam3_tracker_video_output.frame_idx] = {
31... obj_id: video_res_masks[i]
32... for i, obj_id in enumerate(inference_session.obj_ids)
33... }
34
35>>> print(f"Tracked {len(inference_session.obj_ids)} objects through {len(video_segments)} frames")
36Tracked 2 objects through 180 frames1>>> # Initialize session for streaming
2>>> inference_session = processor.init_video_session(
3... inference_device=device,
4... dtype=torch.bfloat16,
5... )
6
7>>> # Process frames one by one
8>>> for frame_idx, frame in enumerate(video_frames[:10]): # Process first 10 frames
9... inputs = processor(images=frame, device=device, return_tensors="pt")
10...
11... if frame_idx == 0:
12... # Add point input on first frame
13... processor.add_inputs_to_inference_session(
14... inference_session=inference_session,
15... frame_idx=0,
16... obj_ids=1,
17... input_points=[[[[210, 350], [250, 220]]]],
18... input_labels=[[[1, 1]]],
19... original_size=inputs.original_sizes[0], # need to be provided when using streaming video inference
20... )
21...
22... # Process current frame
23... sam3_tracker_video_output = model(inference_session=inference_session, frame=inputs.pixel_values[0])
24...
25... video_res_masks = processor.post_process_masks(
26... [sam3_tracker_video_output.pred_masks], original_sizes=inputs.original_sizes, binarize=False
27... )[0]
28... print(f"Frame {frame_idx}: mask shape {video_res_masks.shape}")