| | |
| | import torch |
| | from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, AutoencoderKL |
| | from PIL import Image, ImageFilter, ImageEnhance |
| | import time |
| | import cv2 |
| | import numpy as np |
| | from torchvision import transforms |
| |
|
| | print("="*60) |
| | print("FACE-FIX: REINE QUALITÄTSVERBESSERUNG - MINIMALE ÄNDERUNG") |
| | print("="*60) |
| |
|
| | _components_loaded = False |
| | _controlnet_depth = None |
| | _controlnet_pose = None |
| | _pipeline = None |
| |
|
| | def _initialize_components(): |
| | """Lade nur notwendige Komponenten""" |
| | global _components_loaded, _controlnet_depth, _controlnet_pose |
| | |
| | if _components_loaded: |
| | return True |
| | |
| | print("⚠️ Lade nur OpenPose (Depth wird deaktiviert)...") |
| | |
| | try: |
| | |
| | _controlnet_pose = ControlNetModel.from_pretrained( |
| | "lllyasviel/sd-controlnet-openpose", |
| | torch_dtype=torch.float16 |
| | ) |
| | print("✅ OpenPose geladen") |
| | |
| | |
| | _controlnet_depth = None |
| | |
| | _components_loaded = True |
| | return True |
| | except Exception as e: |
| | print(f"❌ Fehler: {e}") |
| | return False |
| |
|
| | def _extract_precise_pose(image): |
| | """SEHR PRÄZISE Pose-Extraktion nur für Gesicht""" |
| | try: |
| | img_array = np.array(image.convert("RGB")) |
| | gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) |
| | |
| | |
| | edges = cv2.Canny(gray, 15, 45) |
| | |
| | |
| | face_cascade = cv2.CascadeClassifier( |
| | cv2.data.haarcascades + 'haarcascade_frontalface_default.xml' |
| | ) |
| | faces = face_cascade.detectMultiScale(gray, 1.1, 4) |
| | |
| | |
| | pose_map = np.zeros_like(img_array) |
| | |
| | |
| | if len(faces) > 0: |
| | for (x, y, w, h) in faces: |
| | |
| | face_region = edges[y:y+h, x:x+w] |
| | |
| | threshold = np.percentile(face_region[face_region > 0], 90) |
| | face_region[face_region < threshold] = 0 |
| | pose_map[y:y+h, x:x+w, 0] = face_region |
| | else: |
| | |
| | pose_map[..., 0] = edges * 0.3 |
| | |
| | return Image.fromarray(pose_map) |
| | except: |
| | |
| | gray = cv2.cvtColor(np.array(image.convert("RGB")), cv2.COLOR_RGB2GRAY) |
| | edges = cv2.Canny(gray, 10, 30) * 0.2 |
| | return Image.fromarray(edges).convert("RGB") |
| |
|
| | def _apply_face_enhancement(image): |
| | """EINFACHE Face Enhancement ohne AI""" |
| | try: |
| | img_array = np.array(image.convert("RGB")) |
| | |
| | |
| | sharpened = cv2.filter2D(img_array, -1, |
| | np.array([[-0.5, -0.5, -0.5], |
| | [-0.5, 5.0, -0.5], |
| | [-0.5, -0.5, -0.5]]) / 3.0) |
| | |
| | |
| | denoised = cv2.fastNlMeansDenoisingColored(sharpened, None, 3, 3, 7, 21) |
| | |
| | |
| | lab = cv2.cvtColor(denoised, cv2.COLOR_RGB2LAB) |
| | l, a, b = cv2.split(lab) |
| | clahe = cv2.createCLAHE(clipLimit=1.0, tileGridSize=(8,8)) |
| | l = clahe.apply(l) |
| | enhanced = cv2.merge([l, a, b]) |
| | enhanced = cv2.cvtColor(enhanced, cv2.COLOR_LAB2RGB) |
| | |
| | return Image.fromarray(enhanced) |
| | except: |
| | return image |
| |
|
| | def apply_facefix(image: Image.Image, prompt: str, negative_prompt: str, seed: int, model_id: str): |
| | """ |
| | SUPER-SUBTILE QUALITÄTSVERBESSERUNG |
| | |
| | Strategie: |
| | 1. NUR OpenPose (kein Depth - das verändert zu viel) |
| | 2. SEHR niedrige ControlNet-Stärke |
| | 3. Fast kein CFG Scale |
| | 4. Identischer Prompt |
| | """ |
| | print("\n" + "🎯"*50) |
| | print("SUBTILE QUALITÄTSVERBESSERUNG") |
| | print(f" Größe: {image.size}") |
| | print("🎯"*50) |
| | |
| | start_time = time.time() |
| | |
| | |
| | print("\n⚡ OPTION 1: Einfache non-AI Verbesserung...") |
| | enhanced = _apply_face_enhancement(image) |
| | |
| | |
| | use_ai_enhancement = False |
| | |
| | if not use_ai_enhancement: |
| | duration = time.time() - start_time |
| | print(f"✅ Non-AI Verbesserung in {duration:.1f}s") |
| | return enhanced |
| | |
| | |
| | print("⚠️ Starte MINIMALE AI-Verbesserung...") |
| | |
| | if not _initialize_components(): |
| | return enhanced |
| | |
| | |
| | original_size = image.size |
| | control_size = (512, 512) |
| | resized_image = image.resize(control_size, Image.Resampling.LANCZOS) |
| | |
| | |
| | pose_img = _extract_precise_pose(resized_image) |
| | pose_img.save("debug_minimal_pose.png") |
| | |
| | |
| | global _pipeline |
| | if _pipeline is None: |
| | try: |
| | print("🔄 Lade Pipeline...") |
| | _pipeline = StableDiffusionControlNetPipeline.from_pretrained( |
| | model_id, |
| | controlnet=[_controlnet_pose], |
| | torch_dtype=torch.float16, |
| | safety_checker=None, |
| | requires_safety_checker=False, |
| | ) |
| | |
| | _pipeline.enable_attention_slicing() |
| | _pipeline.enable_vae_slicing() |
| | |
| | print("✅ Pipeline geladen") |
| | except Exception as e: |
| | print(f"❌ Pipeline Fehler: {e}") |
| | return enhanced |
| | |
| | try: |
| | device = "cuda" if torch.cuda.is_available() else "cpu" |
| | print(f" Device: {device}") |
| | pipeline = _pipeline.to(device) |
| | |
| | |
| | |
| | |
| | |
| | |
| | print("\n⚙️ EXTREM SUBTILE PARAMETER:") |
| | print(" • OpenPose Strength: 0.3 (SEHR NIEDRIG)") |
| | print(" • Steps: 15 (wenig)") |
| | print(" • CFG: 2.0 (fast kein Guidance)") |
| | print(" • Gleicher Seed") |
| | |
| | result = pipeline( |
| | prompt=prompt, |
| | negative_prompt=f"{negative_prompt}, deformed, blurry", |
| | image=[pose_img], |
| | controlnet_conditioning_scale=[0.3], |
| | num_inference_steps=15, |
| | guidance_scale=2.0, |
| | generator=torch.Generator(device).manual_seed(seed + 100), |
| | height=512, |
| | width=512, |
| | ).images[0] |
| | |
| | |
| | if original_size != (512, 512): |
| | result = result.resize(original_size, Image.Resampling.LANCZOS) |
| | |
| | |
| | result_array = np.array(result).astype(float) |
| | original_array = np.array(image).astype(float) |
| | |
| | |
| | blended = (original_array * 0.7 + result_array * 0.3).astype(np.uint8) |
| | final_result = Image.fromarray(blended) |
| | |
| | duration = time.time() - start_time |
| | print(f"\n✅ SUBTILE VERBESSERUNG in {duration:.1f}s") |
| | print(f" • 70% Original, 30% AI") |
| | print(f" • OpenPose: 0.3") |
| | print(f" • CFG: 2.0") |
| | |
| | return final_result |
| | |
| | except Exception as e: |
| | print(f"\n❌ AI-Verbesserung fehlgeschlagen: {e}") |
| | return enhanced |
| |
|
| | print("="*60) |
| | print("FACE-FIX: REINE QUALITÄTSVERBESSERUNG") |
| | print("="*60) |