host
Browse files- models/__init__.py +84 -53
- 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 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
|
| 574 |
try:
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
|
| 579 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
timeout_seconds = 300
|
| 581 |
-
|
| 582 |
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
|
|
|
| 589 |
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
return
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|