""" 🎨 Super Resolution Aumenta resolução e qualidade de imagens usando IA """ import gradio as gr from PIL import Image, ImageDraw, ImageFont, ImageEnhance import numpy as np import tempfile import traceback import sys import os import time from pathlib import Path print("=" * 60) print("🚀 INICIANDO APP 4: SUPER RESOLUTION") print(f"Python version: {sys.version}") print(f"Gradio version: {gr.__version__}") print("=" * 60) # ========== CONFIGURAÇÃO ========== # Detectar ambiente e instalar dependências necessárias try: import torch print(f"✅ PyTorch {torch.__version__} disponível") print(f"✅ CUDA available: {torch.cuda.is_available()}") TORCH_AVAILABLE = True DEVICE = "cuda" if torch.cuda.is_available() else "cpu" except ImportError: print("⚠️ PyTorch não disponível - usando fallback PIL") TORCH_AVAILABLE = False DEVICE = "cpu" DEFAULT_SCALE_FACTOR = 2 MAX_INPUT_SIZE = 1024 # Tamanho máximo para entrada print(f"⚡ Device: {DEVICE}") print(f"📏 Tamanho máximo de entrada: {MAX_INPUT_SIZE}px") # Cache para o modelo _model_cache = None def load_model(): """Carrega o modelo de super resolução com fallbacks""" global _model_cache if _model_cache is not None: return _model_cache try: print("🔄 Tentando carregar modelo Stable Diffusion Upscaler...") if not TORCH_AVAILABLE: raise ImportError("PyTorch não disponível") from diffusers import StableDiffusionUpscalePipeline # Configurar dtype baseado no device torch_dtype = torch.float16 if DEVICE == "cuda" else torch.float32 model = StableDiffusionUpscalePipeline.from_pretrained( "stabilityai/stable-diffusion-x4-upscaler", torch_dtype=torch_dtype, safety_checker=None, requires_safety_checker=False ) # Otimizações if DEVICE == "cuda": model.enable_attention_slicing() model.enable_model_cpu_offload() else: model = model.to("cpu") try: model.enable_xformers_memory_efficient_attention() print("✅ xFormers habilitado") except: print("⚠️ xFormers não disponível") _model_cache = model print(f"✅ Modelo Stable Diffusion carregado em {DEVICE}") return model except Exception as e: print(f"⚠️ Erro ao carregar Stable Diffusion: {str(e)}") print("🔄 Usando fallback com upscaling clássico PIL...") # Fallback: usar PIL puro _model_cache = "PIL_FALLBACK" return _model_cache # ========== FUNÇÕES AUXILIARES ========== def log_step(step, message): """Log para debug""" timestamp = time.strftime("%H:%M:%S") print(f"[{timestamp}] 🔹 {step}: {message}") def validate_image(image): """Valida e prepara imagem para processamento""" try: if image is None: return None, "❌ Nenhuma imagem fornecida" # Converter tipos diferentes if isinstance(image, dict): if 'image' in image: img = Image.fromarray(image['image'].astype('uint8')) else: return None, "❌ Formato de imagem inválido" elif isinstance(image, np.ndarray): img = Image.fromarray(image.astype('uint8')) elif isinstance(image, str): img = Image.open(image) else: img = image # Validar formato if img.mode not in ['RGB', 'RGBA', 'L']: img = img.convert('RGB') elif img.mode == 'RGBA': # Converter RGBA para RGB background = Image.new('RGB', img.size, (255, 255, 255)) background.paste(img, mask=img.split()[3] if len(img.split()) == 4 else None) img = background elif img.mode == 'L': img = img.convert('RGB') log_step("VALIDATE", f"Imagem: {img.size}px, {img.mode}") # Verificar tamanho mínimo if min(img.size) < 16: return None, "❌ Imagem muito pequena (mínimo 16px)" return img, "✅ Imagem validada" except Exception as e: error_msg = f"❌ Erro na validação: {str(e)}" log_step("VALIDATE_ERROR", error_msg) return None, error_msg def prepare_image_for_model(image, max_size=MAX_INPUT_SIZE): """Prepara imagem para o modelo""" try: # Se imagem for muito grande, redimensionar mantendo aspect ratio if max(image.size) > max_size: log_step("RESIZE", f"Redimensionando de {image.size} para máximo {max_size}px") ratio = max_size / max(image.size) new_width = int(image.width * ratio) new_height = int(image.height * ratio) image = image.resize((new_width, new_height), Image.Resampling.LANCZOS) # Garantir RGB if image.mode != 'RGB': image = image.convert('RGB') return image except Exception as e: log_step("PREPARE_ERROR", str(e)) return image def upscale_pil_fallback(image, scale_factor): """Fallback usando PIL puro com técnicas avançadas""" try: log_step("PIL_FALLBACK", f"Usando upscaling PIL {scale_factor}x") original_size = image.size target_size = (int(original_size[0] * scale_factor), int(original_size[1] * scale_factor)) # Usar Lanczos para melhor qualidade upscaled = image.resize(target_size, Image.Resampling.LANCZOS) # Aplicar sharpening enhancer = ImageEnhance.Sharpness(upscaled) upscaled = enhancer.enhance(1.5) # Aplicar contrast enhancement enhancer = ImageEnhance.Contrast(upscaled) upscaled = enhancer.enhance(1.1) log_step("PIL_FALLBACK", "Upscaling PIL completo") return upscaled except Exception as e: log_step("PIL_FALLBACK_ERROR", str(e)) raise # ========== FUNÇÃO PRINCIPAL ========== def upscale_image(image, scale_factor, prompt="", strength=0.75, progress=gr.Progress()): """Aumenta resolução da imagem""" log_step("START", f"Iniciando upscale {scale_factor}x") try: # Validar imagem progress(0.1, desc="Validando imagem...") img, validation_msg = validate_image(image) if img is None: return None, None, validation_msg original_size = img.size log_step("ORIGINAL", f"Tamanho original: {original_size}") # Preparar imagem progress(0.2, desc="Preparando imagem...") img = prepare_image_for_model(img) prepared_size = img.size log_step("PREPARED", f"Tamanho preparado: {prepared_size}") # Carregar modelo progress(0.3, desc="Carregando modelo...") model = load_model() start_time = time.time() # Processar baseado no modelo disponível if model == "PIL_FALLBACK": progress(0.5, desc=f"Aplicando upscale PIL {scale_factor}x...") result = upscale_pil_fallback(img, scale_factor) model_name = "PIL Lanczos + Enhancement" else: # Usar Stable Diffusion progress(0.5, desc=f"Aplicando IA upscale {scale_factor}x...") if not prompt: prompt = "high quality, detailed, sharp, clear" log_step("PROCESS", f"Prompt: {prompt[:50]}...") # Processar com diffusers img_np = np.array(img) result = model( prompt=prompt, image=img_np, num_inference_steps=20, guidance_scale=7.5, noise_level=20 if scale_factor == 4 else 10 ).images[0] # Garantir scale correto expected_size = (int(prepared_size[0] * scale_factor), int(prepared_size[1] * scale_factor)) if result.size != expected_size: result = result.resize(expected_size, Image.Resampling.LANCZOS) model_name = "Stable Diffusion x4 Upscaler" process_time = time.time() - start_time log_step("TIME", f"Processamento: {process_time:.1f}s") final_size = result.size log_step("FINAL", f"Tamanho final: {final_size}") # Estatísticas size_increase = (final_size[0] * final_size[1]) / (original_size[0] * original_size[1]) megapixels_in = (original_size[0] * original_size[1]) / 1_000_000 megapixels_out = (final_size[0] * final_size[1]) / 1_000_000 status_msg = f""" ✅ Super Resolução aplicada com sucesso! 📊 Estatísticas: • Tamanho original: {original_size[0]} × {original_size[1]}px ({megapixels_in:.1f} MP) • Tamanho final: {final_size[0]} × {final_size[1]}px ({megapixels_out:.1f} MP) • Fator de aumento: {scale_factor}x • Aumento de área: {size_increase:.1f}x • Tempo de processamento: {process_time:.1f}s • Modelo: {model_name} 💡 Dica: Compare as abas para ver a diferença! """ progress(1.0, desc="Completo!") return img, result, status_msg except Exception as e: error_msg = f"❌ Erro no processamento: {str(e)}" log_step("ERROR", error_msg) print(traceback.format_exc()) return None, None, error_msg def compare_images(original, upscaled, scale_factor): """Cria comparação lado a lado""" try: if original is None or upscaled is None: return None # Redimensionar original para comparação justa comparison_height = min(800, upscaled.height) comparison_width = int(original.width * (comparison_height / original.height)) original_resized = original.resize((comparison_width, comparison_height), Image.Resampling.LANCZOS) # Redimensionar upscaled proporcionalmente upscaled_width = int(upscaled.width * (comparison_height / upscaled.height)) upscaled_resized = upscaled.resize((upscaled_width, comparison_height), Image.Resampling.LANCZOS) # Criar canvas total_width = original_resized.width + upscaled_resized.width + 30 canvas_height = comparison_height + 50 comparison = Image.new('RGB', (total_width, canvas_height), color=(245, 245, 245)) draw = ImageDraw.Draw(comparison) # Usar fonte padrão try: font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16) except: font = ImageFont.load_default() # Labels draw.text((10, 10), "ORIGINAL", fill=(80, 80, 80), font=font) draw.text((original_resized.width + 40, 10), f"UPSCALED {scale_factor}X", fill=(0, 120, 0), font=font) # Linha divisória line_x = original_resized.width + 15 draw.line([(line_x, 0), (line_x, canvas_height)], fill=(200, 200, 200), width=3) # Colar imagens comparison.paste(original_resized, (0, 40)) comparison.paste(upscaled_resized, (original_resized.width + 30, 40)) return comparison except Exception as e: log_step("COMPARE_ERROR", str(e)) return None def save_image(image): """Salva imagem para download""" try: if image is None: return None timestamp = time.strftime("%Y%m%d_%H%M%S") temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png", prefix=f"upscaled_{timestamp}_") image.save(temp_file.name, "PNG", optimize=True) log_step("SAVE", f"Imagem salva") return temp_file.name except Exception as e: log_step("SAVE_ERROR", str(e)) return None # ========== INTERFACE GRADIO ========== print("🎨 Criando interface...") with gr.Blocks(title="🎨 Super Resolution", theme=gr.themes.Soft()) as demo: gr.HTML("""
App 4 do Photoshop AI Ecosystem
Aumente a resolução e qualidade de suas imagens com IA
🔍 Super Resolution - Photoshop AI App 4
Gradio {gr.__version__} • {'PyTorch ' + torch.__version__ if TORCH_AVAILABLE else 'PIL Fallback'} • {DEVICE.upper()}