facebookresearch / facebookresearch/sam3
Produce incomplete mask when an object split into 2 parts over time
- 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.
So I would like to know whether there is any good method to address this issue.
Contributor 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