Pardeep0675's picture
Update app.py
715dccb verified
import gradio as gr
import cv2
import numpy as np
import os, shutil, subprocess
WORK = "work"
os.makedirs(WORK, exist_ok=True)
def extract_frames(video):
subprocess.run(["ffmpeg", "-y", "-i", video, f"{WORK}/f_%04d.png"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def build_video(out):
subprocess.run([
"ffmpeg", "-y", "-framerate", "30",
"-i", f"{WORK}/c_%04d.png",
"-c:v", "libx264", "-pix_fmt", "yuv420p", out
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def detect_initial_box(frames):
# motion-based detection on first few frames
prev = cv2.cvtColor(frames[0], cv2.COLOR_BGR2GRAY)
acc = None
for img in frames[1:4]:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prev, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, _ = cv2.cartToPolar(flow[...,0], flow[...,1])
_, m = cv2.threshold(mag, 2.0, 255, cv2.THRESH_BINARY)
acc = m if acc is None else cv2.add(acc, m)
prev = gray
acc = acc.astype("uint8")
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,15))
acc = cv2.morphologyEx(acc, cv2.MORPH_CLOSE, kernel)
cnts, _ = cv2.findContours(acc, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not cnts:
return None
c = max(cnts, key=cv2.contourArea)
return cv2.boundingRect(c) # x,y,w,h
def process(video):
if video is None:
return None
shutil.rmtree(WORK, ignore_errors=True)
os.makedirs(WORK, exist_ok=True)
inp = os.path.join(WORK, "input.mp4")
shutil.copy(video, inp)
extract_frames(inp)
frame_files = sorted([f for f in os.listdir(WORK) if f.startswith("f_")])
frames = [cv2.imread(os.path.join(WORK, f)) for f in frame_files[:5]]
box = detect_initial_box(frames)
if box is None:
return None
tracker = cv2.TrackerCSRT_create()
tracker.init(frames[0], box)
prev_clean = None
for i, f in enumerate(frame_files):
img = cv2.imread(os.path.join(WORK, f))
ok, b = tracker.update(img)
if ok:
x,y,w,h = [int(v) for v in b]
mask = np.zeros(img.shape[:2], dtype="uint8")
cv2.rectangle(mask, (x,y), (x+w,y+h), 255, -1)
clean = cv2.inpaint(img, mask, 3, cv2.INPAINT_TELEA)
if prev_clean is not None:
clean = cv2.addWeighted(clean, 0.7, prev_clean, 0.3, 0)
else:
clean = img
cv2.imwrite(os.path.join(WORK, f"c_{i:04d}.png"), clean)
prev_clean = clean
out = os.path.join(WORK, "output.mp4")
build_video(out)
return out
ui = gr.Interface(
fn=process,
inputs=gr.Video(label="Upload video (≤8–10 sec)"),
outputs=gr.Video(label="Watermark removed (experimental)"),
title="Auto + Moving Watermark Remover (AI-assisted)",
description=(
"Experimental free tool. Best for small or semi-transparent moving watermarks. "
"Upload only videos you own or have permission to edit."
)
)
ui.launch()