""" 🎨 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("""

🔍 Super Resolution

App 4 do Photoshop AI Ecosystem

Aumente a resolução e qualidade de suas imagens com IA

""") with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 📤 Upload da Imagem") image_input = gr.Image( type="pil", label="Arraste ou clique para selecionar", sources=["upload", "clipboard"], height=250 ) gr.Markdown("### ⚙️ Configurações") with gr.Row(): scale_2x = gr.Button("2×", variant="secondary", scale=1) scale_3x = gr.Button("3×", variant="secondary", scale=1) scale_4x = gr.Button("4×", variant="primary", scale=1) scale_factor = gr.Number(value=4, visible=False) prompt_input = gr.Textbox( label="Prompt (opcional)", value="high quality, detailed, sharp, clear", placeholder="Descreva o que deseja realçar" ) strength_slider = gr.Slider( minimum=0.1, maximum=1.0, value=0.75, step=0.05, label="Força do upscale", info="Controla intensidade da transformação" ) process_btn = gr.Button( "🚀 Aplicar Super Resolution", variant="primary", size="lg" ) with gr.Column(scale=1): gr.Markdown("### 📊 Resultados") status_output = gr.Markdown( value="### 📝 Status\nAguardando imagem..." ) with gr.Tabs(): with gr.TabItem("🔄 Comparação"): comparison_output = gr.Image( type="pil", label="Comparação lado a lado", height=350 ) with gr.TabItem("🔍 Original"): original_output = gr.Image( type="pil", label="Imagem original", height=350 ) with gr.TabItem("✨ Upscaled"): upscaled_output = gr.Image( type="pil", label="Imagem melhorada", height=350 ) with gr.Row(): download_upscaled = gr.Button("📥 Baixar Upscaled", variant="secondary") download_comparison = gr.Button("📊 Baixar Comparação", variant="secondary") download_file = gr.File(label="Arquivo para download", interactive=False) with gr.Accordion("📖 Guia de Uso", open=False): gr.Markdown(""" ## 🚀 Como usar: 1. **Carregue uma imagem** que deseja melhorar 2. **Escolha o fator** (2×, 3× ou 4×) 3. **Ajuste opcionalmente** prompt e força 4. **Clique em "Aplicar"** 5. **Compare** nas abas 6. **Baixe** o resultado ## 💡 Dicas: - Use imagens entre 256×256 e 1024×1024 pixels - Imagens menores se beneficiam mais do upscale - O fator 4× é ideal para imagens pequenas - Primeira execução é mais lenta (carrega modelo) ## ⚠️ Informações: - Tempo: 30-90 segundos dependendo do hardware - Formatos: JPG, PNG, WEBP - Processamento: 100% local/privado """) gr.HTML(f"""

🔍 Super Resolution - Photoshop AI App 4

Gradio {gr.__version__} • {'PyTorch ' + torch.__version__ if TORCH_AVAILABLE else 'PIL Fallback'} • {DEVICE.upper()}

""") # Event handlers scale_2x.click(fn=lambda: 2, outputs=[scale_factor]) scale_3x.click(fn=lambda: 3, outputs=[scale_factor]) scale_4x.click(fn=lambda: 4, outputs=[scale_factor]) def process_wrapper(image, scale, prompt, strength): if image is None: return None, None, None, "❌ Carregue uma imagem primeiro" original, upscaled, status = upscale_image(image, scale, prompt, strength) if upscaled is None: return None, None, None, status comparison = compare_images(original, upscaled, scale) return original, upscaled, comparison, status process_btn.click( fn=process_wrapper, inputs=[image_input, scale_factor, prompt_input, strength_slider], outputs=[original_output, upscaled_output, comparison_output, status_output] ) download_upscaled.click( fn=save_image, inputs=[upscaled_output], outputs=[download_file] ) download_comparison.click( fn=save_image, inputs=[comparison_output], outputs=[download_file] ) def on_image_change(image): if image is None: return None, None, None, "### 📝 Status\nAguardando imagem..." img, msg = validate_image(image) if img is None: return None, None, None, msg w, h = img.size mp = (w * h) / 1_000_000 return None, None, None, f""" ### 📝 Status ✅ Imagem carregada: {w}×{h}px ({mp:.1f} MP) Escolha o fator de aumento e clique em "Aplicar"! """ image_input.change( fn=on_image_change, inputs=[image_input], outputs=[original_output, upscaled_output, comparison_output, status_output] ) print("=" * 60) print("✅ APP 4: SUPER RESOLUTION PRONTO!") print("=" * 60) if __name__ == "__main__": demo.launch()