SucoCafe commited on
Commit
e665abb
·
1 Parent(s): 9fe6164

Refine Bicho Mineiro advanced stage diagnostic and update UI

Browse files
Files changed (4) hide show
  1. app.py +54 -11
  2. static/script.js +2 -0
  3. static/style.css +8 -2
  4. templates/index.html +6 -0
app.py CHANGED
@@ -64,15 +64,44 @@ def get_text_features(model, text_descriptions: Dict[str, str], device="cpu"):
64
 
65
  # --- DICIONÁRIO DE DESCRIÇÕES OTIMIZADO PARA LONGCLIP ---
66
  text_descriptions_longclip = {
67
- "Mancha de Olho Pardo (Cercospora)": "Defined by highly symmetrical, circular 'brown eye' lesions with a multi-zonal color palette. The focal point is a pale, ash-grey or silvery-parchment necrotic center, which is strictly separated from a deep chocolate-brown or reddish-umber perimeter ring. A vivid, neon-like lemon-yellow chlorotic halo consistently radiates outward from the brown border. Unlike Phoma, these spots are perfectly geometric and rarely start at the margins. The texture is thin and dry but not cracked, maintaining a distinct target-like appearance that contrasts sharply against the healthy green leaf blade. It is visually distinguished by this tri-colored concentricity: ash-grey core, dark-brown ring, and vibrant yellow halo.",
68
-
69
- "Mancha de Phoma": "Characterized by heavy, non-transparent, and deeply pigmented jet-black or carbon-colored necrotic masses. These lesions are defined by an absolute opacity; no light passes through the tissue. A key morphological feature is the 'undulating concentric rings' that look like dried black ink ripples. These spots typically start at the leaf tips and margins, appearing as a thick, charred, and matte-black solid surface. It is strictly distinguished from Leaf Miner by its intense black saturation and the total absence of any silvery, translucent, or hollow epidermal skin.",
70
-
71
- "Bicho Mineiro do Café": "Presents as a very light-colored, silvery-white or pale-tan 'hollow blister' where the leaf surface looks like a thin, semi-transparent film of dried plastic or parchment. The critical visual trigger is the high-key, bright luminosity of the silvery mine, which contrasts with the dark fungal spots. The lesion represents a structural void or empty 'tunnel' between layers, often containing small black dots of debris (frass). It is strictly distinguished from Phoma by its pale, reflective, and paper-like transparency, lacking any deep-black, charred, or rippled solid tissue.",
72
-
73
- "Ferrugem do Cafeeiro": "Visually dominated by an exogenous, granular coating of vivid cadmium-orange fungal spores that sit on top of the leaf surface like a layer of fine, loose dust or pollen. The defining characteristic is the 'powdery' and 'fuzzy' texture of the orange clusters, which can be rubbed off, unlike solid necrotic tissue. These orange pustules have soft, blurred edges and appear as an accumulation of tiny particles rather than a flat stain. On the upper side, it manifests as diffuse, translucent yellowish spots with no sharp borders. It is strictly distinguished from Leaf Miner by the absence of papery skin and the presence of this additive, vibrant orange fungal dust."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
 
 
76
  @app.route('/')
77
  def home():
78
  return render_template('index.html')
@@ -158,6 +187,7 @@ def predict():
158
 
159
  results_list = []
160
  image_urls = []
 
161
 
162
  print("\nIniciando classificação dos recortes com LongCLIP...")
163
  for file_name in os.listdir(output_dir):
@@ -177,10 +207,15 @@ def predict():
177
 
178
  top_idx = np.argmax(probs)
179
  predicted_class = class_names[top_idx]
 
 
180
  results_list.append(predicted_class)
 
 
181
  image_urls.append({
182
  "url": f"/static/outputs/{file_name}",
183
- "classe": predicted_class
 
184
  })
185
  print(f"Arquivo {file_name}: {predicted_class} ({probs[top_idx]*100:.2f}%)")
186
 
@@ -199,14 +234,22 @@ def predict():
199
  "contagem": {},
200
  "mais_frequente": "Nenhuma detecção encontrada",
201
  "total": 0,
202
- "imagens": []
 
203
  })
204
 
 
 
 
 
 
 
205
  return jsonify({
206
  "contagem": dict(contagem),
207
- "mais_frequente": contagem.most_common(1)[0][0],
208
  "total": sum(contagem.values()),
209
- "imagens": image_urls
 
210
  })
211
 
212
  except Exception as e:
 
64
 
65
  # --- DICIONÁRIO DE DESCRIÇÕES OTIMIZADO PARA LONGCLIP ---
66
  text_descriptions_longclip = {
67
+ "Mancha de Olho Pardo (Cercospora)": (
68
+ "A close-up photograph of a green coffee leaf showing scattered, circular or oval spots. "
69
+ "The most prominent feature of each spot is a distinct, tiny bright white or pale grey center. "
70
+ "This pale central dot is completely surrounded by a thick, dark reddish-brown ring, "
71
+ "creating a clear 'eye' or 'bullseye' appearance. A subtle yellow halo surrounds the dark brown border."
72
+ ),
73
+
74
+ "Ferrugem do Cafeeiro": (
75
+ "A highly detailed, close-up photograph of a green coffee leaf infected with Coffee Rust. "
76
+ "The most striking visual feature is the presence of bright yellow to vivid cadmium-orange patches. "
77
+ "These patches have a highly textured, three-dimensional granular and powdery appearance, "
78
+ "looking exactly like thick orange powder, fine loose dust, or tiny accumulated pollen spores sitting entirely on top of the leaf surface. "
79
+ "The edges of these bright orange spots are soft, diffuse, and blurred, seamlessly blending into the surrounding green leaf tissue. "
80
+ "There are absolutely no sharp, well-defined dark borders. "
81
+ "The spots are irregular in shape and frequently merge together to form large, amorphous, powdery orange masses. "
82
+ "It completely lacks any pale central white dot, completely lacks distinct dark brown concentric rings, "
83
+ "and is clearly characterized by its vibrant, powdery, and dusty orange texture."
84
+ ),
85
+ "Bicho Mineiro do Café": (
86
+ "A close-up photograph of a green coffee leaf damaged by the Coffee Leaf Miner insect. "
87
+ "The visual signature covers both early and severe advanced stages. "
88
+ "In the classic stage, it forms a thin, pale, translucent, papery 'mine' or hollow blister. "
89
+ "In the severe advanced stage, these mines coalesce and merge into large, highly irregular, dark-brown necrotic galleries and sprawling dry patches. "
90
+ "Even when dark and necrotic, the defining features are its irregular serpentine edges, the dry parchment-like texture of the dead skin, and partial translucency. "
91
+ "Crucially, this damage is scattered across the middle of the leaf lamina (the blade). "
92
+ "It completely lacks tiny black fungal fruiting dots."
93
+ ),
94
+ "Mancha de Phoma": (
95
+ "A close-up photograph of a green coffee leaf severely infected with Phoma Leaf Spot. "
96
+ "The absolute defining characteristic is a thick, solid, opaque, dark necrotic mass, usually dark-brown to pitch-black. "
97
+ "This solid dark lesion almost always originates directly on the extreme margins (edges) or the tip of the leaf, aggressively spreading inward. "
98
+ "It forms a solid, compact block of thick, dead rotting tissue, never a network of irregular serpentine galleries. "
99
+ "It often causes the leaf edge to curl and tear. "
100
+ "It frequently has tiny black dots (fungal fruiting bodies) inside the solid dark mass."
101
+ )
102
  }
103
 
104
+
105
  @app.route('/')
106
  def home():
107
  return render_template('index.html')
 
187
 
188
  results_list = []
189
  image_urls = []
190
+ class_probs = []
191
 
192
  print("\nIniciando classificação dos recortes com LongCLIP...")
193
  for file_name in os.listdir(output_dir):
 
207
 
208
  top_idx = np.argmax(probs)
209
  predicted_class = class_names[top_idx]
210
+ top_prob = float(probs[top_idx])
211
+
212
  results_list.append(predicted_class)
213
+ class_probs.append(top_prob)
214
+
215
  image_urls.append({
216
  "url": f"/static/outputs/{file_name}",
217
+ "classe": predicted_class,
218
+ "probabilidade": top_prob
219
  })
220
  print(f"Arquivo {file_name}: {predicted_class} ({probs[top_idx]*100:.2f}%)")
221
 
 
234
  "contagem": {},
235
  "mais_frequente": "Nenhuma detecção encontrada",
236
  "total": 0,
237
+ "imagens": [],
238
+ "veracidade": 0.0
239
  })
240
 
241
+ mais_frequente = contagem.most_common(1)[0][0]
242
+
243
+ # Calcular veracidade média para a classe mais frequente
244
+ freq_probs = [prob for cls, prob in zip(results_list, class_probs) if cls == mais_frequente]
245
+ veracidade = (sum(freq_probs) / len(freq_probs)) * 100 if freq_probs else 0.0
246
+
247
  return jsonify({
248
  "contagem": dict(contagem),
249
+ "mais_frequente": mais_frequente,
250
  "total": sum(contagem.values()),
251
+ "imagens": image_urls,
252
+ "veracidade": veracidade
253
  })
254
 
255
  except Exception as e:
static/script.js CHANGED
@@ -120,6 +120,8 @@ document.addEventListener('DOMContentLoaded', () => {
120
 
121
  // Update Text
122
  mainDisease.textContent = data.mais_frequente;
 
 
123
 
124
  // Render Chart
125
  renderChart(data.contagem);
 
120
 
121
  // Update Text
122
  mainDisease.textContent = data.mais_frequente;
123
+
124
+
125
 
126
  // Render Chart
127
  renderChart(data.contagem);
static/style.css CHANGED
@@ -296,12 +296,18 @@ header {
296
  }
297
 
298
  .stats-grid {
299
- display: flex;
300
- flex-direction: column;
301
  gap: 1rem;
302
  margin-bottom: 2rem;
303
  }
304
 
 
 
 
 
 
 
305
  .stat-card {
306
  background: #ffffff;
307
  border-radius: 12px;
 
296
  }
297
 
298
  .stats-grid {
299
+ display: grid;
300
+ grid-template-columns: 1fr 1fr;
301
  gap: 1rem;
302
  margin-bottom: 2rem;
303
  }
304
 
305
+ @media (max-width: 600px) {
306
+ .stats-grid {
307
+ grid-template-columns: 1fr;
308
+ }
309
+ }
310
+
311
  .stat-card {
312
  background: #ffffff;
313
  border-radius: 12px;
templates/index.html CHANGED
@@ -60,6 +60,12 @@
60
  <span class="stat-label"><i class="ph-bold ph-virus"></i> Doença Principal</span>
61
  <span class="stat-value" id="main-disease">-</span>
62
  </div>
 
 
 
 
 
 
63
  </div>
64
 
65
  <div class="chart-container">
 
60
  <span class="stat-label"><i class="ph-bold ph-virus"></i> Doença Principal</span>
61
  <span class="stat-value" id="main-disease">-</span>
62
  </div>
63
+ <div class="stat-card highlight" style="display: flex; align-items: center; justify-content: center; padding: 10px;">
64
+ <p style="font-size: 0.85rem; color: #718096; margin: 0; text-align: center; line-height: 1.4;">
65
+ <i class="ph-bold ph-warning-circle" style="font-size: 1.2rem; color: var(--accent-primary); vertical-align: middle; margin-bottom: 5px;"></i><br>
66
+ Lembre-se que a IA ainda pode cometer erros na classificação.
67
+ </p>
68
+ </div>
69
  </div>
70
 
71
  <div class="chart-container">