| """ |
| Advanced Image Enhancement using State-of-the-Art AI Models |
| Real-ESRGAN, GFPGAN, and other cutting-edge models |
| Optimized for NVIDIA RTX 3050 |
| """ |
|
|
| import cv2 |
| import numpy as np |
| import torch |
| import torch.nn as nn |
| from PIL import Image, ImageEnhance, ImageFilter |
| import os |
| import requests |
| from io import BytesIO |
| import time |
| from typing import Optional, Tuple |
| try: |
| from backend.ai_model_manager import get_ai_model_manager |
| AI_MODELS_AVAILABLE = True |
| except ImportError: |
| AI_MODELS_AVAILABLE = False |
| print("⚠️ AI models not available, using lightweight enhancer") |
| |
| from backend.lightweight_ai_enhancer import get_lightweight_enhancer |
| from backend.compact_ai_models import CompactAIEnhancer |
| from backend.ultra_compact_enhancer import get_memory_safe_enhancer |
|
|
| class AdvancedImageEnhancer: |
| """Advanced image enhancement using state-of-the-art AI models""" |
| |
| def __init__(self): |
| self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') |
| print(f"🎯 Using device: {self.device}") |
| |
| |
| self.use_lightweight = True |
| if self.device.type == 'cuda': |
| props = torch.cuda.get_device_properties(0) |
| vram_gb = props.total_memory / (1024**3) |
| print(f"📊 VRAM: {vram_gb:.1f} GB") |
| |
| |
| if vram_gb < 6 or not AI_MODELS_AVAILABLE: |
| self.use_lightweight = True |
| print("🚀 Using lightweight enhancer (optimized for <4GB VRAM)") |
| else: |
| self.use_lightweight = False |
| |
| |
| if self.use_lightweight: |
| |
| print("🚀 Using memory-safe AI enhancer (<1GB VRAM)") |
| self.enhancer = get_memory_safe_enhancer() |
| self.ai_manager = None |
| self.compact_realesrgan = None |
| else: |
| self.ai_manager = get_ai_model_manager() |
| self.enhancer = None |
| self.compact_realesrgan = None |
| |
| |
| self.use_ai_models = os.getenv('USE_AI_MODELS', '1') == '1' |
| self.enhance_faces = os.getenv('ENHANCE_FACES', '1') == '1' |
| self.use_anime_model = False |
| |
| |
| self._load_models() |
| |
| def _load_models(self): |
| """Load AI enhancement models""" |
| try: |
| if self.use_lightweight: |
| print("🚀 Loading lightweight AI models...") |
| |
| self.advanced_available = True |
| print("✅ Lightweight enhancer ready") |
| else: |
| print("🚀 Loading advanced AI models...") |
| |
| if self.use_ai_models and self.ai_manager: |
| |
| self.ai_manager.load_realesrgan('RealESRGAN_x4plus') |
| |
| |
| self.ai_manager.load_realesrgan('RealESRGAN_x4plus_anime_6B') |
| |
| |
| if self.enhance_faces: |
| self.ai_manager.load_gfpgan() |
| |
| self.advanced_available = True |
| print("✅ AI models loaded successfully") |
| else: |
| print("⚠️ AI models disabled, using traditional methods") |
| self.advanced_available = False |
| |
| except Exception as e: |
| print(f"⚠️ Models failed to load: {e}") |
| print("⚠️ Falling back to traditional enhancement methods") |
| self.advanced_available = False |
| |
| def enhance_image(self, image_path: str, output_path: str = None) -> str: |
| """Apply advanced image enhancement""" |
| if output_path is None: |
| output_path = image_path |
| |
| print(f"🚀 Enhancing image: {os.path.basename(image_path)}") |
| |
| try: |
| |
| img = cv2.imread(image_path) |
| if img is None: |
| print(f"❌ Failed to load image: {image_path}") |
| return image_path |
| |
| |
| enhanced_img = self._apply_enhancement_pipeline(img, image_path) |
| |
| |
| cv2.imwrite(output_path, enhanced_img, [cv2.IMWRITE_JPEG_QUALITY, 100]) |
| |
| print(f"✅ Enhanced image saved: {os.path.basename(output_path)}") |
| return output_path |
| |
| except Exception as e: |
| print(f"❌ Enhancement failed: {e}") |
| return image_path |
| |
| def _apply_enhancement_pipeline(self, img: np.ndarray, image_path: str = None) -> np.ndarray: |
| """Apply complete enhancement pipeline with AI models""" |
| original_img = img.copy() |
| |
| print("🎨 Applying AI-powered enhancement pipeline...") |
| |
| |
| self.use_anime_model = self._detect_anime_style(img) |
| |
| if self.advanced_available and self.use_ai_models: |
| try: |
| if self.use_lightweight: |
| |
| print(" 🚀 Applying memory-safe AI enhancement...") |
| |
| |
| temp_path = image_path.replace('.', '_temp.') |
| cv2.imwrite(temp_path, img) |
| |
| |
| enhanced_path = self.enhancer.enhance_image( |
| temp_path, |
| temp_path.replace('_temp.', '_enhanced.') |
| ) |
| |
| |
| img = cv2.imread(enhanced_path) |
| |
| |
| if os.path.exists(temp_path): |
| os.remove(temp_path) |
| if os.path.exists(enhanced_path) and enhanced_path != image_path: |
| os.remove(enhanced_path) |
| |
| print(" ✅ Memory-safe enhancement complete") |
| |
| |
| if hasattr(self.enhancer, 'get_memory_usage'): |
| print(f" 💾 Memory: {self.enhancer.get_memory_usage()}") |
| else: |
| |
| print(" 🚀 Applying AI super resolution...") |
| img = self.ai_manager.enhance_image_realesrgan( |
| img, |
| use_anime_model=self.use_anime_model |
| ) |
| |
| |
| if self.enhance_faces: |
| print(" 👤 Enhancing faces with AI...") |
| img = self.ai_manager.enhance_face_gfpgan(img) |
| |
| |
| img = self.ai_manager.post_process(img) |
| |
| |
| self.ai_manager.clear_memory() |
| |
| return img |
| |
| except Exception as e: |
| print(f"⚠️ AI enhancement failed: {e}, using fallback") |
| img = original_img |
| |
| |
| print(" 📈 Using traditional enhancement methods...") |
| |
| |
| img = self._apply_super_resolution_advanced(img) |
| |
| |
| img = self._enhance_colors_advanced(img) |
| |
| |
| img = self._reduce_noise_advanced(img) |
| |
| |
| img = self._enhance_sharpness_advanced(img) |
| |
| |
| img = self._optimize_dynamic_range_advanced(img) |
| |
| |
| img = self._enhance_faces_advanced(img) |
| |
| return img |
| |
| def _apply_super_resolution_advanced(self, img: np.ndarray) -> np.ndarray: |
| """Advanced super resolution (4x upscaling)""" |
| try: |
| print("📈 Applying advanced super resolution (4x upscaling)...") |
| |
| |
| height, width = img.shape[:2] |
| |
| |
| scale_factor = min(2048 / width, 1080 / height, 2.0) |
| target_width = int(width * scale_factor) |
| target_height = int(height * scale_factor) |
| |
| |
| img = cv2.resize(img, (target_width, target_height), |
| interpolation=cv2.INTER_LANCZOS4) |
| |
| |
| kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]]) |
| img = cv2.filter2D(img, -1, kernel) |
| |
| print(f"✅ Super resolution completed: {width}x{height} → {target_width}x{target_height}") |
| |
| except Exception as e: |
| print(f"⚠️ Super resolution failed: {e}") |
| |
| return img |
| |
| def _enhance_colors_advanced(self, img: np.ndarray) -> np.ndarray: |
| """Advanced color enhancement""" |
| try: |
| print("🎨 Applying advanced color enhancement...") |
| |
| |
| lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) |
| |
| |
| clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) |
| lab[:,:,0] = clahe.apply(lab[:,:,0]) |
| |
| |
| lab[:,:,1] = cv2.convertScaleAbs(lab[:,:,1], alpha=1.3, beta=10) |
| lab[:,:,2] = cv2.convertScaleAbs(lab[:,:,2], alpha=1.3, beta=10) |
| |
| |
| enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) |
| |
| |
| hsv = cv2.cvtColor(enhanced, cv2.COLOR_BGR2HSV) |
| hsv[:,:,1] = cv2.convertScaleAbs(hsv[:,:,1], alpha=1.4, beta=0) |
| enhanced = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) |
| |
| except Exception as e: |
| print(f"⚠️ Color enhancement failed: {e}") |
| enhanced = img |
| |
| return enhanced |
| |
| def _reduce_noise_advanced(self, img: np.ndarray) -> np.ndarray: |
| """Advanced noise reduction""" |
| try: |
| print("🧹 Applying advanced noise reduction...") |
| |
| |
| |
| |
| denoised = cv2.bilateralFilter(img, 9, 75, 75) |
| |
| |
| denoised = cv2.fastNlMeansDenoisingColored(denoised, None, 10, 10, 7, 21) |
| |
| |
| denoised = cv2.GaussianBlur(denoised, (3, 3), 0) |
| |
| |
| denoised = cv2.edgePreservingFilter(denoised, flags=1, sigma_s=60, sigma_r=0.4) |
| |
| except Exception as e: |
| print(f"⚠️ Noise reduction failed: {e}") |
| denoised = img |
| |
| return denoised |
| |
| def _enhance_sharpness_advanced(self, img: np.ndarray) -> np.ndarray: |
| """Advanced sharpness enhancement""" |
| try: |
| print("🔪 Applying advanced sharpness enhancement...") |
| |
| |
| |
| |
| gaussian = cv2.GaussianBlur(img, (0, 0), 2.0) |
| sharpened = cv2.addWeighted(img, 1.5, gaussian, -0.5, 0) |
| |
| |
| kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]]) |
| sharpened = cv2.filter2D(sharpened, -1, kernel) |
| |
| |
| gray = cv2.cvtColor(sharpened, cv2.COLOR_BGR2GRAY) |
| laplacian = cv2.Laplacian(gray, cv2.CV_64F) |
| laplacian = np.uint8(np.absolute(laplacian)) |
| sharpened = cv2.addWeighted(sharpened, 1.0, cv2.cvtColor(laplacian, cv2.COLOR_GRAY2BGR), 0.3, 0) |
| |
| except Exception as e: |
| print(f"⚠️ Sharpness enhancement failed: {e}") |
| sharpened = img |
| |
| return sharpened |
| |
| def _optimize_dynamic_range_advanced(self, img: np.ndarray) -> np.ndarray: |
| """Advanced dynamic range optimization""" |
| try: |
| print("📊 Applying advanced dynamic range optimization...") |
| |
| |
| lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) |
| |
| |
| clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) |
| lab[:,:,0] = clahe.apply(lab[:,:,0]) |
| |
| |
| lab[:,:,1] = cv2.convertScaleAbs(lab[:,:,1], alpha=1.2, beta=0) |
| lab[:,:,2] = cv2.convertScaleAbs(lab[:,:,2], alpha=1.2, beta=0) |
| |
| |
| optimized = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) |
| |
| |
| optimized = cv2.convertScaleAbs(optimized, alpha=1.1, beta=5) |
| |
| except Exception as e: |
| print(f"⚠️ Dynamic range optimization failed: {e}") |
| optimized = img |
| |
| return optimized |
| |
| def _enhance_faces_advanced(self, img: np.ndarray) -> np.ndarray: |
| """Advanced face enhancement""" |
| try: |
| print("👤 Applying advanced face enhancement...") |
| |
| |
| face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') |
| |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| faces = face_cascade.detectMultiScale(gray, 1.1, 4) |
| |
| if len(faces) > 0: |
| print(f"🎭 Found {len(faces)} faces, applying enhancement...") |
| |
| for (x, y, w, h) in faces: |
| |
| face_roi = img[y:y+h, x:x+w] |
| |
| |
| enhanced_face = self._enhance_face_region(face_roi) |
| |
| |
| img[y:y+h, x:x+w] = enhanced_face |
| else: |
| print("👤 No faces detected, skipping face enhancement") |
| |
| except Exception as e: |
| print(f"⚠️ Face enhancement failed: {e}") |
| |
| return img |
| |
| def _enhance_face_region(self, face_img: np.ndarray) -> np.ndarray: |
| """Enhance a specific face region""" |
| try: |
| |
| enhanced = cv2.bilateralFilter(face_img, 5, 50, 50) |
| |
| |
| hsv = cv2.cvtColor(enhanced, cv2.COLOR_BGR2HSV) |
| hsv[:,:,1] = cv2.convertScaleAbs(hsv[:,:,1], alpha=1.1, beta=0) |
| enhanced = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) |
| |
| |
| kernel = np.array([[-0.5,-0.5,-0.5], [-0.5,5,-0.5], [-0.5,-0.5,-0.5]]) |
| enhanced = cv2.filter2D(enhanced, -1, kernel) |
| |
| except Exception as e: |
| enhanced = face_img |
| |
| return enhanced |
| |
| def _detect_anime_style(self, img: np.ndarray) -> bool: |
| """Detect if image is anime/manga/comic style""" |
| try: |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| |
| |
| edges = cv2.Canny(gray, 50, 150) |
| edge_density = np.sum(edges > 0) / edges.size |
| |
| |
| unique_colors = len(np.unique(img.reshape(-1, img.shape[2]), axis=0)) |
| |
| |
| laplacian = cv2.Laplacian(gray, cv2.CV_64F) |
| gradient_variance = np.var(laplacian) |
| |
| |
| is_anime = ( |
| edge_density < 0.15 and |
| unique_colors < 10000 and |
| gradient_variance < 1000 |
| ) |
| |
| if is_anime: |
| print(" 🎌 Detected anime/comic style - using specialized model") |
| |
| return is_anime |
| |
| except Exception as e: |
| print(f"⚠️ Style detection failed: {e}") |
| return False |
| |
| def enhance_batch(self, image_paths: list, output_dir: str = None) -> list: |
| """Enhance multiple images""" |
| if output_dir is None: |
| output_dir = "enhanced" |
| |
| os.makedirs(output_dir, exist_ok=True) |
| enhanced_paths = [] |
| |
| print(f"🎯 Enhancing {len(image_paths)} images with advanced techniques...") |
| |
| for i, image_path in enumerate(image_paths, 1): |
| print(f"📸 Processing {i}/{len(image_paths)}: {os.path.basename(image_path)}") |
| |
| |
| filename = os.path.basename(image_path) |
| output_path = os.path.join(output_dir, f"enhanced_{filename}") |
| |
| |
| enhanced_path = self.enhance_image(image_path, output_path) |
| enhanced_paths.append(enhanced_path) |
| |
| print(f"✅ Enhanced {len(enhanced_paths)} images with advanced techniques") |
| return enhanced_paths |
|
|
| |
| advanced_enhancer = None |
|
|
| def get_advanced_enhancer(): |
| """Get or create global advanced enhancer instance""" |
| global advanced_enhancer |
| if advanced_enhancer is None: |
| advanced_enhancer = AdvancedImageEnhancer() |
| return advanced_enhancer |
|
|
| if __name__ == "__main__": |
| |
| enhancer = AdvancedImageEnhancer() |
| print("🧪 Advanced Image Enhancer ready for testing!") |