Spaces:
Runtime error
Runtime error
Refine Bicho Mineiro advanced stage diagnostic and update UI
Browse files- app.py +54 -11
- static/script.js +2 -0
- static/style.css +8 -2
- 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)":
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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":
|
| 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:
|
| 300 |
-
|
| 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">
|