Spaces:
Paused
Paused
| """ | |
| SAM 3 視頻概念分割 - 使用文本提示跟踪概念 | |
| 基於 Ultralytics SAM 3 文檔: | |
| https://docs.ultralytics.com/zh/models/sam-3/#track-concepts-with-text-prompts | |
| 需求: | |
| pip install -U ultralytics | |
| pip uninstall clip -y | |
| pip install git+https://github.com/ultralytics/CLIP.git | |
| 注意: | |
| sam3.pt 需要從 Hugging Face 手動下載(需申請權限): | |
| https://huggingface.co/facebook/sam3 | |
| """ | |
| import cv2 | |
| from pathlib import Path | |
| from ultralytics.models.sam import SAM3VideoSemanticPredictor | |
| # ───────────────────────────────────────────── | |
| # 設定區域(請依需求修改) | |
| # ───────────────────────────────────────────── | |
| # 輸入影片路徑(可改為本地影片路徑) | |
| VIDEO_SOURCE = "video.mp4" | |
| # 文本提示:指定要追蹤的概念(可自由修改) | |
| TEXT_PROMPTS = ["cellphone"] | |
| # SAM 3 模型權重路徑(需手動下載) | |
| from huggingface_hub import hf_hub_download | |
| weights_path = hf_hub_download( | |
| repo_id="kamillkate/sam3-weights", | |
| filename="sam3.pt", | |
| repo_type="model", | |
| ) | |
| MODEL_PATH = weights_path | |
| # 輸出影片路徑 | |
| OUTPUT_PATH = "output.mp4" | |
| # 信心閾值 | |
| CONFIDENCE = 0.25 | |
| # 圖像尺寸 | |
| IMG_SIZE = 640 | |
| # ───────────────────────────────────────────── | |
| # 主程式 | |
| # ───────────────────────────────────────────── | |
| def main(): | |
| print("=" * 60) | |
| print("SAM 3 視頻概念分割 - 文本提示跟踪") | |
| print("=" * 60) | |
| print(f"📹 輸入影片:{VIDEO_SOURCE}") | |
| print(f"🔍 追蹤概念:{TEXT_PROMPTS}") | |
| print(f"💾 輸出路徑:{OUTPUT_PATH}") | |
| print() | |
| # 確認影片存在 | |
| if not Path(VIDEO_SOURCE).exists(): | |
| raise FileNotFoundError( | |
| f"找不到影片:{VIDEO_SOURCE}\n" | |
| "請修改 VIDEO_SOURCE 為有效的影片路徑。" | |
| ) | |
| # 確認模型存在 | |
| if not Path(MODEL_PATH).exists(): | |
| raise FileNotFoundError( | |
| f"找不到 SAM 3 模型:{MODEL_PATH}\n" | |
| "請至 https://huggingface.co/facebook/sam3 下載 sam3.pt 並放置於當前目錄。" | |
| ) | |
| # 初始化 SAM3VideoSemanticPredictor | |
| overrides = dict( | |
| conf=CONFIDENCE, | |
| task="segment", | |
| mode="predict", | |
| imgsz=IMG_SIZE, | |
| model=MODEL_PATH, | |
| half=True, # 使用 FP16 加速推理(GPU 需支援) | |
| save=False, # 我們手動處理輸出,不使用自動儲存 | |
| ) | |
| predictor = SAM3VideoSemanticPredictor(overrides=overrides) | |
| # 取得影片基本資訊(用於設定輸出) | |
| cap = cv2.VideoCapture(VIDEO_SOURCE) | |
| fps = cap.get(cv2.CAP_PROP_FPS) or 30.0 | |
| width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | |
| height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| cap.release() | |
| print(f"影片資訊:{width}x{height} @ {fps:.1f} FPS,共 {total_frames} 幀") | |
| # 建立 VideoWriter 輸出 output.mp4 | |
| fourcc = cv2.VideoWriter_fourcc(*"mp4v") | |
| writer = cv2.VideoWriter(OUTPUT_PATH, fourcc, fps, (width, height)) | |
| # 執行文本提示視頻跟踪(stream=True 逐幀處理) | |
| print(f"\n開始分割追蹤...") | |
| results = predictor( | |
| source=VIDEO_SOURCE, | |
| text=TEXT_PROMPTS, | |
| stream=True, | |
| ) | |
| frame_count = 0 | |
| for r in results: | |
| frame_count += 1 | |
| # 取得帶有分割遮罩的視覺化幀 | |
| annotated_frame = r.plot() # BGR numpy array | |
| # 寫入輸出影片 | |
| writer.write(annotated_frame) | |
| # 顯示進度 | |
| if frame_count % 10 == 0 or frame_count == 1: | |
| print(f" 處理第 {frame_count}/{total_frames} 幀 | 偵測到 {len(r.boxes) if r.boxes is not None else 0} 個物件") | |
| writer.release() | |
| print() | |
| print("=" * 60) | |
| print(f"✅ 完成!共處理 {frame_count} 幀") | |
| print(f"💾 輸出已儲存至:{OUTPUT_PATH}") | |
| print("=" * 60) | |
| if __name__ == "__main__": | |
| main() |