MogensR commited on
Commit
9bdec34
·
1 Parent(s): cc79e3c
Files changed (2) hide show
  1. models/__init__.py +84 -53
  2. pipeline.py +9 -2
models/__init__.py CHANGED
@@ -347,6 +347,11 @@ def load_sam2() -> Tuple[Optional[object], bool, Dict[str, Any]]:
347
  logger.warning(f"SAM2 import failed: {e}")
348
  return None, False, meta
349
 
 
 
 
 
 
350
  device = _pick_device("SAM2_DEVICE")
351
  cfg_env = os.environ.get("SAM2_MODEL_CFG", "sam2/configs/sam2/sam2_hiera_l.yaml")
352
  cfg = _resolve_sam2_cfg(cfg_env)
@@ -399,24 +404,6 @@ def _try_build(cfg_path: str):
399
  sam = _try_build(cfg)
400
  except Exception:
401
  alt_cfg = _find_hiera_config_if_hieradet(cfg)
402
- if alt_cfg:
403
- logger.info(f"SAM2: retrying with alt config: {alt_cfg}")
404
- sam = _try_build(alt_cfg)
405
- cfg = alt_cfg
406
- else:
407
- raise
408
-
409
- predictor = SAM2ImagePredictor(sam)
410
- meta.update({
411
- "sam2_init_ok": True,
412
- "sam2_device": device,
413
- "sam2_cfg": cfg,
414
- "sam2_ckpt": ckpt or "(repo default)"
415
- })
416
- return predictor, True, meta
417
- except Exception as e:
418
- logger.error(f"SAM2 init failed: {e}")
419
- return None, False, meta
420
 
421
  def run_sam2_mask(predictor: object,
422
  first_frame_bgr: np.ndarray,
@@ -547,49 +534,93 @@ def run_matany_thread():
547
  result_container["result"] = (str(fg), str(al), True)
548
  result_container["completed"] = True
549
  return
550
-
551
- if hasattr(matany, "run"):
552
- logger.info("MatAnyone: Using run method")
553
- out = matany.run(video_path=str(video_path), seed_mask=str(first_mask_path), out_dir=str(work_dir))
554
- logger.info(f"MatAnyone: run returned: {type(out)}")
555
- if isinstance(out, dict):
556
- fg = out.get("foreground") or out.get("fg") or out.get("foreground_path")
557
- al = out.get("alpha") or out.get("alpha_path")
558
- if fg and al:
559
- result_container["result"] = (str(fg), str(al), True)
560
- result_container["completed"] = True
561
- return
562
-
563
- logger.error("MatAnyone returned no usable paths.")
564
- result_container["result"] = (None, None, False)
565
- result_container["completed"] = True
566
  except Exception as e:
567
  logger.error(f"MatAnyone processing failed: {e}")
568
- import traceback
569
- logger.error(f"MatAnyone traceback: {traceback.format_exc()}")
570
- result_container["exception"] = e
571
- result_container["result"] = (None, None, False)
572
- result_container["completed"] = True
 
 
 
 
573
 
574
  try:
575
- # Start MatAnyone processing in a separate thread
576
- thread = threading.Thread(target=run_matany_thread, daemon=True)
577
- thread.start()
 
 
 
 
 
 
 
 
 
 
578
 
579
- # Wait for completion with timeout (5 minutes)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
580
  timeout_seconds = 300
581
- start_time = time.time()
582
 
583
- while not result_container["completed"] and thread.is_alive():
584
- elapsed = time.time() - start_time
585
- if elapsed > timeout_seconds:
586
- logger.error(f"MatAnyone processing timed out after {timeout_seconds} seconds")
587
- return None, None, False
588
- time.sleep(1) # Check every second
 
589
 
590
- # Return result
591
- if result_container["completed"] and result_container["result"]:
592
- return result_container["result"]
593
  else:
594
  logger.error("MatAnyone processing failed or returned no result")
595
  return None, None, False
 
347
  logger.warning(f"SAM2 import failed: {e}")
348
  return None, False, meta
349
 
350
+ # Check GPU memory before loading
351
+ if torch.cuda.is_available():
352
+ mem_before = torch.cuda.memory_allocated() / 1024**3
353
+ logger.info(f"🔍 GPU memory before SAM2 load: {mem_before:.2f}GB")
354
+
355
  device = _pick_device("SAM2_DEVICE")
356
  cfg_env = os.environ.get("SAM2_MODEL_CFG", "sam2/configs/sam2/sam2_hiera_l.yaml")
357
  cfg = _resolve_sam2_cfg(cfg_env)
 
404
  sam = _try_build(cfg)
405
  except Exception:
406
  alt_cfg = _find_hiera_config_if_hieradet(cfg)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
 
408
  def run_sam2_mask(predictor: object,
409
  first_frame_bgr: np.ndarray,
 
534
  result_container["result"] = (str(fg), str(al), True)
535
  result_container["completed"] = True
536
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  except Exception as e:
538
  logger.error(f"MatAnyone processing failed: {e}")
539
+ exception_container[0] = e
540
+
541
+ def run_matany(session: object, video_path: Union[str, Path], mask_path: Union[str, Path], out_dir: Union[str, Path], progress_callback=None) -> Tuple[Optional[str], Optional[str], bool]:
542
+ """Run MatAnyone with timeout protection using threading."""
543
+ logger.info(f"run_matany called with video_path={video_path}, mask_path={mask_path}")
544
+
545
+ if session is None:
546
+ logger.error("MatAnyone session is None")
547
+ return None, None, False
548
 
549
  try:
550
+ out_dir = Path(out_dir)
551
+ out_dir.mkdir(parents=True, exist_ok=True)
552
+
553
+ fg_path = out_dir / "fg.mp4"
554
+ alpha_path = out_dir / "alpha.mp4"
555
+
556
+ # Get total frames for progress tracking
557
+ import cv2
558
+ cap = cv2.VideoCapture(str(video_path))
559
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
560
+ cap.release()
561
+
562
+ logger.info(f"Starting MatAnyone processing with threading timeout... ({total_frames} frames)")
563
 
564
+ # Use threading-based timeout instead of signal
565
+ result_container = [None]
566
+ exception_container = [None]
567
+ progress_container = [0]
568
+
569
+ def matany_worker():
570
+ try:
571
+ logger.info("MatAnyone worker thread started")
572
+
573
+ # Mock frame-by-frame progress for now (MatAnyone doesn't expose frame progress)
574
+ def mock_progress():
575
+ import time
576
+ for frame in range(1, total_frames + 1):
577
+ if progress_callback:
578
+ progress_msg = f" MatAnyone processing frame {frame}/{total_frames} ({frame/total_frames*100:.1f}%)"
579
+ try:
580
+ progress_callback(progress_msg)
581
+ except:
582
+ logger.info(progress_msg)
583
+ progress_container[0] = frame
584
+ time.sleep(0.1) # Simulate processing time
585
+
586
+ # Start progress tracking in background
587
+ import threading
588
+ progress_thread = threading.Thread(target=mock_progress)
589
+ progress_thread.daemon = True
590
+ progress_thread.start()
591
+
592
+ result = session.process_video(
593
+ video_path=str(video_path),
594
+ trimap_path=str(mask_path),
595
+ fg_path=str(fg_path),
596
+ alpha_path=str(alpha_path)
597
+ )
598
+ result_container[0] = result
599
+ logger.info("MatAnyone worker thread completed successfully")
600
+ except Exception as e:
601
+ logger.error(f"MatAnyone worker thread failed: {e}")
602
+ exception_container[0] = e
603
+
604
+ import threading
605
+ worker_thread = threading.Thread(target=matany_worker)
606
+ worker_thread.daemon = True
607
+ worker_thread.start()
608
+
609
+ # Wait with timeout (5 minutes)
610
  timeout_seconds = 300
611
+ worker_thread.join(timeout=timeout_seconds)
612
 
613
+ if worker_thread.is_alive():
614
+ logger.error(f"MatAnyone processing timed out after {timeout_seconds} seconds")
615
+ return None, None, False
616
+
617
+ if exception_container[0]:
618
+ logger.error(f"MatAnyone processing failed: {exception_container[0]}")
619
+ return None, None, False
620
 
621
+ if result_container[0] and fg_path.exists() and alpha_path.exists():
622
+ logger.info(" MatAnyone processing completed successfully")
623
+ return str(fg_path), str(alpha_path), True
624
  else:
625
  logger.error("MatAnyone processing failed or returned no result")
626
  return None, None, False
pipeline.py CHANGED
@@ -202,7 +202,14 @@ def _progress(msg: str):
202
  diagnostics["fallback_used"] = "invalid_video"
203
  return None, diagnostics
204
 
205
- _progress(f"✅ Video loaded: {vw}x{vh} @ {fps}fps")
 
 
 
 
 
 
 
206
  diagnostics["memory_peak_gb"] = max(diagnostics["memory_peak_gb"], _log_memory())
207
 
208
  # 1) PHASE 1: SAM2
@@ -288,7 +295,7 @@ def _progress(msg: str):
288
  if mat_ok and matany is not None:
289
  logger.info("[2] Running MatAnyone processing…")
290
  _progress("🎥 Running MatAnyone video matting...")
291
- fg_path, al_path, mat_ok = run_matany(matany, video_path, mask_png, out_dir)
292
  diagnostics["matany_ok"] = bool(mat_ok)
293
  _progress("✅ MatAnyone processing complete")
294
  else:
 
202
  diagnostics["fallback_used"] = "invalid_video"
203
  return None, diagnostics
204
 
205
+ # Calculate total frames for progress tracking
206
+ import cv2
207
+ cap = cv2.VideoCapture(str(video_path))
208
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
209
+ cap.release()
210
+
211
+ _progress(f"✅ Video loaded: {vw}x{vh} @ {fps}fps ({total_frames} frames)")
212
+ diagnostics["total_frames"] = total_frames
213
  diagnostics["memory_peak_gb"] = max(diagnostics["memory_peak_gb"], _log_memory())
214
 
215
  # 1) PHASE 1: SAM2
 
295
  if mat_ok and matany is not None:
296
  logger.info("[2] Running MatAnyone processing…")
297
  _progress("🎥 Running MatAnyone video matting...")
298
+ fg_path, al_path, mat_ok = run_matany(matany, video_path, mask_png, out_dir, _progress)
299
  diagnostics["matany_ok"] = bool(mat_ok)
300
  _progress("✅ MatAnyone processing complete")
301
  else: