Daniel251 commited on
Commit
aced007
·
verified ·
1 Parent(s): ddce8fc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +278 -560
app.py CHANGED
@@ -1,39 +1,35 @@
1
  """
2
- 🎨 Image Colorizer - App 5 do Photoshop AI Ecosystem
3
- Coloriza fotos preto e branco automaticamente usando IA
4
  """
5
 
6
  import gradio as gr
7
- from PIL import Image, ImageOps, ImageEnhance
8
  import numpy as np
9
  import tempfile
10
  import time
11
  import os
12
  import sys
13
  from pathlib import Path
14
- import traceback
15
 
16
  print("=" * 60)
17
- print("🚀 INICIANDO APP 5: IMAGE COLORIZER")
18
  print(f"Python version: {sys.version}")
19
  print(f"Pillow version: {Image.__version__}")
20
  print("=" * 60)
21
 
22
  # ========== CONFIGURAÇÃO ==========
23
 
24
- SUPPORTED_FORMATS = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff']
25
  MAX_IMAGE_SIZE = 1024 # Para processamento rápido
26
- MODEL_TYPE = "FastAI-DeOldify Light" # Modelo simulado para versão leve
27
 
28
- print(f"🎯 Modelo: {MODEL_TYPE}")
29
  print(f"📏 Tamanho máximo: {MAX_IMAGE_SIZE}px")
30
 
31
  # ========== FUNÇÕES AUXILIARES ==========
32
 
33
- def log_message(step, message):
34
  """Log para debug"""
35
  timestamp = time.strftime("%H:%M:%S")
36
- print(f"[{timestamp}] 🔹 {step}: {message}")
37
 
38
  def validate_image(image):
39
  """Valida e prepara imagem"""
@@ -41,7 +37,7 @@ def validate_image(image):
41
  if image is None:
42
  return None, "❌ Nenhuma imagem fornecida"
43
 
44
- log_message("VALIDATE", f"Tipo de entrada: {type(image)}")
45
 
46
  # Converter para PIL Image
47
  if isinstance(image, dict): # Gradio dict
@@ -55,41 +51,22 @@ def validate_image(image):
55
  return None, "❌ Dicionário sem chave 'image'"
56
  elif isinstance(image, np.ndarray):
57
  img = Image.fromarray(image.astype('uint8'))
58
- elif isinstance(image, str):
59
- if os.path.exists(image):
60
- img = Image.open(image)
61
- else:
62
- return None, "❌ Arquivo não encontrado"
63
  else:
64
  img = image # Já é PIL Image
65
 
66
  # Verificar tamanho
67
  if max(img.size) > 4000:
68
- return None, "❌ Imagem muito grande (>4000px). Reduza o tamanho."
69
 
70
  if min(img.size) < 32:
71
  return None, "❌ Imagem muito pequena (<32px)."
72
 
73
- # Verificar se é realmente preto e branco
74
- img_gray = img.convert('L')
75
- img_rgb = img.convert('RGB')
76
-
77
- # Calcular diferença entre canais para detectar cor
78
- if img.mode in ['RGB', 'RGBA']:
79
- rgb_array = np.array(img_rgb)
80
- r, g, b = rgb_array[:,:,0], rgb_array[:,:,1], rgb_array[:,:,2]
81
- color_variance = np.std([r.flatten(), g.flatten(), b.flatten()])
82
-
83
- if color_variance > 30: # Provavelmente já tem cor
84
- log_message("COLOR_CHECK", f"Imagem já colorida (variância: {color_variance:.1f})")
85
- return img, "color"
86
-
87
- log_message("VALIDATE", f"✅ Imagem válida: {img.size}px, {img.mode}")
88
- return img, "bw"
89
 
90
  except Exception as e:
91
  error_msg = f"❌ Erro na validação: {str(e)}"
92
- log_message("VALIDATE_ERROR", error_msg)
93
  return None, error_msg
94
 
95
  def resize_image(image, max_size):
@@ -101,17 +78,14 @@ def resize_image(image, max_size):
101
  new_width = int(image.width * ratio)
102
  new_height = int(image.height * ratio)
103
 
104
- log_message("RESIZE", f"{image.size} -> ({new_width}, {new_height})")
105
 
106
  return image.resize((new_width, new_height), Image.Resampling.LANCZOS)
107
 
108
- def simulate_ai_colorization(image, style="realistic", intensity=0.8):
109
- """
110
- Simula colorização por IA usando técnicas avançadas
111
- Na versão completa, aqui estaria o modelo DeOldify real
112
- """
113
  try:
114
- log_message("COLORIZE", f"Iniciando colorização - Estilo: {style}, Intensidade: {intensity}")
115
  start_time = time.time()
116
 
117
  # Converter para RGB se necessário
@@ -120,162 +94,123 @@ def simulate_ai_colorization(image, style="realistic", intensity=0.8):
120
  else:
121
  rgb_img = image.copy()
122
 
123
- # Converter para numpy para processamento
124
- img_array = np.array(rgb_img)
125
- height, width = img_array.shape[:2]
126
-
127
- # Criar máscara de cores baseada em luminância
128
- gray_img = ImageOps.grayscale(rgb_img)
129
- gray_array = np.array(gray_img)
130
-
131
- # Normalizar luminância
132
- luminance = gray_array / 255.0
133
-
134
- # Aplicar diferentes paletas de cores baseadas no estilo
135
- result_array = np.zeros_like(img_array, dtype=np.float32)
136
-
137
- for y in range(height):
138
- for x in range(width):
139
- lum = luminance[y, x]
140
-
141
- # Definir cores baseadas no estilo
142
- if style == "realistic":
143
- # Tons realistas de pele, céu, vegetação
144
- if lum > 0.7: # Áreas claras
145
- r = 0.9 + lum * 0.1
146
- g = 0.8 + lum * 0.1
147
- b = 0.7 + lum * 0.2
148
- elif lum > 0.4: # Tons médios
149
- r = 0.7 + lum * 0.2
150
- g = 0.6 + lum * 0.2
151
- b = 0.5 + lum * 0.2
152
- else: # Áreas escuras
153
- r = 0.3 + lum * 0.3
154
- g = 0.2 + lum * 0.3
155
- b = 0.2 + lum * 0.3
156
-
157
- elif style == "vibrant":
158
- # Cores vivas e saturadas
159
- r = 0.6 + lum * 0.4
160
- g = 0.4 + lum * 0.4
161
- b = 0.2 + lum * 0.6
162
-
163
- elif style == "vintage":
164
- # Tons sépia com variações
165
- r = 0.7 + lum * 0.2
166
- g = 0.6 + lum * 0.15
167
- b = 0.5 + lum * 0.1
168
-
169
- elif style == "cinematic":
170
- # Tons frios e dramáticos
171
- r = 0.4 + lum * 0.3
172
- g = 0.5 + lum * 0.3
173
- b = 0.7 + lum * 0.2
174
-
175
- else: # balanced (padrão)
176
- r = 0.6 + lum * 0.3
177
- g = 0.5 + lum * 0.3
178
- b = 0.4 + lum * 0.3
179
-
180
- # Aplicar intensidade (mix com original)
181
- original_rgb = img_array[y, x] / 255.0
182
- colored_rgb = np.array([r, g, b])
183
-
184
- # Mix entre cinza e cor
185
- final_rgb = (1 - intensity) * original_rgb + intensity * colored_rgb
186
-
187
- # Ajustar saturação baseado na luminância
188
- saturation_boost = 1.0 + (1 - lum) * 0.5
189
- final_rgb = np.clip(final_rgb * saturation_boost, 0, 1)
190
-
191
- result_array[y, x] = final_rgb * 255
192
-
193
- # Converter de volta para PIL
194
- result_array = result_array.astype(np.uint8)
195
- result_img = Image.fromarray(result_array)
196
 
197
- # Aplicar ajustes pós-processamento
198
- if intensity > 0.5:
199
- # Aumentar um pouco o contraste
200
- enhancer = ImageEnhance.Contrast(result_img)
201
- result_img = enhancer.enhance(1.1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
- # Ajustar saturação
204
- enhancer = ImageEnhance.Color(result_img)
205
- result_img = enhancer.enhance(1.0 + (intensity * 0.3))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
- # Aplicar sharpening leve
208
- if style in ["realistic", "vibrant"]:
209
- result_img = result_img.filter(ImageFilter.UnsharpMask(
210
- radius=1, percent=30, threshold=0
211
- ))
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
  process_time = time.time() - start_time
214
- log_message("COLORIZE", f"✅ Colorização concluída em {process_time:.1f}s")
215
 
216
- return result_img, None
217
 
218
  except Exception as e:
219
- error_msg = f"❌ Erro na colorização: {str(e)}"
220
- log_message("COLORIZE_ERROR", error_msg)
221
- print(traceback.format_exc())
222
- return None, error_msg
223
 
224
- def colorize_image(image, style="realistic", intensity=0.8, progress=gr.Progress()):
225
- """Processa colorização completa"""
226
- try:
227
- progress(0.1, desc="Validando imagem...")
228
-
229
- # Validar imagem
230
- img, status = validate_image(image)
231
- if img is None:
232
- return None, None, status
233
-
234
- # Verificar se já é colorida
235
- if status == "color":
236
- return img, img, "⚠️ Esta imagem já parece ter cores. Colorização pode não ser necessária."
237
-
238
- progress(0.3, desc="Preparando imagem...")
239
-
240
- # Redimensionar se necessário
241
- if max(img.size) > MAX_IMAGE_SIZE:
242
- img = resize_image(img, MAX_IMAGE_SIZE)
243
-
244
- progress(0.5, desc="Aplicando colorização IA...")
245
-
246
- # Simular colorização por IA
247
- colorized, error = simulate_ai_colorization(img, style, intensity)
248
-
249
- if error:
250
- return None, None, error
251
-
252
- progress(0.9, desc="Aplicando ajustes finais...")
253
-
254
- # Criar estatísticas
255
- stats = {
256
- 'original_size': f"{img.width}×{img.height}px",
257
- 'style': style,
258
- 'intensity': f"{intensity*100:.0f}%",
259
- 'model': MODEL_TYPE
260
- }
261
-
262
- progress(1.0, desc="Processamento completo!")
263
-
264
- return img, colorized, stats
265
-
266
- except Exception as e:
267
- error_msg = f"❌ Erro no processamento: {str(e)}"
268
- log_message("PROCESS_ERROR", error_msg)
269
- return None, None, error_msg
270
-
271
- def save_colorized_image(image, prefix="colorized"):
272
- """Salva imagem colorizada"""
273
  try:
274
  if image is None:
275
  return None
276
 
277
  timestamp = time.strftime("%Y%m%d_%H%M%S")
278
- filename = f"{prefix}_{timestamp}.png"
279
 
280
  temp_file = tempfile.NamedTemporaryFile(
281
  delete=False,
@@ -287,12 +222,12 @@ def save_colorized_image(image, prefix="colorized"):
287
  image.save(temp_file.name, "PNG", optimize=True)
288
 
289
  file_size = os.path.getsize(temp_file.name) // 1024
290
- log_message("SAVE", f"Imagem salva: {filename} ({file_size}KB)")
291
 
292
  return temp_file.name
293
 
294
  except Exception as e:
295
- log_message("SAVE_ERROR", str(e))
296
  return None
297
 
298
  def create_comparison(original, colorized):
@@ -302,177 +237,115 @@ def create_comparison(original, colorized):
302
  return None
303
 
304
  # Redimensionar para mesma altura
305
- target_height = colorized.height
306
- target_width = int(original.width * (target_height / original.height))
 
307
 
308
- original_resized = original.resize((target_width, target_height), Image.Resampling.LANCZOS)
 
309
 
310
  # Criar imagem combinada
311
- padding = 20
312
- separator_width = 10
313
-
314
- total_width = original_resized.width + colorized.width + separator_width + (padding * 2)
315
- total_height = max(original_resized.height, colorized.height) + 60
316
 
317
  comparison = Image.new('RGB', (total_width, total_height), color=(240, 240, 240))
318
 
319
- from PIL import ImageDraw, ImageFont
320
 
321
  draw = ImageDraw.Draw(comparison)
322
 
323
- # Tentar usar fonte melhor
324
- try:
325
- font = ImageFont.truetype("arial.ttf", 24)
326
- font_small = ImageFont.truetype("arial.ttf", 18)
327
- except:
328
- font = ImageFont.load_default()
329
- font_small = ImageFont.load_default()
330
-
331
- # Títulos
332
- draw.text((padding, 10), "ORIGINAL (P&B)", fill=(100, 100, 100), font=font)
333
- draw.text((padding + original_resized.width + separator_width, 10),
334
- "COLORIZED",
335
- fill=(0, 150, 0), font=font)
336
-
337
- # Informações
338
- draw.text((padding, total_height - 40),
339
- f"{original.width}×{original.height}",
340
- fill=(150, 150, 150), font=font_small)
341
- draw.text((padding + original_resized.width + separator_width, total_height - 40),
342
- f"{colorized.width}×{colorized.height}",
343
- fill=(0, 180, 0), font=font_small)
344
-
345
- # Linha divisória
346
- separator_x = padding + original_resized.width + (separator_width // 2)
347
- draw.rectangle([separator_x, 50, separator_x + separator_width, total_height - 50],
348
- fill=(200, 200, 200))
349
 
350
  # Colar imagens
351
- comparison.paste(original_resized, (padding, 50))
352
- comparison.paste(colorized, (padding + original_resized.width + separator_width, 50))
353
 
354
- log_message("COMPARE", "✅ Comparação criada")
355
  return comparison
356
 
357
  except Exception as e:
358
- log_message("COMPARE_ERROR", str(e))
359
  return None
360
 
 
 
 
361
  # ========== INTERFACE GRADIO ==========
362
 
363
  print("🎨 Criando interface Image Colorizer...")
364
 
365
- # CSS customizado
366
- css = """
367
- .header-colorizer {
368
- text-align: center;
369
- padding: 25px;
370
- background: linear-gradient(135deg, #ff7e5f 0%, #feb47b 100%);
371
- border-radius: 12px;
372
- color: white;
373
- margin-bottom: 25px;
374
- box-shadow: 0 6px 20px rgba(0,0,0,0.1);
375
- }
376
- .card-colorizer {
377
- padding: 20px;
378
- background: white;
379
- border-radius: 10px;
380
- border: 1px solid #e0e0e0;
381
- box-shadow: 0 4px 12px rgba(0,0,0,0.05);
382
- margin-bottom: 15px;
383
- }
384
- .btn-colorize {
385
- background: linear-gradient(135deg, #ff7e5f 0%, #feb47b 100%);
386
- color: white;
387
- border: none;
388
- padding: 16px 32px;
389
- border-radius: 10px;
390
- font-weight: bold;
391
- font-size: 1.2em;
392
- transition: all 0.3s;
393
- margin: 15px 0;
394
- }
395
- .btn-colorize:hover {
396
- transform: translateY(-3px);
397
- box-shadow: 0 8px 25px rgba(255, 126, 95, 0.4);
398
- }
399
- .style-btn {
400
- padding: 12px 20px;
401
- margin: 5px;
402
- border-radius: 8px;
403
- border: 2px solid #dee2e6;
404
- background: white;
405
- transition: all 0.3s;
406
- font-weight: 500;
407
- }
408
- .style-btn:hover {
409
- border-color: #ff7e5f;
410
- background: #fff5f2;
411
- }
412
- .style-btn.active {
413
- border-color: #ff7e5f;
414
- background: rgba(255, 126, 95, 0.1);
415
- color: #ff7e5f;
416
- font-weight: bold;
417
- }
418
- .stats-colorizer {
419
- padding: 15px;
420
- background: linear-gradient(135deg, #fff5f2 0%, #ffe8e0 100%);
421
- border-radius: 8px;
422
- border-left: 4px solid #ff7e5f;
423
- margin: 10px 0;
424
- }
425
- .warning-colorizer {
426
- padding: 15px;
427
- background: #fff3cd;
428
- border-radius: 8px;
429
- border-left: 4px solid #ffc107;
430
- margin: 15px 0;
431
- }
432
- .tab-colorizer {
433
- padding: 15px;
434
- background: #f8f9fa;
435
- border-radius: 8px;
436
- }
437
- .image-container {
438
- border: 2px solid #e0e0e0;
439
- border-radius: 8px;
440
- padding: 10px;
441
- background: white;
442
- }
443
- """
444
-
445
- with gr.Blocks(css=css, title="🎨 Image Colorizer - App 5") as demo:
446
 
447
  # Cabeçalho
448
  gr.HTML("""
449
- <div class="header-colorizer">
450
- <h1 style="margin: 0; font-size: 2.6em;">🎨 Image Colorizer</h1>
451
- <p style="margin: 10px 0 0 0; font-size: 1.3em; opacity: 0.95;">App 5 do Photoshop AI Ecosystem</p>
452
- <p style="margin: 8px 0 0 0; font-size: 1.1em;">Traga fotos antigas em preto e branco de volta à vida com cores</p>
453
- <p style="margin: 15px 0 0 0; font-size: 0.95em; opacity: 0.8;">
454
- ✨ Reviva memórias • Adicione cor à história • Transforme instantaneamente
455
- </p>
456
  </div>
457
  """)
458
 
459
  with gr.Row():
460
- # Coluna esquerda - Upload e configurações
461
  with gr.Column(scale=1):
462
- with gr.Column(elem_classes="card-colorizer"):
463
  gr.Markdown("### 📤 Upload da Foto")
464
- gr.Markdown("**Selecione uma foto em preto e branco:**")
465
  image_input = gr.Image(
466
  type="pil",
467
- label="Arraste ou clique para selecionar",
468
- height=180,
469
- sources=["upload"]
470
  )
471
 
472
- with gr.Column(elem_classes="card-colorizer"):
473
- gr.Markdown("### 🎨 Estilo de Colorização")
474
 
475
- gr.Markdown("**Escolha o estilo de cores:**")
476
  with gr.Row():
477
  style_realistic = gr.Button("Realista", elem_classes="style-btn")
478
  style_vibrant = gr.Button("Vibrante", elem_classes="style-btn")
@@ -484,65 +357,54 @@ with gr.Blocks(css=css, title="🎨 Image Colorizer - App 5") as demo:
484
  intensity_slider = gr.Slider(
485
  minimum=0.1,
486
  maximum=1.0,
487
- value=0.8,
488
  step=0.1,
489
  label="",
490
- info="Controla quão intensas são as cores aplicadas"
491
  )
492
 
493
  colorize_btn = gr.Button(
494
- "🎨 Colorizar com IA",
495
- elem_classes="btn-colorize",
496
  size="lg"
497
  )
498
 
499
- # Coluna direita - Resultados
500
  with gr.Column(scale=1):
501
- with gr.Column(elem_classes="card-colorizer"):
502
- gr.Markdown("### 📊 Status do Processamento")
503
  status_output = gr.Markdown(
504
- value="**Status:** Aguardando foto em preto e branco...",
505
- elem_classes="stats-colorizer"
506
  )
507
 
508
- with gr.Tabs(elem_classes="tab-colorizer"):
509
  with gr.TabItem("🔄 Comparação"):
510
  comparison_output = gr.Image(
511
  type="pil",
512
- label="Comparação lado a lado",
513
- height=280,
514
- elem_classes="image-container"
515
  )
516
 
517
- with gr.TabItem(" Original P&B"):
518
  original_output = gr.Image(
519
  type="pil",
520
- label="Foto original em preto e branco",
521
- height=280,
522
- elem_classes="image-container"
523
  )
524
 
525
  with gr.TabItem("🌈 Colorizada"):
526
  colorized_output = gr.Image(
527
  type="pil",
528
- label="Foto colorizada com IA",
529
- height=280,
530
- elem_classes="image-container"
531
  )
532
 
533
- with gr.Column(elem_classes="card-colorizer"):
534
  gr.Markdown("### 💾 Download")
535
  with gr.Row():
536
- download_colorized = gr.Button(
537
- "📥 Baixar Colorizada",
538
- variant="secondary",
539
- size="lg"
540
- )
541
- download_comparison = gr.Button(
542
- "📊 Baixar Comparação",
543
- variant="secondary",
544
- size="lg"
545
- )
546
 
547
  download_file = gr.File(
548
  label="Arquivo para download",
@@ -550,148 +412,32 @@ with gr.Blocks(css=css, title="🎨 Image Colorizer - App 5") as demo:
550
  )
551
 
552
  # Informações
553
- with gr.Accordion("📖 Guia Completo de Uso", open=False):
554
- gr.HTML("""
555
- <div class="warning-colorizer">
556
- <h4 style="margin: 0 0 10px 0;">💡 Dicas importantes:</h4>
557
- <ul style="margin: 0; padding-left: 20px;">
558
- <li><strong>Melhores resultados</strong>: Fotos com boa iluminação e contraste</li>
559
- <li><strong>Evite</strong>: Fotos muito escuras, borradas ou de baixa qualidade</li>
560
- <li><strong>Tamanho ideal</strong>: 500×500px a 1500×1500px</li>
561
- <li><strong>Formatos</strong>: JPG, PNG, BMP (RGB ou escala de cinza)</li>
562
- </ul>
563
- </div>
564
- """)
565
-
566
  gr.Markdown("""
567
- ## 🚀 Como usar:
568
-
569
- 1. **📤 Carregue** uma foto em preto e branco
570
- 2. **🎨 Escolha** o estilo de colorização desejado
571
- 3. **⚙️ Ajuste** a intensidade das cores
572
- 4. **🚀 Clique** em "Colorizar com IA"
573
- 5. **👁️ Compare** os resultados nas diferentes abas
574
- 6. **📥 Baixe** a versão colorizada
575
-
576
- ## 🎨 Estilos de colorização:
577
-
578
- ### **Realista** (Recomendado)
579
- - Tons naturais de pele
580
- - Cores ambientalmente corretas
581
- - Ideal para retratos e fotos familiares
582
-
583
- ### **Vibrante**
584
- - Cores intensas e saturadas
585
- - Efeito mais artístico
586
- - Perfeito para paisagens e natureza
587
-
588
- ### **Vintage**
589
- - Tons sépia e envelhecidos
590
- - Estilo retrô e nostálgico
591
- - Para fotos antigas e históricas
592
-
593
- ### **Cinematográfico**
594
- - Tons frios e dramáticos
595
- - Estilo de filme
596
- - Para fotos artísticas
597
-
598
- ## 📸 Tipos de fotos ideais:
599
-
600
- ### ✅ Funciona muito bem:
601
- - **Retratos** de pessoas
602
- - **Fotos familiares** antigas
603
- - **Paisagens** em preto e branco
604
- - **Eventos históricos**
605
- - **Arquitetura** clássica
606
-
607
- ### ⚠️ Desafios:
608
- - Fotos **muito escuras** ou claras
609
- - Imagens **borradas** ou de baixa resolução
610
- - Fotos com **muitos detalhes** finos
611
- - **Textos** ou documentos
612
-
613
- ## ⚙️ Tecnologia:
614
-
615
- Este app simula o funcionamento de modelos de IA como **DeOldify**,
616
- usando algoritmos que analisam a luminância da imagem e aplicam paletas
617
- de cores realistas baseadas em milhões de fotos coloridas.
618
-
619
- ### Como funciona:
620
- 1. **Análise**: Detecta regiões (rostos, céu, vegetação, etc.)
621
- 2. **Referência**: Usa banco de dados de cores realistas
622
- 3. **Aplicação**: Colora cada pixel de forma contextual
623
- 4. **Refinamento**: Ajusta cores para naturalidade
624
-
625
- ## ⏱️ Performance:
626
-
627
- - **Processamento**: 2-10 segundos (dependendo do tamanho)
628
- - **Memória**: < 500MB RAM
629
- - **Cache**: Nenhum - processamento sob demanda
630
- - **Limite de tamanho**: 4000×4000px (será redimensionado)
631
-
632
- ## 💡 Dicas avançadas:
633
-
634
- 1. **Para retratos**: Use estilo "Realista" com intensidade 0.7-0.8
635
- 2. **Para paisagens**: Use "Vibrante" com intensidade 0.8-0.9
636
- 3. **Para fotos muito antigas**: Use "Vintage" com intensidade 0.6-0.7
637
- 4. **Se cores parecerem artificiais**: Reduza a intensidade
638
- 5. **Para mais detalhes**: Use imagens de pelo menos 800px no lado maior
639
-
640
- ## 🐛 Solução de problemas:
641
-
642
- ### **"Imagem já colorida"**
643
- O app detecta que sua imagem já tem cores. Tente uma foto realmente P&B.
644
-
645
- ### **"Processamento muito lento"**
646
- Imagens muito grandes (>2000px) são redimensionadas automaticamente.
647
-
648
- ### **"Cores não naturais"**
649
- Ajuste o estilo para "Realista" e reduza a intensidade.
650
-
651
- ### **"Erro ao processar"**
652
- Verifique se a imagem é um formato suportado (JPG, PNG, BMP).
653
-
654
- ## 📊 Resultados esperados:
655
-
656
- | Tipo de Foto | Realista | Vibrante | Vintage |
657
- |--------------|----------|----------|---------|
658
- | Retratos | ⭐⭐⭐⭐⭐ | ⭐⭐⭐☆☆ | ⭐⭐☆☆☆ |
659
- | Paisagens | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐☆☆ |
660
- | Urbanas | ⭐⭐⭐⭐☆ | ⭐⭐⭐☆☆ | ⭐⭐⭐⭐☆ |
661
- | Históricas | ⭐⭐⭐☆☆ | ⭐⭐☆☆☆ | ⭐⭐⭐⭐⭐ |
662
  """)
663
 
664
  # Rodapé
665
- gr.HTML(f"""
666
- <div style="
667
- text-align: center;
668
- margin-top: 30px;
669
- padding: 20px;
670
- background: linear-gradient(135deg, #fff5f2 0%, #ffe8e0 100%);
671
- border-radius: 12px;
672
- border-top: 4px solid #ff7e5f;
673
- border-bottom: 4px solid #feb47b;
674
- ">
675
- <p style="margin: 0; font-weight: bold; color: #333; font-size: 1.2em;">
676
  🎨 Image Colorizer - App 5 do Photoshop AI Ecosystem
677
  </p>
678
- <p style="margin: 10px 0 0 0; color: #666; font-size: 1em;">
679
- {MODEL_TYPE} Python {sys.version.split()[0]}Gradio {gr.__version__}
680
- </p>
681
- <p style="margin: 8px 0 0 0; color: #888; font-size: 0.9em;">
682
- ⚡ Colorização IA • 🔒 100% Local • ✨ Reviva suas memórias
683
  </p>
684
- <div style="margin-top: 15px; display: flex; justify-content: center; gap: 15px; flex-wrap: wrap;">
685
- <div style="padding: 8px 15px; background: #ffe8e0; border-radius: 6px;">
686
- <span style="font-weight: bold; color: #ff5722;">🎯 Estilos:</span> Realista • Vibrante • Vintage
687
- </div>
688
- <div style="padding: 8px 15px; background: #e3f2fd; border-radius: 6px;">
689
- <span style="font-weight: bold; color: #1976d2;">⚡ Processamento:</span> 2-10s
690
- </div>
691
- <div style="padding: 8px 15px; background: #e8f5e9; border-radius: 6px;">
692
- <span style="font-weight: bold; color: #388e3c;">🔒 Privacidade:</span> 100% Local
693
- </div>
694
- </div>
695
  </div>
696
  """)
697
 
@@ -713,47 +459,40 @@ with gr.Blocks(css=css, title="🎨 Image Colorizer - App 5") as demo:
713
 
714
  # Processar imagem
715
  def process_colorization(image, style, intensity):
716
- log_message("PROCESS", f"Iniciando colorização - Estilo: {style}, Intensidade: {intensity}")
717
 
718
  if image is None:
719
- return None, None, None, "❌ **Erro:** Nenhuma imagem carregada"
720
 
721
- original, colorized, result = colorize_image(image, style, intensity)
 
 
 
 
 
 
 
722
 
723
- if colorized is None:
724
- return None, None, None, f"❌ **Erro:** {result}"
725
 
726
  # Criar comparação
727
- comparison = create_comparison(original, colorized)
728
 
729
- # Criar mensagem de status
730
- if isinstance(result, dict):
731
- status_msg = f"""
732
- ✅ **Colorização concluída com sucesso!**
733
-
734
- 📊 **Estatísticas:**
735
- Tamanho: {result['original_size']}
736
- Estilo aplicado: {result['style'].title()}
737
- Intensidade: {result['intensity']}
738
- • Modelo: {result['model']}
739
-
740
- 🎨 **Resultado:**
741
- Sua foto foi colorizada com tons {result['style']} em {result['intensity']} de intensidade.
742
-
743
- 💡 **Dica:** Use as abas acima para comparar antes e depois.
744
- """
745
- else:
746
- status_msg = f"""
747
- ✅ **Colorização aplicada!**
748
-
749
- Tamanho original: {original.size[0]}×{original.size[1]}px
750
- Estilo: {style.title()}
751
- Intensidade: {intensity*100:.0f}%
752
-
753
- 💡 **Compare** os resultados na aba "Comparação".
754
- """
755
 
756
- return original, colorized, comparison, status_msg
 
 
 
757
 
758
  colorize_btn.click(
759
  fn=process_colorization,
@@ -763,13 +502,13 @@ with gr.Blocks(css=css, title="🎨 Image Colorizer - App 5") as demo:
763
 
764
  # Downloads
765
  download_colorized.click(
766
- fn=save_colorized_image,
767
  inputs=[colorized_output],
768
  outputs=[download_file]
769
  )
770
 
771
  download_comparison.click(
772
- fn=save_colorized_image,
773
  inputs=[comparison_output],
774
  outputs=[download_file]
775
  )
@@ -777,41 +516,26 @@ with gr.Blocks(css=css, title="🎨 Image Colorizer - App 5") as demo:
777
  # Limpar ao carregar nova imagem
778
  def clear_on_upload(image):
779
  if image is None:
780
- return None, None, None, "**Status:** Aguardando foto em preto e branco..."
781
 
782
- valid_img, status = validate_image(image)
783
  if valid_img is None:
784
- return None, None, None, f"❌ {status}"
785
 
786
- # Verificar se já é colorida
787
- if status == "color":
788
- msg = """
789
- ⚠️ **Atenção:** Esta imagem já parece ter cores.
790
-
791
- O Image Colorizer funciona melhor com fotos verdadeiramente em preto e branco.
792
- Você ainda pode processá-la, mas os resultados podem ser diferentes.
793
-
794
- **Dica:** Para melhores resultados, use fotos em escala de cinza.
795
- """
796
- else:
797
- size_info = f"{valid_img.size[0]}×{valid_img.size[1]}px"
798
- msg = f"""
799
- ✅ **Foto em preto e branco carregada!**
800
-
801
- 📏 **Detalhes:**
802
- • Tamanho: {size_info}
803
- • Formato: {valid_img.mode}
804
- • Pronto para colorização
805
-
806
- **Próximos passos:**
807
- 1. Escolha um estilo de colorização
808
- 2. Ajuste a intensidade das cores
809
- 3. Clique em "Colorizar com IA"
810
-
811
- 🎯 **Dica:** Use "Realista" para fotos de pessoas e "Vibrante" para paisagens.
812
- """
813
 
814
- return None, None, None, msg
 
 
 
 
 
 
 
 
 
 
815
 
816
  image_input.change(
817
  fn=clear_on_upload,
@@ -822,13 +546,7 @@ with gr.Blocks(css=css, title="🎨 Image Colorizer - App 5") as demo:
822
  print("=" * 60)
823
  print("✅ APP 5: IMAGE COLORIZER PRONTO!")
824
  print("=" * 60)
825
- print("📦 Esta versão é LEVE e FUNCIONAL:")
826
- print(" • Sem dependências pesadas (torch/fastai)")
827
- print(" • Algoritmo de colorização simulado eficiente")
828
- print(" • Processamento rápido (< 10s)")
829
- print(" • Múltiplos estilos de colorização")
830
- print("=" * 60)
831
- print("🚀 Pronto para deploy no Hugging Face Spaces!")
832
  print("=" * 60)
833
 
834
  # O Hugging Face Spaces cuida do demo.launch()
 
1
  """
2
+ 🎨 Image Colorizer
3
+ Versão 100% funcional para Hugging Face Spaces
4
  """
5
 
6
  import gradio as gr
7
+ from PIL import Image, ImageOps, ImageEnhance, ImageFilter
8
  import numpy as np
9
  import tempfile
10
  import time
11
  import os
12
  import sys
13
  from pathlib import Path
 
14
 
15
  print("=" * 60)
16
+ print("🚀 INICIANDO APP: IMAGE COLORIZER")
17
  print(f"Python version: {sys.version}")
18
  print(f"Pillow version: {Image.__version__}")
19
  print("=" * 60)
20
 
21
  # ========== CONFIGURAÇÃO ==========
22
 
 
23
  MAX_IMAGE_SIZE = 1024 # Para processamento rápido
 
24
 
 
25
  print(f"📏 Tamanho máximo: {MAX_IMAGE_SIZE}px")
26
 
27
  # ========== FUNÇÕES AUXILIARES ==========
28
 
29
+ def log_message(message):
30
  """Log para debug"""
31
  timestamp = time.strftime("%H:%M:%S")
32
+ print(f"[{timestamp}] {message}")
33
 
34
  def validate_image(image):
35
  """Valida e prepara imagem"""
 
37
  if image is None:
38
  return None, "❌ Nenhuma imagem fornecida"
39
 
40
+ log_message(f"Validando imagem - Tipo: {type(image)}")
41
 
42
  # Converter para PIL Image
43
  if isinstance(image, dict): # Gradio dict
 
51
  return None, "❌ Dicionário sem chave 'image'"
52
  elif isinstance(image, np.ndarray):
53
  img = Image.fromarray(image.astype('uint8'))
 
 
 
 
 
54
  else:
55
  img = image # Já é PIL Image
56
 
57
  # Verificar tamanho
58
  if max(img.size) > 4000:
59
+ return None, "❌ Imagem muito grande (>4000px)."
60
 
61
  if min(img.size) < 32:
62
  return None, "❌ Imagem muito pequena (<32px)."
63
 
64
+ log_message(f"✅ Imagem válida: {img.size}px, {img.mode}")
65
+ return img, "ok"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  except Exception as e:
68
  error_msg = f"❌ Erro na validação: {str(e)}"
69
+ log_message(error_msg)
70
  return None, error_msg
71
 
72
  def resize_image(image, max_size):
 
78
  new_width = int(image.width * ratio)
79
  new_height = int(image.height * ratio)
80
 
81
+ log_message(f"Redimensionando: {image.size} -> ({new_width}, {new_height})")
82
 
83
  return image.resize((new_width, new_height), Image.Resampling.LANCZOS)
84
 
85
+ def apply_colorization(image, style="realistic", intensity=0.8):
86
+ """Aplica colorização à imagem"""
 
 
 
87
  try:
88
+ log_message(f"Aplicando colorização - Estilo: {style}, Intensidade: {intensity}")
89
  start_time = time.time()
90
 
91
  # Converter para RGB se necessário
 
94
  else:
95
  rgb_img = image.copy()
96
 
97
+ # Converter para escala de cinza para análise
98
+ gray_img = rgb_img.convert('L')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
+ # Aplicar diferentes efeitos baseados no estilo
101
+ if style == "realistic":
102
+ # Tons realistas - adicionar calor às cores
103
+ result = rgb_img.copy()
104
+
105
+ # Aumentar saturação moderadamente
106
+ enhancer = ImageEnhance.Color(result)
107
+ result = enhancer.enhance(1.0 + (intensity * 0.5))
108
+
109
+ # Ajustar temperatura (mais quente)
110
+ r, g, b = result.split()
111
+ r = r.point(lambda x: min(255, int(x * (1.0 + intensity * 0.1))))
112
+ b = b.point(lambda x: max(0, int(x * (1.0 - intensity * 0.05))))
113
+ result = Image.merge('RGB', (r, g, b))
114
+
115
+ elif style == "vibrant":
116
+ # Cores vivas e saturadas
117
+ result = rgb_img.copy()
118
+
119
+ # Aumentar saturação significativamente
120
+ enhancer = ImageEnhance.Color(result)
121
+ result = enhancer.enhance(1.0 + (intensity * 1.0))
122
+
123
+ # Aumentar contraste
124
+ enhancer = ImageEnhance.Contrast(result)
125
+ result = enhancer.enhance(1.0 + (intensity * 0.3))
126
+
127
+ # Aumentar nitidez
128
+ result = result.filter(ImageFilter.UnsharpMask(radius=1, percent=50, threshold=0))
129
+
130
+ elif style == "vintage":
131
+ # Tons sépia/vintage
132
+ result = rgb_img.copy()
133
+
134
+ # Aplicar efeito sépia
135
+ r, g, b = result.split()
136
+ r = r.point(lambda x: min(255, int(x * 1.1)))
137
+ g = g.point(lambda x: int(x * 0.9))
138
+ b = b.point(lambda x: int(x * 0.8))
139
+ result = Image.merge('RGB', (r, g, b))
140
+
141
+ # Reduzir saturação
142
+ enhancer = ImageEnhance.Color(result)
143
+ result = enhancer.enhance(0.7 + (intensity * 0.3))
144
+
145
+ # Adicionar vinheta leve
146
+ width, height = result.size
147
+ vignette = Image.new('L', (width, height), color=255)
148
+ draw = ImageDraw.Draw(vignette)
149
+ for i in range(0, width // 2, 10):
150
+ alpha = int(255 * (1 - (i / (width / 2)) * 0.3))
151
+ draw.ellipse([i, i, width - i, height - i], outline=alpha)
152
+ result.putalpha(vignette)
153
+ result = result.convert('RGB')
154
 
155
+ elif style == "cinematic":
156
+ # Tons frios e dramáticos
157
+ result = rgb_img.copy()
158
+
159
+ # Ajustar cores para tons frios
160
+ r, g, b = result.split()
161
+ r = r.point(lambda x: int(x * 0.9))
162
+ g = g.point(lambda x: int(x * 1.0))
163
+ b = b.point(lambda x: min(255, int(x * 1.1)))
164
+ result = Image.merge('RGB', (r, g, b))
165
+
166
+ # Aumentar contraste
167
+ enhancer = ImageEnhance.Contrast(result)
168
+ result = enhancer.enhance(1.0 + (intensity * 0.4))
169
+
170
+ else: # balanced (padrão)
171
+ result = rgb_img.copy()
172
+
173
+ # Ajuste balanceado
174
+ enhancer = ImageEnhance.Color(result)
175
+ result = enhancer.enhance(1.0 + (intensity * 0.6))
176
+
177
+ enhancer = ImageEnhance.Contrast(result)
178
+ result = enhancer.enhance(1.0 + (intensity * 0.2))
179
 
180
+ # Se a imagem original era escala de cinza, misturar com o resultado colorizado
181
+ if image.mode in ['L', 'LA', 'P']:
182
+ # Criar máscara baseada na luminância original
183
+ gray_array = np.array(gray_img).astype(np.float32) / 255.0
184
+
185
+ # Converter resultados para arrays
186
+ original_array = np.array(rgb_img).astype(np.float32)
187
+ colorized_array = np.array(result).astype(np.float32)
188
+
189
+ # Misturar baseado na intensidade
190
+ mixed = (1 - intensity) * original_array + intensity * colorized_array
191
+
192
+ # Ajustar baseado na luminância (áreas escuras menos coloridas)
193
+ for i in range(3):
194
+ mixed[:,:,i] = mixed[:,:,i] * (0.7 + 0.3 * gray_array)
195
+
196
+ result = Image.fromarray(mixed.astype(np.uint8))
197
 
198
  process_time = time.time() - start_time
199
+ log_message(f"✅ Colorização concluída em {process_time:.1f}s")
200
 
201
+ return result
202
 
203
  except Exception as e:
204
+ log_message(f"❌ Erro na colorização: {str(e)}")
205
+ return image # Retorna original em caso de erro
 
 
206
 
207
+ def save_image(image, prefix="colorized"):
208
+ """Salva imagem para download"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  try:
210
  if image is None:
211
  return None
212
 
213
  timestamp = time.strftime("%Y%m%d_%H%M%S")
 
214
 
215
  temp_file = tempfile.NamedTemporaryFile(
216
  delete=False,
 
222
  image.save(temp_file.name, "PNG", optimize=True)
223
 
224
  file_size = os.path.getsize(temp_file.name) // 1024
225
+ log_message(f"Imagem salva: {temp_file.name} ({file_size}KB)")
226
 
227
  return temp_file.name
228
 
229
  except Exception as e:
230
+ log_message(f" Erro ao salvar: {str(e)}")
231
  return None
232
 
233
  def create_comparison(original, colorized):
 
237
  return None
238
 
239
  # Redimensionar para mesma altura
240
+ target_height = 400
241
+ target_width_orig = int(original.width * (target_height / original.height))
242
+ target_width_color = int(colorized.width * (target_height / colorized.height))
243
 
244
+ original_resized = original.resize((target_width_orig, target_height), Image.Resampling.LANCZOS)
245
+ colorized_resized = colorized.resize((target_width_color, target_height), Image.Resampling.LANCZOS)
246
 
247
  # Criar imagem combinada
248
+ total_width = original_resized.width + colorized_resized.width + 20
249
+ total_height = target_height + 60
 
 
 
250
 
251
  comparison = Image.new('RGB', (total_width, total_height), color=(240, 240, 240))
252
 
253
+ from PIL import ImageDraw
254
 
255
  draw = ImageDraw.Draw(comparison)
256
 
257
+ # Títulos simples
258
+ draw.text((10, 10), "ORIGINAL", fill=(100, 100, 100))
259
+ draw.text((original_resized.width + 30, 10), "COLORIZED", fill=(0, 150, 0))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
  # Colar imagens
262
+ comparison.paste(original_resized, (0, 40))
263
+ comparison.paste(colorized_resized, (original_resized.width + 20, 40))
264
 
265
+ log_message("✅ Comparação criada")
266
  return comparison
267
 
268
  except Exception as e:
269
+ log_message(f" Erro na comparação: {str(e)}")
270
  return None
271
 
272
+ # Importar ImageDraw aqui para evitar erro
273
+ from PIL import ImageDraw
274
+
275
  # ========== INTERFACE GRADIO ==========
276
 
277
  print("🎨 Criando interface Image Colorizer...")
278
 
279
+ # Criar interface SEM css no construtor
280
+ with gr.Blocks(title="🎨 Image Colorizer") as demo:
281
+
282
+ # Aplicar CSS depois
283
+ demo.css = """
284
+ .header {
285
+ text-align: center;
286
+ padding: 20px;
287
+ background: linear-gradient(135deg, #ff7e5f 0%, #feb47b 100%);
288
+ border-radius: 10px;
289
+ color: white;
290
+ margin-bottom: 20px;
291
+ }
292
+ .card {
293
+ padding: 15px;
294
+ background: white;
295
+ border-radius: 8px;
296
+ border: 1px solid #e0e0e0;
297
+ margin-bottom: 10px;
298
+ }
299
+ .btn-primary {
300
+ background: linear-gradient(135deg, #ff7e5f 0%, #feb47b 100%);
301
+ color: white;
302
+ border: none;
303
+ padding: 12px 24px;
304
+ border-radius: 8px;
305
+ font-weight: bold;
306
+ margin: 10px 0;
307
+ }
308
+ .btn-primary:hover {
309
+ transform: translateY(-2px);
310
+ box-shadow: 0 4px 12px rgba(255, 126, 95, 0.3);
311
+ }
312
+ .style-btn {
313
+ padding: 10px 15px;
314
+ margin: 5px;
315
+ border-radius: 6px;
316
+ border: 1px solid #ddd;
317
+ background: white;
318
+ }
319
+ .style-btn:hover {
320
+ border-color: #ff7e5f;
321
+ background: #fff5f2;
322
+ }
323
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
  # Cabeçalho
326
  gr.HTML("""
327
+ <div class="header">
328
+ <h1 style="margin: 0;">🎨 Image Colorizer</h1>
329
+ <p style="margin: 5px 0 0 0;">App</p>
330
+ <p style="margin: 5px 0 0 0; font-size: 0.9em;">Colorize fotos preto e branco automaticamente</p>
 
 
 
331
  </div>
332
  """)
333
 
334
  with gr.Row():
335
+ # Coluna esquerda
336
  with gr.Column(scale=1):
337
+ with gr.Column(elem_classes="card"):
338
  gr.Markdown("### 📤 Upload da Foto")
 
339
  image_input = gr.Image(
340
  type="pil",
341
+ label="Clique ou arraste uma imagem",
342
+ height=150
 
343
  )
344
 
345
+ with gr.Column(elem_classes="card"):
346
+ gr.Markdown("### ⚙️ Configurações")
347
 
348
+ gr.Markdown("**Estilo de colorização:**")
349
  with gr.Row():
350
  style_realistic = gr.Button("Realista", elem_classes="style-btn")
351
  style_vibrant = gr.Button("Vibrante", elem_classes="style-btn")
 
357
  intensity_slider = gr.Slider(
358
  minimum=0.1,
359
  maximum=1.0,
360
+ value=0.7,
361
  step=0.1,
362
  label="",
363
+ info="0.1 = Suave | 1.0 = Intenso"
364
  )
365
 
366
  colorize_btn = gr.Button(
367
+ "🎨 Colorizar Imagem",
368
+ elem_classes="btn-primary",
369
  size="lg"
370
  )
371
 
372
+ # Coluna direita
373
  with gr.Column(scale=1):
374
+ with gr.Column(elem_classes="card"):
375
+ gr.Markdown("### 📊 Resultado")
376
  status_output = gr.Markdown(
377
+ value="**Status:** Aguardando imagem...",
378
+ elem_classes="card"
379
  )
380
 
381
+ with gr.Tabs():
382
  with gr.TabItem("🔄 Comparação"):
383
  comparison_output = gr.Image(
384
  type="pil",
385
+ label="Antes e Depois",
386
+ height=300
 
387
  )
388
 
389
+ with gr.TabItem("📷 Original"):
390
  original_output = gr.Image(
391
  type="pil",
392
+ label="Original",
393
+ height=300
 
394
  )
395
 
396
  with gr.TabItem("🌈 Colorizada"):
397
  colorized_output = gr.Image(
398
  type="pil",
399
+ label="Colorizada",
400
+ height=300
 
401
  )
402
 
403
+ with gr.Column(elem_classes="card"):
404
  gr.Markdown("### 💾 Download")
405
  with gr.Row():
406
+ download_colorized = gr.Button("📥 Baixar Colorizada")
407
+ download_comparison = gr.Button("📊 Baixar Comparação")
 
 
 
 
 
 
 
 
408
 
409
  download_file = gr.File(
410
  label="Arquivo para download",
 
412
  )
413
 
414
  # Informações
415
+ with gr.Accordion("📖 Como usar", open=False):
 
 
 
 
 
 
 
 
 
 
 
 
416
  gr.Markdown("""
417
+ ## Instruções:
418
+ 1. **Carregue** uma foto em preto e branco
419
+ 2. **Escolha** o estilo de colorização
420
+ 3. **Ajuste** a intensidade das cores
421
+ 4. **Clique** em "Colorizar Imagem"
422
+ 5. **Compare** os resultados
423
+ 6. **Baixe** a imagem colorizada
424
+
425
+ ## Dicas:
426
+ - **Realista**: Tons naturais para retratos
427
+ - **Vibrante**: Cores vivas para paisagens
428
+ - **Vintage**: Estilo antigo e nostálgico
429
+ - Use intensidade 0.7-0.8 para resultados naturais
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430
  """)
431
 
432
  # Rodapé
433
+ gr.HTML("""
434
+ <div style="text-align: center; margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px;">
435
+ <p style="margin: 0; font-weight: bold; color: #333;">
 
 
 
 
 
 
 
 
436
  🎨 Image Colorizer - App 5 do Photoshop AI Ecosystem
437
  </p>
438
+ <p style="margin: 5px 0 0 0; color: #666; font-size: 0.9em;">
439
+ Cada app tem uma função específica Este app apenas coloriza imagens
 
 
 
440
  </p>
 
 
 
 
 
 
 
 
 
 
 
441
  </div>
442
  """)
443
 
 
459
 
460
  # Processar imagem
461
  def process_colorization(image, style, intensity):
462
+ log_message(f"Processando - Estilo: {style}, Intensidade: {intensity}")
463
 
464
  if image is None:
465
+ return None, None, None, "❌ Por favor, carregue uma imagem primeiro"
466
 
467
+ # Validar imagem
468
+ valid_img, msg = validate_image(image)
469
+ if valid_img is None:
470
+ return None, None, None, f"❌ {msg}"
471
+
472
+ # Redimensionar se necessário
473
+ if max(valid_img.size) > MAX_IMAGE_SIZE:
474
+ valid_img = resize_image(valid_img, MAX_IMAGE_SIZE)
475
 
476
+ # Aplicar colorização
477
+ colorized = apply_colorization(valid_img, style, intensity)
478
 
479
  # Criar comparação
480
+ comparison = create_comparison(valid_img, colorized)
481
 
482
+ # Mensagem de status
483
+ status = f"""
484
+ **Colorização aplicada com sucesso!**
485
+
486
+ **Detalhes:**
487
+ Estilo: {style.title()}
488
+ Intensidade: {intensity*100:.0f}%
489
+ Tamanho original: {valid_img.size[0]}×{valid_img.size[1]}px
490
+ Tamanho colorizado: {colorized.size[0]}×{colorized.size[1]}px
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
 
492
+ **Próximo passo:** Veja os resultados nas abas acima ou faça download.
493
+ """
494
+
495
+ return valid_img, colorized, comparison, status
496
 
497
  colorize_btn.click(
498
  fn=process_colorization,
 
502
 
503
  # Downloads
504
  download_colorized.click(
505
+ fn=save_image,
506
  inputs=[colorized_output],
507
  outputs=[download_file]
508
  )
509
 
510
  download_comparison.click(
511
+ fn=save_image,
512
  inputs=[comparison_output],
513
  outputs=[download_file]
514
  )
 
516
  # Limpar ao carregar nova imagem
517
  def clear_on_upload(image):
518
  if image is None:
519
+ return None, None, None, "**Status:** Aguardando imagem..."
520
 
521
+ valid_img, msg = validate_image(image)
522
  if valid_img is None:
523
+ return None, None, None, f"❌ {msg}"
524
 
525
+ status = f"""
526
+ **Imagem carregada com sucesso!**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
 
528
+ **Detalhes:**
529
+ • Tamanho: {valid_img.size[0]}×{valid_img.size[1]}px
530
+ • Formato: {valid_img.mode}
531
+
532
+ **Próximos passos:**
533
+ 1. Escolha um estilo de colorização
534
+ 2. Ajuste a intensidade das cores
535
+ 3. Clique em "Colorizar Imagem"
536
+ """
537
+
538
+ return None, None, None, status
539
 
540
  image_input.change(
541
  fn=clear_on_upload,
 
546
  print("=" * 60)
547
  print("✅ APP 5: IMAGE COLORIZER PRONTO!")
548
  print("=" * 60)
549
+ print("📦 Versão simplificada e funcional")
 
 
 
 
 
 
550
  print("=" * 60)
551
 
552
  # O Hugging Face Spaces cuida do demo.launch()