| |
| import sys |
| import os |
| import tempfile |
| from pathlib import Path |
| import streamlit as st |
| from PIL import Image |
|
|
| |
| sys.path.append(str(Path(__file__).parent.resolve())) |
| sys.path.append(str(Path(__file__).parent.resolve() / "pipeline")) |
|
|
| |
| try: |
| import torch |
| print("=== CUDA Info ===") |
| print("CUDA available:", torch.cuda.is_available()) |
| print("CUDA device count:", torch.cuda.device_count()) |
| print("torch version:", torch.__version__) |
| print("=================") |
| except Exception as e: |
| print(f"[WARN] Could not print CUDA info: {e}") |
|
|
| |
| try: |
| from pipeline.two_stage_pipeline import process_two_stage |
| except ImportError as e: |
| st.error(f"Pipeline not found or misconfigured: {e}") |
| st.stop() |
|
|
| st.set_page_config( |
| page_title="BackgroundFX Pro", |
| layout="wide", |
| page_icon="π¬" |
| ) |
|
|
| st.title("π¬ BackgroundFX Pro β AI Video Background Replacer") |
| st.write( |
| "Upload a video and a background image (optional). The system will remove the original background " |
| "using **SAM2** & **MatAnyone**, and composite the subject over your new background image." |
| ) |
|
|
| def progress_callback(msg, prog): |
| """Streamlit-friendly progress reporting (persistent).""" |
| if "progress_bar" not in st.session_state: |
| st.session_state.progress_bar = st.progress(0) |
| st.session_state.progress_text = st.empty() |
| st.session_state.progress_bar.progress(min(max(prog,0.0),1.0)) |
| st.session_state.progress_text.text(msg) |
|
|
| |
| video_file = st.file_uploader( |
| "1οΈβ£ Upload video file (mp4, mov, avi, mkv)", |
| type=["mp4", "mov", "avi", "mkv"] |
| ) |
| bg_file = st.file_uploader( |
| "2οΈβ£ Upload new background (jpg/png, optional)", |
| type=["jpg", "jpeg", "png"] |
| ) |
|
|
| video_path, bg_path = None, None |
|
|
| if video_file: |
| |
| with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as vf: |
| vf.write(video_file.read()) |
| video_path = vf.name |
| st.video(video_path) |
|
|
| if bg_file: |
| |
| with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as bf: |
| bf.write(bg_file.read()) |
| bg_path = bf.name |
| background_img = Image.open(bg_path).convert("RGB") |
| st.image(background_img, caption="Background Image") |
| elif video_file: |
| |
| try: |
| import cv2 |
| cap = cv2.VideoCapture(video_path) |
| width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) or 1280 |
| height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) or 720 |
| cap.release() |
| except Exception: |
| width, height = 1280, 720 |
| background_img = Image.new("RGB", (width, height), (0,255,0)) |
| st.info("No background image uploaded. Using default green background.") |
|
|
| |
| if video_path and background_img: |
| if st.button("π Run Background Replacement"): |
| st.session_state.progress_bar = st.progress(0) |
| st.session_state.progress_text = st.empty() |
| with st.spinner("Processing video... (May take several minutes for long videos)"): |
| try: |
| out_path = process_two_stage( |
| video_path, |
| background_img, |
| progress=progress_callback |
| ) |
| st.success("β
Done! Here is your composited video:") |
| st.video(str(out_path)) |
| with open(out_path, "rb") as f: |
| st.download_button( |
| label="πΎ Download Result", |
| data=f, |
| file_name="backgroundfx_result.mp4", |
| mime="video/mp4" |
| ) |
| except Exception as e: |
| st.error(f"β Processing failed: {e}") |
|
|
| |
| try: |
| if video_path and os.path.exists(video_path): |
| os.unlink(video_path) |
| except Exception: pass |
| try: |
| if bg_path and os.path.exists(bg_path): |
| os.unlink(bg_path) |
| except Exception: pass |
|
|
| |
| st.caption("Built for Hugging Face T4 Spaces β’ CUDA & GPU acceleration required β’ v2025.10") |
|
|