Update app.py
Browse files
app.py
CHANGED
|
@@ -1,109 +1,28 @@
|
|
| 1 |
-
|
| 2 |
-
from rembg import remove
|
| 3 |
-
from rembg.session_factory import new_session
|
| 4 |
import io
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
app = Flask(__name__)
|
| 7 |
-
|
| 8 |
-
# FULL U²-Net
|
| 9 |
session = new_session("u2net")
|
| 10 |
|
|
|
|
| 11 |
HTML = """
|
| 12 |
<!DOCTYPE html>
|
| 13 |
-
<html
|
| 14 |
-
<head>
|
| 15 |
-
|
| 16 |
-
<
|
| 17 |
-
<
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
<
|
| 22 |
-
|
| 23 |
-
<!-- Open Graph for social sharing -->
|
| 24 |
-
<meta property="og:title" content="Xlnk RMBG - AI Background Remover">
|
| 25 |
-
<meta property="og:description" content="Drag & drop images from anywhere and remove the background instantly. Full U²-Net AI engine.">
|
| 26 |
-
<meta property="og:type" content="website">
|
| 27 |
-
<meta property="og:image" content="https://huggingface.co/spaces/Xlnk/rmbg/resolve/main/preview.png">
|
| 28 |
-
<meta property="og:url" content="https://huggingface.co/spaces/Xlnk/rmbg">
|
| 29 |
-
|
| 30 |
-
<style>
|
| 31 |
-
html, body {
|
| 32 |
-
margin: 0;
|
| 33 |
-
height: 100%;
|
| 34 |
-
background: #0b0f19;
|
| 35 |
-
display: flex;
|
| 36 |
-
justify-content: center;
|
| 37 |
-
align-items: center;
|
| 38 |
-
color: white;
|
| 39 |
-
font-family: sans-serif;
|
| 40 |
-
}
|
| 41 |
-
#dropZone {
|
| 42 |
-
width: 100vw;
|
| 43 |
-
height: 100vh;
|
| 44 |
-
border: 2px dashed #555;
|
| 45 |
-
display: flex;
|
| 46 |
-
justify-content: center;
|
| 47 |
-
align-items: center;
|
| 48 |
-
cursor: pointer;
|
| 49 |
-
text-align: center;
|
| 50 |
-
}
|
| 51 |
-
#dropZone.dragover { background-color: #1b2030; }
|
| 52 |
-
input { display: none; }
|
| 53 |
-
</style>
|
| 54 |
-
</head>
|
| 55 |
-
<body>
|
| 56 |
-
<div id="dropZone">Drop image from anywhere</div>
|
| 57 |
-
|
| 58 |
-
<form id="uploadForm" method="post" enctype="multipart/form-data">
|
| 59 |
-
<input type="file" id="fileInput" name="file" />
|
| 60 |
-
</form>
|
| 61 |
-
|
| 62 |
-
<script>
|
| 63 |
-
const dropZone = document.getElementById("dropZone");
|
| 64 |
-
const fileInput = document.getElementById("fileInput");
|
| 65 |
-
const form = document.getElementById("uploadForm");
|
| 66 |
-
|
| 67 |
-
dropZone.addEventListener("click", () => fileInput.click());
|
| 68 |
-
|
| 69 |
-
fileInput.addEventListener("change", () => {
|
| 70 |
-
if(fileInput.files.length > 0) form.submit();
|
| 71 |
-
});
|
| 72 |
-
|
| 73 |
-
dropZone.addEventListener("dragover", e => {
|
| 74 |
-
e.preventDefault();
|
| 75 |
-
dropZone.classList.add("dragover");
|
| 76 |
-
});
|
| 77 |
-
|
| 78 |
-
dropZone.addEventListener("dragleave", e => {
|
| 79 |
-
dropZone.classList.remove("dragover");
|
| 80 |
-
});
|
| 81 |
-
|
| 82 |
-
dropZone.addEventListener("drop", e => {
|
| 83 |
-
e.preventDefault();
|
| 84 |
-
dropZone.classList.remove("dragover");
|
| 85 |
-
|
| 86 |
-
// Local files
|
| 87 |
-
if (e.dataTransfer.files.length > 0) {
|
| 88 |
-
fileInput.files = e.dataTransfer.files;
|
| 89 |
-
form.submit();
|
| 90 |
-
}
|
| 91 |
-
// Drag from browser (Google Images, etc)
|
| 92 |
-
else {
|
| 93 |
-
let url = e.dataTransfer.getData('text/uri-list');
|
| 94 |
-
if(url){
|
| 95 |
-
fetch(url)
|
| 96 |
-
.then(res => res.blob())
|
| 97 |
-
.then(blob => {
|
| 98 |
-
let dt = new DataTransfer();
|
| 99 |
-
dt.items.add(new File([blob], "image.png", {type: blob.type}));
|
| 100 |
-
fileInput.files = dt.files;
|
| 101 |
-
form.submit();
|
| 102 |
-
});
|
| 103 |
-
}
|
| 104 |
-
}
|
| 105 |
-
});
|
| 106 |
-
</script>
|
| 107 |
</body>
|
| 108 |
</html>
|
| 109 |
"""
|
|
@@ -111,18 +30,51 @@ dropZone.addEventListener("drop", e => {
|
|
| 111 |
@app.route("/", methods=["GET", "POST"])
|
| 112 |
def index():
|
| 113 |
if request.method == "POST":
|
| 114 |
-
file = request.files.get("
|
| 115 |
-
if not file:
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
return HTML
|
| 128 |
|
|
|
|
| 1 |
+
import os
|
|
|
|
|
|
|
| 2 |
import io
|
| 3 |
+
import cv2
|
| 4 |
+
import zipfile
|
| 5 |
+
import shutil
|
| 6 |
+
from flask import Flask, request, send_file, render_template_string
|
| 7 |
+
from rembg import remove, new_session
|
| 8 |
+
from PIL import Image
|
| 9 |
|
| 10 |
app = Flask(__name__)
|
|
|
|
|
|
|
| 11 |
session = new_session("u2net")
|
| 12 |
|
| 13 |
+
# Simple UI for Video Upload
|
| 14 |
HTML = """
|
| 15 |
<!DOCTYPE html>
|
| 16 |
+
<html>
|
| 17 |
+
<head><title>Video Background Remover</title></head>
|
| 18 |
+
<body style="background:#0b0f19; color:white; font-family:sans-serif; text-align:center; padding:50px;">
|
| 19 |
+
<h1>Video to Transparent PNG Frames</h1>
|
| 20 |
+
<p>Upload a video (MP4/MOV). We will zip the transparent frames for you.</p>
|
| 21 |
+
<form method="post" enctype="multipart/form-data">
|
| 22 |
+
<input type="file" name="video" accept="video/*">
|
| 23 |
+
<input type="submit" value="Process and Download ZIP">
|
| 24 |
+
</form>
|
| 25 |
+
<p style="color:#888; font-size:0.8em;">Note: Processing takes ~1 sec per frame on CPU.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
</body>
|
| 27 |
</html>
|
| 28 |
"""
|
|
|
|
| 30 |
@app.route("/", methods=["GET", "POST"])
|
| 31 |
def index():
|
| 32 |
if request.method == "POST":
|
| 33 |
+
file = request.files.get("video")
|
| 34 |
+
if not file: return "No file", 400
|
| 35 |
+
|
| 36 |
+
# Create temporary working directories
|
| 37 |
+
temp_dir = "temp_frames"
|
| 38 |
+
if os.path.exists(temp_dir): shutil.rmtree(temp_dir)
|
| 39 |
+
os.makedirs(temp_dir)
|
| 40 |
+
|
| 41 |
+
# Save uploaded video temporarily
|
| 42 |
+
video_path = "input_video.mp4"
|
| 43 |
+
file.save(video_path)
|
| 44 |
+
|
| 45 |
+
# Process Video
|
| 46 |
+
cap = cv2.VideoCapture(video_path)
|
| 47 |
+
frame_count = 0
|
| 48 |
+
|
| 49 |
+
while cap.isOpened():
|
| 50 |
+
ret, frame = cap.read()
|
| 51 |
+
if not ret: break
|
| 52 |
+
|
| 53 |
+
# Convert BGR to RGB for rembg
|
| 54 |
+
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 55 |
+
|
| 56 |
+
# Remove background
|
| 57 |
+
output = remove(frame_rgb, session=session)
|
| 58 |
+
|
| 59 |
+
# Save frame as PNG
|
| 60 |
+
frame_name = f"frame_{frame_count:04d}.png"
|
| 61 |
+
Image.fromarray(output).save(os.path.join(temp_dir, frame_name))
|
| 62 |
+
frame_count += 1
|
| 63 |
+
|
| 64 |
+
cap.release()
|
| 65 |
+
|
| 66 |
+
# Create ZIP file
|
| 67 |
+
zip_path = "processed_frames.zip"
|
| 68 |
+
with zipfile.ZipFile(zip_path, 'w') as zipf:
|
| 69 |
+
for root, dirs, files in os.walk(temp_dir):
|
| 70 |
+
for f in files:
|
| 71 |
+
zipf.write(os.path.join(root, f), f)
|
| 72 |
+
|
| 73 |
+
# Cleanup
|
| 74 |
+
shutil.rmtree(temp_dir)
|
| 75 |
+
os.remove(video_path)
|
| 76 |
+
|
| 77 |
+
return send_file(zip_path, as_attachment=True)
|
| 78 |
|
| 79 |
return HTML
|
| 80 |
|