rmayormartins commited on
Commit
84845c0
·
1 Parent(s): 7731d94
Files changed (2) hide show
  1. app.py +140 -87
  2. requirements.txt +1 -1
app.py CHANGED
@@ -24,7 +24,8 @@ print(f"Device: {device}")
24
  # Modelos disponíveis
25
  MODELS = {
26
  'ResNet18': models.resnet18,
27
- 'ResNet34': models.resnet34,
 
28
  'MobileNetV2': models.mobilenet_v2
29
  }
30
 
@@ -39,14 +40,14 @@ class AppState:
39
  self.class_dirs = []
40
  self.class_labels = ['classe_0', 'classe_1']
41
  self.num_classes = 2
42
- self.image_queue = [] # Para armazenar imagens uploaded
43
 
44
  state = AppState()
45
 
46
  def setup_classes(num_classes_value):
47
  """Configura número de classes"""
48
  try:
49
- state.num_classes = int(num_classes_value)
50
  state.dataset_path = tempfile.mkdtemp()
51
  state.class_labels = [f'classe_{i}' for i in range(state.num_classes)]
52
 
@@ -73,16 +74,26 @@ def set_class_labels(labels_text):
73
  except Exception as e:
74
  return f"❌ Erro: {str(e)}"
75
 
76
- def add_image_to_queue(image):
77
- """Adiciona imagem à fila"""
78
- if image is None:
79
- return "❌ Selecione uma imagem", 0
80
 
81
- state.image_queue.append(image)
82
- return f"✅ Imagem adicionada à fila. Total: {len(state.image_queue)}", len(state.image_queue)
 
 
 
 
 
 
 
 
 
 
83
 
84
- def save_images_to_class(class_id, clear_queue=True):
85
- """Salva todas as imagens da fila para uma classe"""
86
  try:
87
  if not state.image_queue:
88
  return "❌ Nenhuma imagem na fila"
@@ -90,10 +101,7 @@ def save_images_to_class(class_id, clear_queue=True):
90
  if not state.class_dirs:
91
  return "❌ Configure as classes primeiro"
92
 
93
- class_idx = int(class_id)
94
- if class_idx >= len(state.class_dirs):
95
- return "❌ Classe inválida"
96
-
97
  class_dir = state.class_dirs[class_idx]
98
  count = 0
99
 
@@ -107,21 +115,19 @@ def save_images_to_class(class_id, clear_queue=True):
107
  except Exception as e:
108
  print(f"Erro salvando imagem {i}: {e}")
109
 
110
- if clear_queue:
111
- state.image_queue = []
112
-
113
  class_name = state.class_labels[class_idx]
114
  return f"✅ {count} imagens salvas em '{class_name}'"
115
  except Exception as e:
116
  return f"❌ Erro: {str(e)}"
117
 
118
- def clear_image_queue():
119
- """Limpa a fila de imagens"""
120
  state.image_queue = []
121
  return "✅ Fila limpa", 0
122
 
123
  def prepare_data(batch_size):
124
- """Prepara dados para treinamento"""
125
  try:
126
  if not state.dataset_path:
127
  return "❌ Configure as classes primeiro"
@@ -157,7 +163,7 @@ def prepare_data(batch_size):
157
  return f"❌ Erro: {str(e)}"
158
 
159
  def train_model(model_name, epochs, lr):
160
- """Treina o modelo"""
161
  try:
162
  if state.train_loader is None:
163
  return "❌ Prepare os dados primeiro"
@@ -208,7 +214,7 @@ def train_model(model_name, epochs, lr):
208
  return f"❌ Erro: {str(e)}"
209
 
210
  def evaluate_model():
211
- """Avalia o modelo"""
212
  try:
213
  if state.model is None or state.test_loader is None:
214
  return "❌ Modelo/dados não disponíveis"
@@ -268,7 +274,7 @@ def generate_confusion_matrix():
268
  return None
269
 
270
  def predict_image(image):
271
- """Prediz uma única imagem"""
272
  try:
273
  if state.model is None:
274
  return "❌ Treine o modelo primeiro"
@@ -298,87 +304,134 @@ def predict_image(image):
298
  except Exception as e:
299
  return f"❌ Erro: {str(e)}"
300
 
301
- # Interface usando componentes mais antigos/estáveis
302
  def create_interface():
303
- with gr.Blocks(title="🖼️ Classificador Completo") as demo:
304
-
 
305
  gr.Markdown("# 🖼️ Sistema de Classificação de Imagens Completo")
 
306
 
307
- # Configuração
308
- with gr.Group():
309
- gr.Markdown("## 1️⃣ Configuração")
310
- with gr.Row():
311
- num_classes = gr.Number(label="Número de Classes (2-5)", value=2, precision=0)
312
- setup_btn = gr.Button("🔧 Configurar")
313
- setup_status = gr.Textbox(label="Status")
314
 
315
- labels_input = gr.Textbox(label="Rótulos (separados por vírgula)", value="gato,cachorro")
 
316
  labels_btn = gr.Button("🏷️ Definir Rótulos")
317
- labels_status = gr.Textbox(label="Status dos Rótulos")
318
-
319
- # Upload de Imagens
320
- with gr.Group():
321
- gr.Markdown("## 2️⃣ Upload de Imagens")
 
 
 
 
 
 
322
  with gr.Row():
323
- upload_image = gr.Image(type="pil", label="Upload de Imagem")
324
- with gr.Column():
325
- add_btn = gr.Button("➕ Adicionar à Fila")
326
- queue_status = gr.Textbox(label="Fila de Imagens")
327
- queue_count = gr.Number(label="Total na Fila", value=0)
328
 
 
329
  with gr.Row():
330
- class_id = gr.Number(label="Classe (0, 1, 2...)", value=0, precision=0)
331
  save_btn = gr.Button("💾 Salvar Fila na Classe", variant="primary")
332
  clear_btn = gr.Button("🗑️ Limpar Fila")
333
- save_status = gr.Textbox(label="Status do Upload")
334
-
335
- # Treinamento
336
- with gr.Group():
337
- gr.Markdown("## 3️⃣ Preparação e Treinamento")
338
- batch_size = gr.Number(label="Batch Size", value=8, precision=0)
 
 
 
 
 
339
  prepare_btn = gr.Button("⚙️ Preparar Dados", variant="primary")
340
- prepare_status = gr.Textbox(label="Status da Preparação", lines=4)
341
 
 
342
  with gr.Row():
343
- model_choice = gr.Dropdown(choices=list(MODELS.keys()), value="MobileNetV2", label="Modelo")
344
- epochs = gr.Number(label="Épocas", value=5, precision=0)
345
- learning_rate = gr.Number(label="Learning Rate", value=0.001)
 
 
 
346
 
347
- train_btn = gr.Button("🚀 Treinar Modelo", variant="primary")
348
- train_status = gr.Textbox(label="Status do Treinamento", lines=8)
 
349
 
350
- # Avaliação
351
- with gr.Group():
352
- gr.Markdown("## 4️⃣ Avaliação")
353
  with gr.Row():
354
  eval_btn = gr.Button("📊 Avaliar Modelo", variant="primary")
355
- matrix_btn = gr.Button("📈 Matriz de Confusão")
356
 
357
- eval_results = gr.Textbox(label="Relatório de Avaliação", lines=12)
358
- confusion_plot = gr.Image(label="Matriz de Confusão")
359
-
360
- # Predição
361
- with gr.Group():
362
- gr.Markdown("## 5️⃣ Predição")
363
- predict_img = gr.Image(type="pil", label="Imagem para Predição")
364
- predict_btn = gr.Button("🔮 Predizer", variant="primary")
365
- predict_result = gr.Textbox(label="Resultado da Predição", lines=3)
366
-
367
- # Conectar eventos
368
- setup_btn.click(setup_classes, [num_classes], [setup_status])
369
- labels_btn.click(set_class_labels, [labels_input], [labels_status])
370
-
371
- add_btn.click(add_image_to_queue, [upload_image], [queue_status, queue_count])
372
- save_btn.click(save_images_to_class, [class_id], [save_status])
373
- clear_btn.click(clear_image_queue, outputs=[queue_status, queue_count])
374
-
375
- prepare_btn.click(prepare_data, [batch_size], [prepare_status])
376
- train_btn.click(train_model, [model_choice, epochs, learning_rate], [train_status])
377
-
378
- eval_btn.click(evaluate_model, outputs=[eval_results])
379
- matrix_btn.click(generate_confusion_matrix, outputs=[confusion_plot])
380
 
381
- predict_btn.click(predict_image, [predict_img], [predict_result])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
  return demo
384
 
@@ -386,4 +439,4 @@ if __name__ == "__main__":
386
  print("🎯 Criando interface...")
387
  demo = create_interface()
388
  print("🚀 Iniciando aplicação...")
389
- demo.launch(server_name="0.0.0.0", server_port=7860, show_api=False)
 
24
  # Modelos disponíveis
25
  MODELS = {
26
  'ResNet18': models.resnet18,
27
+ 'ResNet34': models.resnet34,
28
+ 'ResNet50': models.resnet50,
29
  'MobileNetV2': models.mobilenet_v2
30
  }
31
 
 
40
  self.class_dirs = []
41
  self.class_labels = ['classe_0', 'classe_1']
42
  self.num_classes = 2
43
+ self.image_queue = []
44
 
45
  state = AppState()
46
 
47
  def setup_classes(num_classes_value):
48
  """Configura número de classes"""
49
  try:
50
+ state.num_classes = max(2, min(5, int(num_classes_value)))
51
  state.dataset_path = tempfile.mkdtemp()
52
  state.class_labels = [f'classe_{i}' for i in range(state.num_classes)]
53
 
 
74
  except Exception as e:
75
  return f"❌ Erro: {str(e)}"
76
 
77
+ def add_images_to_queue(images):
78
+ """Adiciona múltiplas imagens à fila"""
79
+ if not images:
80
+ return "❌ Nenhuma imagem selecionada", len(state.image_queue)
81
 
82
+ count = 0
83
+ for image_file in images:
84
+ try:
85
+ if image_file is not None:
86
+ # Carregar imagem
87
+ img = Image.open(image_file.name).convert('RGB')
88
+ state.image_queue.append(img)
89
+ count += 1
90
+ except Exception as e:
91
+ print(f"Erro processando imagem: {e}")
92
+
93
+ return f"✅ {count} imagens adicionadas. Total na fila: {len(state.image_queue)}", len(state.image_queue)
94
 
95
+ def save_queue_to_class(class_id):
96
+ """Salva fila de imagens para uma classe"""
97
  try:
98
  if not state.image_queue:
99
  return "❌ Nenhuma imagem na fila"
 
101
  if not state.class_dirs:
102
  return "❌ Configure as classes primeiro"
103
 
104
+ class_idx = max(0, min(int(class_id), len(state.class_dirs) - 1))
 
 
 
105
  class_dir = state.class_dirs[class_idx]
106
  count = 0
107
 
 
115
  except Exception as e:
116
  print(f"Erro salvando imagem {i}: {e}")
117
 
118
+ state.image_queue = [] # Limpar fila
 
 
119
  class_name = state.class_labels[class_idx]
120
  return f"✅ {count} imagens salvas em '{class_name}'"
121
  except Exception as e:
122
  return f"❌ Erro: {str(e)}"
123
 
124
+ def clear_queue():
125
+ """Limpa a fila"""
126
  state.image_queue = []
127
  return "✅ Fila limpa", 0
128
 
129
  def prepare_data(batch_size):
130
+ """Prepara dados"""
131
  try:
132
  if not state.dataset_path:
133
  return "❌ Configure as classes primeiro"
 
163
  return f"❌ Erro: {str(e)}"
164
 
165
  def train_model(model_name, epochs, lr):
166
+ """Treina modelo"""
167
  try:
168
  if state.train_loader is None:
169
  return "❌ Prepare os dados primeiro"
 
214
  return f"❌ Erro: {str(e)}"
215
 
216
  def evaluate_model():
217
+ """Avalia modelo"""
218
  try:
219
  if state.model is None or state.test_loader is None:
220
  return "❌ Modelo/dados não disponíveis"
 
274
  return None
275
 
276
  def predict_image(image):
277
+ """Prediz imagem"""
278
  try:
279
  if state.model is None:
280
  return "❌ Treine o modelo primeiro"
 
304
  except Exception as e:
305
  return f"❌ Erro: {str(e)}"
306
 
307
+ # Interface usando Gradio 3.x (sintaxe correta)
308
  def create_interface():
309
+
310
+ # Interface com abas usando Gradio 3.x
311
+ with gr.Blocks() as demo:
312
  gr.Markdown("# 🖼️ Sistema de Classificação de Imagens Completo")
313
+ gr.Markdown("**Versão estável sem bugs - Funcionalidade completa mantida**")
314
 
315
+ with gr.Tab("1️⃣ Configuração"):
316
+ gr.Markdown("### 🎯 Configurar Classes")
317
+ num_classes_input = gr.Number(value=2, label="Número de Classes (2-5)")
318
+ setup_btn = gr.Button("🔧 Configurar Classes", variant="primary")
319
+ setup_output = gr.Textbox(label="Status da Configuração")
 
 
320
 
321
+ gr.Markdown("### 🏷️ Definir Rótulos")
322
+ labels_input = gr.Textbox(value="gato,cachorro", label="Rótulos (separados por vírgula)")
323
  labels_btn = gr.Button("🏷️ Definir Rótulos")
324
+ labels_output = gr.Textbox(label="Status dos Rótulos")
325
+
326
+ # Conectar eventos
327
+ setup_btn.click(setup_classes, inputs=[num_classes_input], outputs=[setup_output])
328
+ labels_btn.click(set_class_labels, inputs=[labels_input], outputs=[labels_output])
329
+
330
+ with gr.Tab("2️⃣ Upload de Imagens"):
331
+ gr.Markdown("### 📤 Upload Múltiplo via Fila")
332
+ images_upload = gr.File(file_count="multiple", label="Selecionar Múltiplas Imagens", file_types=["image"])
333
+ add_btn = gr.Button("➕ Adicionar à Fila")
334
+
335
  with gr.Row():
336
+ queue_output = gr.Textbox(label="Status da Fila")
337
+ queue_count_output = gr.Number(label="Total na Fila", value=0)
 
 
 
338
 
339
+ gr.Markdown("### 💾 Salvar por Classe")
340
  with gr.Row():
341
+ class_id_input = gr.Number(value=0, label="Classe de Destino (0, 1, 2...)")
342
  save_btn = gr.Button("💾 Salvar Fila na Classe", variant="primary")
343
  clear_btn = gr.Button("🗑️ Limpar Fila")
344
+
345
+ save_output = gr.Textbox(label="Status do Upload")
346
+
347
+ # Conectar eventos
348
+ add_btn.click(add_images_to_queue, inputs=[images_upload], outputs=[queue_output, queue_count_output])
349
+ save_btn.click(save_queue_to_class, inputs=[class_id_input], outputs=[save_output])
350
+ clear_btn.click(clear_queue, outputs=[queue_output, queue_count_output])
351
+
352
+ with gr.Tab("3️⃣ Preparação e Treinamento"):
353
+ gr.Markdown("### ⚙️ Preparar Dados")
354
+ batch_size_input = gr.Number(value=8, label="Batch Size")
355
  prepare_btn = gr.Button("⚙️ Preparar Dados", variant="primary")
356
+ prepare_output = gr.Textbox(label="Status da Preparação", lines=4)
357
 
358
+ gr.Markdown("### 🚀 Configurar e Treinar Modelo")
359
  with gr.Row():
360
+ model_input = gr.Dropdown(choices=list(MODELS.keys()), value="MobileNetV2", label="Modelo")
361
+ epochs_input = gr.Number(value=5, label="Épocas")
362
+ lr_input = gr.Number(value=0.001, label="Learning Rate")
363
+
364
+ train_btn = gr.Button("🚀 Iniciar Treinamento", variant="primary")
365
+ train_output = gr.Textbox(label="Status do Treinamento", lines=8)
366
 
367
+ # Conectar eventos
368
+ prepare_btn.click(prepare_data, inputs=[batch_size_input], outputs=[prepare_output])
369
+ train_btn.click(train_model, inputs=[model_input, epochs_input, lr_input], outputs=[train_output])
370
 
371
+ with gr.Tab("4️⃣ Avaliação do Modelo"):
372
+ gr.Markdown("### 📊 Avaliar Desempenho")
 
373
  with gr.Row():
374
  eval_btn = gr.Button("📊 Avaliar Modelo", variant="primary")
375
+ matrix_btn = gr.Button("📈 Gerar Matriz de Confusão")
376
 
377
+ eval_output = gr.Textbox(label="Relatório de Avaliação", lines=12)
378
+ matrix_output = gr.Image(label="Matriz de Confusão")
379
+
380
+ # Conectar eventos
381
+ eval_btn.click(evaluate_model, outputs=[eval_output])
382
+ matrix_btn.click(generate_confusion_matrix, outputs=[matrix_output])
383
+
384
+ with gr.Tab("5️⃣ Predição"):
385
+ gr.Markdown("### 🔮 Predizer Novas Imagens")
386
+ predict_image_input = gr.Image(type="pil", label="Imagem para Predição")
387
+ predict_btn = gr.Button("🔮 Fazer Predição", variant="primary")
388
+ predict_output = gr.Textbox(label="Resultado da Predição", lines=3)
389
+
390
+ # Conectar eventos
391
+ predict_btn.click(predict_image, inputs=[predict_image_input], outputs=[predict_output])
 
 
 
 
 
 
 
 
392
 
393
+ # Informações adicionais
394
+ with gr.Tab("ℹ️ Informações"):
395
+ gr.Markdown("""
396
+ ## 📋 Como Usar Este Sistema
397
+
398
+ ### 1️⃣ **Configuração Inicial**
399
+ - Defina o número de classes (2-5)
400
+ - Configure rótulos personalizados separados por vírgula
401
+
402
+ ### 2️⃣ **Upload de Imagens**
403
+ - Selecione múltiplas imagens
404
+ - Adicione à fila
405
+ - Escolha a classe de destino (0, 1, 2...)
406
+ - Salve a fila na classe escolhida
407
+ - Repita para todas as classes
408
+
409
+ ### 3️⃣ **Treinamento**
410
+ - Configure batch size (recomendado: 8-16)
411
+ - Prepare os dados
412
+ - Escolha modelo (MobileNetV2 = mais rápido)
413
+ - Configure épocas (recomendado: 3-10)
414
+ - Inicie o treinamento
415
+
416
+ ### 4️⃣ **Avaliação**
417
+ - Avalie o modelo para ver métricas
418
+ - Gere matriz de confusão para análise visual
419
+
420
+ ### 5️⃣ **Predição**
421
+ - Teste com novas imagens
422
+ - Veja predições com níveis de confiança
423
+
424
+ ## 🎯 **Dicas para Melhores Resultados**
425
+ - Use pelo menos 10-20 imagens por classe
426
+ - Imagens bem balanceadas entre classes
427
+ - Imagens claras e bem iluminadas
428
+ - Varie poses, ângulos e ambientes
429
+
430
+ ## 🔧 **Modelos Disponíveis**
431
+ - **MobileNetV2**: Rápido, ideal para prototipagem
432
+ - **ResNet18**: Bom equilíbrio velocidade/precisão
433
+ - **ResNet34/50**: Maior precisão, mais lento
434
+ """)
435
 
436
  return demo
437
 
 
439
  print("🎯 Criando interface...")
440
  demo = create_interface()
441
  print("🚀 Iniciando aplicação...")
442
+ demo.launch(server_name="0.0.0.0", server_port=7860)
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- gradio==4.15.0
2
  torch==2.0.1
3
  torchvision==0.15.2
4
  scikit-learn==1.3.0
 
1
+ gradio==3.45.0
2
  torch==2.0.1
3
  torchvision==0.15.2
4
  scikit-learn==1.3.0