""" šŸŽØ Image Colorizer VersĆ£o otimizada para Hugging Face Spaces """ import gradio as gr from PIL import Image, ImageEnhance, ImageFilter, ImageDraw import numpy as np import tempfile import time import os print("šŸš€ Iniciando Image Colorizer...") MAX_IMAGE_SIZE = 1024 def log_message(message): """Log para debug""" timestamp = time.strftime("%H:%M:%S") print(f"[{timestamp}] {message}") def validate_image(image): """Valida e prepara imagem""" try: if image is None: return None, "āŒ Nenhuma imagem fornecida" # Converter para PIL Image se necessĆ”rio if isinstance(image, np.ndarray): img = Image.fromarray(image.astype('uint8')) else: img = image # Verificar tamanho if max(img.size) > 4000: return None, "āŒ Imagem muito grande (>4000px)" if min(img.size) < 32: return None, "āŒ Imagem muito pequena (<32px)" log_message(f"āœ… Imagem vĆ”lida: {img.size}px, {img.mode}") return img, "ok" except Exception as e: log_message(f"āŒ Erro na validação: {str(e)}") return None, str(e) def resize_image(image, max_size): """Redimensiona mantendo aspect ratio""" if max(image.size) <= max_size: return image ratio = max_size / max(image.size) new_width = int(image.width * ratio) new_height = int(image.height * ratio) return image.resize((new_width, new_height), Image.Resampling.LANCZOS) def apply_colorization(image, style="realistic", intensity=0.8): """Aplica colorização Ć  imagem""" try: log_message(f"Aplicando colorização - Estilo: {style}, Intensidade: {intensity}") # Converter para RGB if image.mode != 'RGB': rgb_img = image.convert('RGB') else: rgb_img = image.copy() gray_img = rgb_img.convert('L') # Aplicar efeitos baseados no estilo if style == "realistic": result = rgb_img.copy() enhancer = ImageEnhance.Color(result) result = enhancer.enhance(1.0 + (intensity * 0.5)) r, g, b = result.split() r = r.point(lambda x: min(255, int(x * (1.0 + intensity * 0.1)))) b = b.point(lambda x: max(0, int(x * (1.0 - intensity * 0.05)))) result = Image.merge('RGB', (r, g, b)) elif style == "vibrant": result = rgb_img.copy() enhancer = ImageEnhance.Color(result) result = enhancer.enhance(1.0 + (intensity * 1.0)) enhancer = ImageEnhance.Contrast(result) result = enhancer.enhance(1.0 + (intensity * 0.3)) result = result.filter(ImageFilter.UnsharpMask(radius=1, percent=50, threshold=0)) elif style == "vintage": result = rgb_img.copy() r, g, b = result.split() r = r.point(lambda x: min(255, int(x * 1.1))) g = g.point(lambda x: int(x * 0.9)) b = b.point(lambda x: int(x * 0.8)) result = Image.merge('RGB', (r, g, b)) enhancer = ImageEnhance.Color(result) result = enhancer.enhance(0.7 + (intensity * 0.3)) elif style == "cinematic": result = rgb_img.copy() r, g, b = result.split() r = r.point(lambda x: int(x * 0.9)) g = g.point(lambda x: int(x * 1.0)) b = b.point(lambda x: min(255, int(x * 1.1))) result = Image.merge('RGB', (r, g, b)) enhancer = ImageEnhance.Contrast(result) result = enhancer.enhance(1.0 + (intensity * 0.4)) else: # balanced result = rgb_img.copy() enhancer = ImageEnhance.Color(result) result = enhancer.enhance(1.0 + (intensity * 0.6)) enhancer = ImageEnhance.Contrast(result) result = enhancer.enhance(1.0 + (intensity * 0.2)) # Misturar se imagem era grayscale if image.mode in ['L', 'LA', 'P']: gray_array = np.array(gray_img).astype(np.float32) / 255.0 original_array = np.array(rgb_img).astype(np.float32) colorized_array = np.array(result).astype(np.float32) mixed = (1 - intensity) * original_array + intensity * colorized_array for i in range(3): mixed[:,:,i] = mixed[:,:,i] * (0.7 + 0.3 * gray_array) result = Image.fromarray(mixed.astype(np.uint8)) log_message("āœ… Colorização concluĆ­da") return result except Exception as e: log_message(f"āŒ Erro na colorização: {str(e)}") return image def create_comparison(original, colorized): """Cria comparação lado a lado""" try: if original is None or colorized is None: return None target_height = 400 target_width_orig = int(original.width * (target_height / original.height)) target_width_color = int(colorized.width * (target_height / colorized.height)) original_resized = original.resize((target_width_orig, target_height), Image.Resampling.LANCZOS) colorized_resized = colorized.resize((target_width_color, target_height), Image.Resampling.LANCZOS) total_width = original_resized.width + colorized_resized.width + 20 total_height = target_height + 60 comparison = Image.new('RGB', (total_width, total_height), color=(240, 240, 240)) draw = ImageDraw.Draw(comparison) draw.text((10, 10), "ORIGINAL", fill=(100, 100, 100)) draw.text((original_resized.width + 30, 10), "COLORIZED", fill=(0, 150, 0)) comparison.paste(original_resized, (0, 40)) comparison.paste(colorized_resized, (original_resized.width + 20, 40)) log_message("āœ… Comparação criada") return comparison except Exception as e: log_message(f"āŒ Erro na comparação: {str(e)}") return None def save_image(image, prefix="colorized"): """Salva imagem para download""" try: if image is None: return None temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png", prefix=f"{prefix}_") image.save(temp_file.name, "PNG", optimize=True) log_message(f"Imagem salva: {temp_file.name}") return temp_file.name except Exception as e: log_message(f"āŒ Erro ao salvar: {str(e)}") return None # Interface Gradio with gr.Blocks(title="šŸŽØ Image Colorizer", theme=gr.themes.Soft()) as demo: gr.HTML("""

šŸŽØ Image Colorizer

Colorize fotos preto e branco automaticamente

""") with gr.Row(): with gr.Column(scale=1): gr.Markdown("### šŸ“¤ Upload da Foto") image_input = gr.Image(type="pil", label="Clique ou arraste uma imagem") gr.Markdown("### āš™ļø ConfiguraƧƵes") gr.Markdown("**Estilo de colorização:**") with gr.Row(): style_realistic = gr.Button("Realista", size="sm") style_vibrant = gr.Button("Vibrante", size="sm") style_vintage = gr.Button("Vintage", size="sm") style_selected = gr.Textbox(value="realistic", visible=False) gr.Markdown("**Intensidade das cores:**") intensity_slider = gr.Slider( minimum=0.1, maximum=1.0, value=0.7, step=0.1, label="", info="0.1 = Suave | 1.0 = Intenso" ) colorize_btn = gr.Button("šŸŽØ Colorizar Imagem", variant="primary", size="lg") with gr.Column(scale=1): gr.Markdown("### šŸ“Š Resultado") status_output = gr.Markdown("**Status:** Aguardando imagem...") with gr.Tabs(): with gr.TabItem("šŸ”„ Comparação"): comparison_output = gr.Image(type="pil", label="Antes e Depois") with gr.TabItem("šŸ“· Original"): original_output = gr.Image(type="pil", label="Original") with gr.TabItem("🌈 Colorizada"): colorized_output = gr.Image(type="pil", label="Colorizada") gr.Markdown("### šŸ’¾ Download") with gr.Row(): download_colorized = gr.Button("šŸ“„ Baixar Colorizada") download_comparison = gr.Button("šŸ“Š Baixar Comparação") download_file = gr.File(label="Arquivo para download", interactive=False) with gr.Accordion("šŸ“– Como usar", open=False): gr.Markdown(""" ## InstruƧƵes: 1. **Carregue** uma foto em preto e branco 2. **Escolha** o estilo de colorização 3. **Ajuste** a intensidade das cores 4. **Clique** em "Colorizar Imagem" 5. **Compare** os resultados e baixe ## Estilos: - **Realista**: Tons naturais para retratos - **Vibrante**: Cores vivas para paisagens - **Vintage**: Estilo antigo e nostĆ”lgico """) gr.HTML("""

šŸŽØ Image Colorizer - Photoshop AI Ecosystem

""") # Event handlers style_realistic.click(fn=lambda: "realistic", outputs=[style_selected]) style_vibrant.click(fn=lambda: "vibrant", outputs=[style_selected]) style_vintage.click(fn=lambda: "vintage", outputs=[style_selected]) def process_colorization(image, style, intensity): if image is None: return None, None, None, "āŒ Por favor, carregue uma imagem primeiro" valid_img, msg = validate_image(image) if valid_img is None: return None, None, None, f"āŒ {msg}" if max(valid_img.size) > MAX_IMAGE_SIZE: valid_img = resize_image(valid_img, MAX_IMAGE_SIZE) colorized = apply_colorization(valid_img, style, intensity) comparison = create_comparison(valid_img, colorized) status = f""" āœ… **Colorização aplicada com sucesso!** **Detalhes:** • Estilo: {style.title()} • Intensidade: {intensity*100:.0f}% • Tamanho: {valid_img.size[0]}Ɨ{valid_img.size[1]}px """ return valid_img, colorized, comparison, status colorize_btn.click( fn=process_colorization, inputs=[image_input, style_selected, intensity_slider], outputs=[original_output, colorized_output, comparison_output, status_output] ) download_colorized.click(fn=save_image, inputs=[colorized_output], outputs=[download_file]) download_comparison.click(fn=save_image, inputs=[comparison_output], outputs=[download_file]) def clear_on_upload(image): if image is None: return None, None, None, "**Status:** Aguardando imagem..." valid_img, msg = validate_image(image) if valid_img is None: return None, None, None, f"āŒ {msg}" status = f"āœ… **Imagem carregada!** ({valid_img.size[0]}Ɨ{valid_img.size[1]}px)\n\nEscolha um estilo e clique em Colorizar." return None, None, None, status image_input.change( fn=clear_on_upload, inputs=[image_input], outputs=[original_output, colorized_output, comparison_output, status_output] ) if __name__ == "__main__": log_message("āœ… Iniciando aplicação...") demo.launch()