import os import warnings import cv2 import streamlit as st from PIL import Image, ImageDraw import redirect as rd from main import segment_video warnings.filterwarnings("ignore") def load_image(image_path): return Image.open(image_path) def extract_first_frame(video_path, output_image_path): """ Extract the first frame from a video file and save it to disk. Parameters: video_path (str): Path to the video file. output_image_path (str): Path to save the extracted frame. Returns: str: Path to the saved frame. """ cap = cv2.VideoCapture(video_path) if not cap.isOpened(): raise ValueError(f"Error: Unable to open video file: {video_path}") ret, frame = cap.read() cap.release() if not ret: raise ValueError("Error: Unable to read the first frame from the video.") cv2.imwrite(output_image_path, frame) return output_image_path st.title("Video Background Removal") st.write( "This app uses the Mobile-SAM model to remove the background from a video. " "The model is based on the paper [Faster Segment Anything: Towards Lightweight SAM for Mobile Applications](https://arxiv.org/abs/2306.14289)." ) st.write( "How to use: Upload a video and click 'Segment Video'. The app will then process the video and remove the background. " "You can also use a bounding box to specify the area to segment. " "The app will then output the segmented video, that you can download. " "Do not hesitate to hit the 'Stop/Reset' button if you encounter any issues (it usually solves them all) or want to start over." ) video_file = st.file_uploader("Upload a video", type=["mp4", "avi", "mov"]) if video_file is not None: st.video(video_file) with open("temp_video.mp4", "wb") as f: f.write(video_file.getbuffer()) if not os.path.exists("./temp_images"): os.makedirs("./temp_images") frame_path = extract_first_frame("temp_video.mp4", "temp_frame.jpg") use_bbox = st.checkbox("Use bounding box", value=False) background_color = st.color_picker("Background keying color", "#009000") initial_frame = load_image(frame_path) original_width, original_height = initial_frame.width, initial_frame.height if use_bbox: col1, col2 = st.columns(2) with col1: xmin = st.slider("xmin", 0, original_width, original_width // 4) ymin = st.slider("ymin", 0, original_height, original_height // 4) with col2: xmax = st.slider("xmax", 0, original_width, original_width // 2) ymax = st.slider("ymax", 0, original_height, original_height // 2) draw = ImageDraw.Draw(initial_frame) draw.rectangle([xmin, ymin, xmax, ymax], outline="red", width=3) st.image(initial_frame, caption="Bounding Box Preview", use_column_width=True) if st.button("Save Bounding Box"): with open("temp_bbox.txt", "w") as bbox_file: bbox_file.write(f"{xmin} {ymin} {xmax} {ymax}") st.write(f"Bounding box saved to {os.path.abspath('temp_bbox.txt')}") col1, col2 = st.columns(2) with col2: if st.button( "Stop/Reset", key="stop", help="Stop the process and reset the app", type="primary", ): st.write("Stopping...") os.system("rm -r ./temp_images") os.system("rm ./temp_bbox.txt") os.system("rm -r ./temp_processed_images") os.system("rm ./temp_video.mp4") os.system("rm ./temp_frame.jpg") st.write("Process interrupted") with col1: if st.button( "Segment Video", key="segment", help="Segment the video", type="secondary" ): if use_bbox: if not os.path.exists("./temp_bbox.txt"): with open("temp_bbox.txt", "w") as bbox_file: bbox_file.write(f"{xmin} {ymin} {xmax} {ymax}") else: with open("temp_bbox.txt", "w") as bbox_file: bbox_file.write(f"0 0 {original_width} {original_height}") st.write("Segmenting video...") so = st.empty() with rd.stdouterr(to=st.sidebar): segment_video( video_filename="temp_video.mp4", dir_frames="temp_images", image_start=0, image_end=0, bbox_file="temp_bbox.txt", skip_vid2im=False, mobile_sam_weights="./models/mobile_sam.pt", auto_detect=not use_bbox, background_color=background_color, output_video="video_segmented.mp4", output_dir="temp_processed_images", pbar=False, reverse_mask=not use_bbox, ) os.system("rm -rf ./temp_images") os.system("rm -rf ./temp_bbox.txt") os.system("rm -rf ./temp_processed_images") os.system("rm -rf ./temp_video.mp4") st.video("./video_segmented.mp4") st.write(f"Video saved to {os.path.abspath('video_segmented.mp4')}") vid_file = open("video_segmented.mp4", "rb") vid_bytes = vid_file.read() st.download_button( label="Download Segmented Video", data=vid_bytes, file_name="video_segmented.mp4", ) vid_file.close()