Update app.py
Browse files
app.py
CHANGED
@@ -57,10 +57,8 @@ def predict_single(image_pil, weights=(0.45, 0.25, 0.30)):
|
|
57 |
preds_ensemble[:, mel_idx] = (0.5 * preds_ensemble[:, mel_idx] + 0.5 * pred_d[:, mel_idx])
|
58 |
|
59 |
return {
|
60 |
-
"ensemble": preds_ensemble[0],
|
61 |
-
"
|
62 |
-
"resnet50": pred_r[0],
|
63 |
-
"densenet201": pred_d[0]
|
64 |
}
|
65 |
|
66 |
# ---- Grad-CAM ----
|
@@ -95,6 +93,11 @@ def make_gradcam(image_pil, model, last_conv_layer_name, class_index):
|
|
95 |
heatmap = tf.maximum(heatmap, 0) / (tf.math.reduce_max(heatmap) + 1e-8)
|
96 |
heatmap = heatmap.numpy()
|
97 |
|
|
|
|
|
|
|
|
|
|
|
98 |
heatmap = np.uint8(255 * heatmap)
|
99 |
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
|
100 |
|
@@ -103,52 +106,51 @@ def make_gradcam(image_pil, model, last_conv_layer_name, class_index):
|
|
103 |
|
104 |
return cv2.cvtColor(superimposed_img, cv2.COLOR_BGR2RGB)
|
105 |
|
106 |
-
# ---- Fonction Gradio (avec
|
107 |
def gradio_predict(image_pil):
|
108 |
if image_pil is None: return "Veuillez uploader une image.", None, None
|
109 |
try:
|
110 |
all_preds = predict_single(image_pil)
|
111 |
ensemble_probs = all_preds["ensemble"]
|
112 |
|
113 |
-
# ===== NOUVELLE LOGIQUE DE DIAGNOSTIC (bien meilleure) =====
|
114 |
-
# 1. On trouve la classe avec le plus haut score
|
115 |
top_class_idx = np.argmax(ensemble_probs)
|
116 |
top_class_name = CLASS_NAMES[top_class_idx]
|
117 |
-
|
118 |
-
# 2. Le diagnostic global est celui de cette classe unique
|
119 |
global_diag = diagnosis_map[top_class_name]
|
120 |
-
# ==========================================================
|
121 |
|
122 |
-
# Préparation du bar plot (inchangé)
|
123 |
confidences = {CLASS_NAMES[i]: float(ensemble_probs[i]) for i in range(len(CLASS_NAMES))}
|
124 |
df = pd.DataFrame.from_dict(confidences, orient='index', columns=['Probabilité'])
|
125 |
df = df.sort_values(by='Probabilité', ascending=False)
|
126 |
df.index.name = "Classe"
|
127 |
df = df.reset_index()
|
128 |
|
129 |
-
#
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
"xception": "
|
140 |
-
"resnet50": "conv5_block3_out",
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
|
|
|
|
|
|
|
|
148 |
|
149 |
return global_diag, df, gradcam_img
|
|
|
150 |
except Exception as e:
|
151 |
-
print(f"Erreur dans gradio_predict : {e}")
|
152 |
import traceback
|
153 |
traceback.print_exc()
|
154 |
return "Erreur lors du traitement de l'image.", None, None
|
@@ -157,8 +159,7 @@ def gradio_predict(image_pil):
|
|
157 |
example_paths = ["exemple1.jpg", "exemple2.jpg", "exemple3.jpg"]
|
158 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
159 |
gr.Markdown("# Analyse de lésions cutanées (Ensemble de modèles + Grad-CAM)")
|
160 |
-
gr.Markdown("Cet outil propose une prédiction de la nature de la lésion (Bénin/Malin) avec explication visuelle dynamique.
|
161 |
-
"Le diagnostic global est déterminé par la classe unique ayant le score le plus élevé.")
|
162 |
with gr.Row():
|
163 |
with gr.Column(scale=1):
|
164 |
input_image = gr.Image(type="pil", label="Uploader une image de lésion")
|
|
|
57 |
preds_ensemble[:, mel_idx] = (0.5 * preds_ensemble[:, mel_idx] + 0.5 * pred_d[:, mel_idx])
|
58 |
|
59 |
return {
|
60 |
+
"ensemble": preds_ensemble[0], "xception": pred_x[0],
|
61 |
+
"resnet50": pred_r[0], "densenet201": pred_d[0]
|
|
|
|
|
62 |
}
|
63 |
|
64 |
# ---- Grad-CAM ----
|
|
|
93 |
heatmap = tf.maximum(heatmap, 0) / (tf.math.reduce_max(heatmap) + 1e-8)
|
94 |
heatmap = heatmap.numpy()
|
95 |
|
96 |
+
# ===== CORRECTION FINALE ET CRUCIALE =====
|
97 |
+
# On redimensionne la heatmap (ex: 7x7) à la taille de l'image (ex: 224x224)
|
98 |
+
heatmap = cv2.resize(heatmap, (img_resized.shape[1], img_resized.shape[0]))
|
99 |
+
# =======================================
|
100 |
+
|
101 |
heatmap = np.uint8(255 * heatmap)
|
102 |
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
|
103 |
|
|
|
106 |
|
107 |
return cv2.cvtColor(superimposed_img, cv2.COLOR_BGR2RGB)
|
108 |
|
109 |
+
# ---- Fonction Gradio (avec gestion d'erreur pour Grad-CAM) ----
|
110 |
def gradio_predict(image_pil):
|
111 |
if image_pil is None: return "Veuillez uploader une image.", None, None
|
112 |
try:
|
113 |
all_preds = predict_single(image_pil)
|
114 |
ensemble_probs = all_preds["ensemble"]
|
115 |
|
|
|
|
|
116 |
top_class_idx = np.argmax(ensemble_probs)
|
117 |
top_class_name = CLASS_NAMES[top_class_idx]
|
|
|
|
|
118 |
global_diag = diagnosis_map[top_class_name]
|
|
|
119 |
|
|
|
120 |
confidences = {CLASS_NAMES[i]: float(ensemble_probs[i]) for i in range(len(CLASS_NAMES))}
|
121 |
df = pd.DataFrame.from_dict(confidences, orient='index', columns=['Probabilité'])
|
122 |
df = df.sort_values(by='Probabilité', ascending=False)
|
123 |
df.index.name = "Classe"
|
124 |
df = df.reset_index()
|
125 |
|
126 |
+
# --- BLOC GRAD-CAM SÉCURISÉ ---
|
127 |
+
gradcam_img = None # Initialisation à None
|
128 |
+
try:
|
129 |
+
model_confidences = {
|
130 |
+
"xception": all_preds["xception"][top_class_idx],
|
131 |
+
"resnet50": all_preds["resnet50"][top_class_idx],
|
132 |
+
"densenet201": all_preds["densenet201"][top_class_idx]
|
133 |
+
}
|
134 |
+
explainer_model_name = max(model_confidences, key=model_confidences.get)
|
135 |
+
|
136 |
+
model_map = {"xception": model_xcept, "resnet50": model_resnet50, "densenet201": model_densenet}
|
137 |
+
layer_map = {"xception": "block14_sepconv2_act", "resnet50": "conv5_block3_out", "densenet201": "relu"}
|
138 |
+
|
139 |
+
explainer_model = model_map[explainer_model_name]
|
140 |
+
explainer_layer = layer_map[explainer_model_name]
|
141 |
+
|
142 |
+
print(f"Génération du Grad-CAM avec le modèle '{explainer_model_name}' sur la couche '{explainer_layer}'.")
|
143 |
+
gradcam_img = make_gradcam(image_pil, explainer_model, explainer_layer, class_index=top_class_idx)
|
144 |
+
except Exception as e:
|
145 |
+
print(f"--- ERREUR LORS DE LA GÉNÉRATION DE GRAD-CAM (le reste de l'app continue) ---")
|
146 |
+
print(e)
|
147 |
+
# gradcam_img reste à None, Gradio affichera une boîte vide
|
148 |
+
# --- FIN DU BLOC SÉCURISÉ ---
|
149 |
|
150 |
return global_diag, df, gradcam_img
|
151 |
+
|
152 |
except Exception as e:
|
153 |
+
print(f"Erreur majeure dans gradio_predict : {e}")
|
154 |
import traceback
|
155 |
traceback.print_exc()
|
156 |
return "Erreur lors du traitement de l'image.", None, None
|
|
|
159 |
example_paths = ["exemple1.jpg", "exemple2.jpg", "exemple3.jpg"]
|
160 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
161 |
gr.Markdown("# Analyse de lésions cutanées (Ensemble de modèles + Grad-CAM)")
|
162 |
+
gr.Markdown("Cet outil propose une prédiction de la nature de la lésion (Bénin/Malin) avec explication visuelle dynamique.")
|
|
|
163 |
with gr.Row():
|
164 |
with gr.Column(scale=1):
|
165 |
input_image = gr.Image(type="pil", label="Uploader une image de lésion")
|