# 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!")