facebookresearch / facebookresearch/sam3

Produce incomplete mask when an object split into 2 parts over time

Open
#381 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
Python
Stars
11.7k
Forks
1.8k
PR merge metrics
No merged PRs in 30d

Description

Thx for your excellent work!
I tried to segment the headset in a video. At the beginning, SAM3 segments the handset very well, where the handset appears as a single connected mask region. However, as time progresses and the man raises his head, the handset mask should become two disconnected left and right parts, yet SAM3 only segments one of them. I would like to know whether this behavior is related to SAM3’s tracking logic.

https://github.com/user-attachments/assets/ab013e88-3683-4c5a-a568-4af9465ba820

My code:
```
import os
import cv2
import pdb
from typing import Optional, List, Tuple
import numpy as np

# import av # pip install av
from tqdm import tqdm

from sam3.model_builder import build_sam3_video_predictor
from sam3.visualization_utils import render_masklet_frame, save_masklet_video

def read_video_frames_and_fps_cv2(
video_path: str,
to_rgb: bool = True,
fallback_fps: float = 24.0,
dtype: np.dtype = np.uint8,
) -> Tuple[List[np.ndarray], float]:
"""
Read all frames and FPS from a video using OpenCV.

Returns:
frames: List[np.ndarray], each with shape (H, W, 3)
fps: float
"""
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise RuntimeError(f"Cannot open video: {video_path}")

# ---- get fps ----
fps = cap.get(cv2.CAP_PROP_FPS)
if fps is None or fps <= 1e-3 or np.isnan(fps):
print(f"[Warning] Failed to read FPS from video, fallback to {fallback_fps}")
fps = fallback_fps
fps = float(round(fps))

frames: List[np.ndarray] = []

try:
while True:
ok, frame_bgr = cap.read()
if not ok:
break

if to_rgb:
frame = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
else:
frame = frame_bgr

if frame.dtype != dtype:
frame = frame.astype(dtype, copy=False)

frames.append(frame)
finally:
cap.release()

if len(frames) == 0:
raise RuntimeError(f"No frames decoded from: {video_path}")

return frames, fps

def sam3_overlay_video_official(video_path, prompt, out_path, checkpoint_path="checkpoint/sam3.pt",
prompt_frame_index=0, alpha=0.5, video_frames = None, fps=24.0):
predictor = build_sam3_video_predictor(checkpoint_path=checkpoint_path)

# 1) start session
resp = predictor.handle_request(dict(type="start_session", resource_path=video_path))
session_id = resp["session_id"]

# 2) add prompt once (anchor frame)
predictor.handle_request(dict(
type="add_prompt",
session_id=session_id,
frame_index=prompt_frame_index,
text=prompt
))

# pdb.set_trace()

# 3) propagate over video => collect outputs per frame
frame_to_outputs = {}
multiframes_results = predictor.handle_stream_request(dict(
type="propagate_in_video",
session_id=session_id,
propagation_direction="forward",
start_frame_index=None,
max_frame_num_to_track=None,
))

# pdb.set_trace()

for item in multiframes_results:
frame_to_outputs[item["frame_index"]] = item["outputs"]

# pdb.set_trace()

os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
save_masklet_video(video_frames=video_frames, outputs=frame_to_outputs, out_path=out_path, alpha=alpha, fps=fps)

predictor.handle_request(dict(type="close_session", session_id=session_id))
return out_path

if __name__ == "__main__":
video_path = "/mnt/shared-storage-gpfs2/kanghengrui-gpfs02/manivid/vid_models/APIs/result/kling/origin_add_20251225_122317.mp4"
# video_path = "/mnt/shared-storage-gpfs2/kanghengrui-gpfs02/manivid/vid_models/original_video.mp4"
video_id = os.path.basename(video_path).split('.')[0]
prompt = "a realistic silver over-ear headset on the man's head"
out_path = f"temp/{video_id}.mp4"

video_frames, orig_fps = read_video_frames_and_fps_cv2(video_path=video_path)

# pdb.set_trace()

out = sam3_overlay_video_official(
video_path=video_path,
prompt=prompt,
out_path=out_path,
checkpoint_path="checkpoint/sam3.pt",
prompt_frame_index=0,
alpha=0.5,
video_frames=video_frames,
fps=orig_fps,
)
print("Saved:", out)
```

I tried running SAM3’s image segmentation pipeline on one of these frames, and found that it is actually able to segment the handset completely.

Image

So I would like to know whether there is any good method to address this issue.

Contributor guide

Open the contributing guide

Research direction

Start by running the supplied Python reproduction through build_sam3_video_predictor, add_prompt, and propagate_in_video, then compare the affected frame with the image segmentation pipeline result. Done means identifying whether propagation or tracking drops one disconnected component and documenting a supported way to obtain the complete mask, with the behavior reproducible.

Written by the indexing model from the issue text.

Assessment

Tech stack
numpy, opencv, python
Domain
computer-vision
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.