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