image2image / app.py
Alibrown's picture
Update app.py
57bd923 verified
# app.py - Streamlit für Hugging Face Spaces (MIT REMBG-INTEGRATION)
import os
import tempfile
import streamlit as st
from PIL import Image
import io
import numpy as np
# NEUER IMPORT für die KI-gestützte Hintergrundentfernung
from rembg import remove
# ----------------------------------------------------
# 🚨 KRITISCHE FIXES FÜR DEN PERMISSION ERROR (beibehalten)
# ----------------------------------------------------
TEMP_STREAMLIT_HOME = os.path.join(tempfile.gettempdir(), "st_config_workaround")
os.makedirs(TEMP_STREAMLIT_HOME, exist_ok=True)
os.environ["STREAMLIT_HOME"] = TEMP_STREAMLIT_HOME
os.environ["STREAMLIT_GATHER_USAGE_STATS"] = "false"
CONFIG_PATH = os.path.join(TEMP_STREAMLIT_HOME, "config.toml")
CONFIG_CONTENT = """
[browser]
gatherUsageStats = false
[server]
headless = true
port = 7860
enableCORS = false
"""
with open(CONFIG_PATH, "w") as f:
f.write(CONFIG_CONTENT)
# --- NEUE FUNKTION: Hintergrundentfernung mit KI ---
def remove_background(image_pil):
"""
Entfernt den Hintergrund eines Bildes mithilfe der rembg-Bibliothek.
Das Ergebnis ist ein PIL-Image mit Alpha-Kanal (RGBA).
"""
# Konvertiere PIL Image zu Bytes für rembg (empfohlene Methode)
img_byte_arr = io.BytesIO()
image_pil.save(img_byte_arr, format='PNG')
input_bytes = img_byte_arr.getvalue()
# KI-Operation: Hintergrund entfernen
# Da wir auf CPU laufen, kann dies einige Sekunden dauern!
output_bytes = remove(input_bytes, alpha_matting=True)
# Konvertiere die Ergebnis-Bytes zurück zu einem PIL Image
return Image.open(io.BytesIO(output_bytes))
# --- Bildverarbeitungsfunktionen (Unverändert) ---
def stack_horizontal(img1, img2):
# ... (Code unverändert) ...
img1 = img1.convert("RGB")
img2 = img2.convert("RGB")
h1, h2 = img1.size[1], img2.size[1]
if h1 != h2:
w2_new = int(img2.size[0] * h1 / h2)
img2 = img2.resize((w2_new, h1), Image.Resampling.LANCZOS)
total_width = img1.size[0] + img2.size[0]
total_height = img1.size[1]
stacked_img = Image.new('RGB', (total_width, total_height))
stacked_img.paste(img1, (0, 0))
stacked_img.paste(img2, (img1.size[0], 0))
return stacked_img
def blend_images_cpu(img1, img2, alpha):
# ... (Code unverändert) ...
img1 = img1.convert("RGBA")
img2 = img2.convert("RGBA")
if img1.size != img2.size:
img2 = img2.resize(img1.size, Image.Resampling.LANCZOS)
blended = Image.blend(img1, img2, alpha)
return blended.convert("RGB")
def overlay_image(background_img, overlay_img, x_pos, y_pos, scale_factor):
# ... (Code unverändert) ...
background = background_img.convert("RGBA")
overlay = overlay_img.convert("RGBA")
new_width = int(overlay.width * scale_factor)
new_height = int(overlay.height * scale_factor)
overlay = overlay.resize((new_width, new_height), Image.Resampling.LANCZOS)
result = Image.new("RGBA", background.size)
result.paste(background, (0, 0))
result.paste(overlay, (x_pos, y_pos), overlay)
return result.convert("RGB")
# --- Streamlit UI ---
st.set_page_config(page_title="Image Transformer", layout="wide")
st.title("🖼️ CPU Image Transformer (Blend, Stack, KI-Overlay)")
st.markdown("**Blend** (überblenden), **Stack** (aneinanderreihen) oder **KI-Overlay** (Katze auf Klo!) - Reine CPU-Operation.")
col1, col2 = st.columns(2)
with col1:
st.subheader("Eingabe & Steuerung")
img1_file = st.file_uploader("Bild 1 (Basisbild / Hintergrund)", type=["png", "jpg", "jpeg", "webp"])
img2_file = st.file_uploader("Bild 2 (Zusatzbild / Overlay)", type=["png", "jpg", "jpeg", "webp"])
method = st.selectbox("Transformationsmethode", ["Blend", "Stack Horizontal", "Overlay (Position & Scale)"])
# Blending-Faktor (nur bei Blend relevant)
alpha = st.slider("Blending-Faktor (Alpha, nur bei 'Blend' aktiv)", 0.0, 1.0, 0.5, 0.05, disabled=(method != "Blend"))
# Overlay-Parameter (nur bei Overlay relevant)
with st.expander("Overlay-Optionen", expanded=(method == "Overlay (Position & Scale)")):
# NEUES UI-ELEMENT: KI-Freistellung
auto_remove_bg = st.checkbox(
"Automatisch freistellen (KI)",
value=False,
disabled=(method != "Overlay (Position & Scale)"),
help="Nutzt ein KI-Modell, um den Hintergrund von Bild 2 zu entfernen. **Achtung: Dies ist eine CPU-intensive Operation und kann die Verarbeitungszeit erhöhen.**"
)
st.divider() # Trennlinie
x_pos = st.slider("X-Position des Overlays", 0, 1000, 0, 10, disabled=(method != "Overlay (Position & Scale)"))
y_pos = st.slider("Y-Position des Overlays", 0, 1000, 0, 10, disabled=(method != "Overlay (Position & Scale)"))
scale_factor = st.slider("Skalierung des Overlays", 0.1, 3.0, 1.0, 0.1, disabled=(method != "Overlay (Position & Scale)"))
if not auto_remove_bg:
st.info("Wenn **nicht** freigestellt wird, muss Bild 2 bereits ein **transparentes PNG** sein!")
process_btn = st.button("🚀 Verarbeiten", type="primary")
with col2:
st.subheader("Resultat")
result_placeholder = st.empty()
# Verarbeitung
if process_btn:
if img1_file and img2_file:
with st.spinner("Verarbeite..."):
try:
img1 = Image.open(img1_file)
img2 = Image.open(img2_file)
result = None
if method == "Blend":
result = blend_images_cpu(img1, img2, alpha)
elif method == "Stack Horizontal":
result = stack_horizontal(img1, img2)
elif method == "Overlay (Position & Scale)":
# KI-Freistellungslogik HIER
overlay_img_final = img2
if auto_remove_bg:
st.text("KI: Hintergrund von Bild 2 wird entfernt...")
overlay_img_final = remove_background(img2)
st.text("KI: Freistellung abgeschlossen.")
result = overlay_image(img1, overlay_img_final, x_pos, y_pos, scale_factor)
if result:
result_placeholder.image(result, use_container_width=True)
# Download-Button
buf = io.BytesIO()
result.save(buf, format="PNG") # PNG ist wichtig, da es den Alpha-Kanal für den Download beibehält
st.download_button(
label="💾 Download Resultat",
data=buf.getvalue(),
file_name=f"result_{method.lower().replace(' ', '_')}.png",
mime="image/png"
)
except Exception as e:
st.error(f"Fehler bei der Verarbeitung: {e}")
# Füge hier weitere Debug-Informationen hinzu, wenn das Modell nicht lädt
if "No such file or directory" in str(e):
st.error("WICHTIG: Die KI-Modell-Dateien wurden nicht gefunden. Stelle sicher, dass `rembg` alle Abhängigkeiten korrekt geladen hat.")
else:
st.warning("⚠️ Bitte beide Bilder hochladen!")