Update app.py
Browse files
app.py
CHANGED
|
@@ -6,12 +6,14 @@ from torchvision import transforms
|
|
| 6 |
import torchvision.models as models
|
| 7 |
from torchvision.models import VGG16_Weights, ResNet50_Weights, MobileNet_V2_Weights
|
| 8 |
import os
|
|
|
|
|
|
|
| 9 |
|
| 10 |
# Taille d'entrée pour les modèles
|
| 11 |
INPUT_SIZE = 224
|
| 12 |
|
| 13 |
# Chemins des modèles sauvegardés (adapté pour PyTorch)
|
| 14 |
-
MODEL_PYTORCH_PATH = "VGG16_best_accuracy_0.9660.pth" # Exemple
|
| 15 |
|
| 16 |
# Chargement des classes
|
| 17 |
class_names = ['Healthy', 'Tumor']
|
|
@@ -65,6 +67,50 @@ def predict_with_pytorch(model_path, image, class_names):
|
|
| 65 |
return f"Erreur lors de la prédiction: {e}", None
|
| 66 |
|
| 67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
# Fonction JS pour animer les ballons
|
| 69 |
def show_balloons():
|
| 70 |
st.markdown("""
|
|
@@ -194,18 +240,54 @@ st.markdown("""
|
|
| 194 |
</style>
|
| 195 |
""", unsafe_allow_html=True)
|
| 196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
# Application Streamlit
|
| 198 |
st.markdown('<div class="title">Application de Classification d\'Images</div>', unsafe_allow_html=True)
|
| 199 |
|
| 200 |
menu = st.sidebar.selectbox("Menu", ["🧠 Accueil", "🧠 Classification de l'état cérébral avec VGG16", "Comparatif entre modèles", "👨💻À propos"])
|
| 201 |
|
| 202 |
if menu == "🧠 Accueil":
|
| 203 |
-
st.write("Bienvenue dans notre application de classification d'images. Cette application a été développée pour la classification d'images dans le contexte du **Brain Tumor MRI images**, un dataset médical contenant des images de
|
| 204 |
|
| 205 |
st.write("""
|
| 206 |
Cette application a pour objectif de classer ces images en différentes catégories (**Healthy** Aucun problème: , **Tumor**: Tumeur cérébrale) à l'aide de modèles de machine learning.
|
| 207 |
Nous avons effectué du Transfer Learning sur trois modèles pré entrainés et avons fait un comparatif des trois avant de choisir **VGG16** comme celui avec les meilleurs caractéristiques.
|
| 208 |
-
Ces modèles ont été entraînés sur le dataset Brain Tumor MRI images et peuvent être utilisés pour prédire la catégorie d'une image donnée, en détectant des anomalies ou en validant l'état du
|
| 209 |
""")
|
| 210 |
|
| 211 |
# Création des onglets pour chaque modèle
|
|
@@ -272,7 +354,7 @@ elif menu == "🧠 Classification de l'état cérébral avec VGG16":
|
|
| 272 |
|
| 273 |
# Présentation de la fonctionnalité pour l'utilisateur
|
| 274 |
st.markdown("""
|
| 275 |
-
Cette section vous permet de **classer une image d'état
|
| 276 |
Le modèle utilise **VGG16**, une architecture d'apprentissage profond optimisée pour analyser les images.
|
| 277 |
Voici ce que vous devez faire :
|
| 278 |
1. Téléchargez une image au format `jpg`, `jpeg` ou `png`.
|
|
@@ -290,7 +372,7 @@ elif menu == "🧠 Classification de l'état cérébral avec VGG16":
|
|
| 290 |
|
| 291 |
# Explication pour l'étape suivante
|
| 292 |
st.markdown("""
|
| 293 |
-
Cliquez sur le bouton **Classifier** pour que le modèle analyse l'image et détermine si l'état
|
| 294 |
""")
|
| 295 |
|
| 296 |
# Étape 2 : L'utilisateur clique pour classifier l'image
|
|
@@ -298,6 +380,10 @@ elif menu == "🧠 Classification de l'état cérébral avec VGG16":
|
|
| 298 |
# Appel de la fonction de prédiction avec le modèle ResNet50
|
| 299 |
label, probabilities = predict_with_pytorch(MODEL_PYTORCH_PATH, image, class_names)
|
| 300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
# Affichage du résultat
|
| 302 |
st.markdown(f"""
|
| 303 |
### Résultat de la classification :
|
|
|
|
| 6 |
import torchvision.models as models
|
| 7 |
from torchvision.models import VGG16_Weights, ResNet50_Weights, MobileNet_V2_Weights
|
| 8 |
import os
|
| 9 |
+
from fpdf import FPDF
|
| 10 |
+
import io
|
| 11 |
|
| 12 |
# Taille d'entrée pour les modèles
|
| 13 |
INPUT_SIZE = 224
|
| 14 |
|
| 15 |
# Chemins des modèles sauvegardés (adapté pour PyTorch)
|
| 16 |
+
MODEL_PYTORCH_PATH = "saved_models/VGG16_best_accuracy_0.9660.pth" # Exemple
|
| 17 |
|
| 18 |
# Chargement des classes
|
| 19 |
class_names = ['Healthy', 'Tumor']
|
|
|
|
| 67 |
return f"Erreur lors de la prédiction: {e}", None
|
| 68 |
|
| 69 |
|
| 70 |
+
# Fonction pour générer un PDF avec les prédictions et recommandations
|
| 71 |
+
def generate_pdf(prediction, probabilities, image, model_name):
|
| 72 |
+
pdf = FPDF()
|
| 73 |
+
pdf.set_auto_page_break(auto=True, margin=15)
|
| 74 |
+
pdf.add_page()
|
| 75 |
+
pdf.set_font("Arial", style="B", size=16)
|
| 76 |
+
pdf.cell(200, 10, "Rapport de Prédiction", ln=True, align='C')
|
| 77 |
+
pdf.ln(10)
|
| 78 |
+
|
| 79 |
+
pdf.set_font("Arial", size=12)
|
| 80 |
+
pdf.cell(200, 10, f"Modèle utilisé: {model_name}", ln=True)
|
| 81 |
+
pdf.cell(200, 10, f"Prédiction: {prediction}", ln=True)
|
| 82 |
+
pdf.cell(200, 10, "Probabilités:", ln=True)
|
| 83 |
+
|
| 84 |
+
for i, prob in enumerate(probabilities):
|
| 85 |
+
pdf.cell(200, 10, f"{class_names[i]}: {prob:.2%}", ln=True)
|
| 86 |
+
|
| 87 |
+
pdf.ln(10)
|
| 88 |
+
pdf.cell(200, 10, "Recommandations:", ln=True)
|
| 89 |
+
|
| 90 |
+
recommendations = {
|
| 91 |
+
"Cyst": "Consultez un urologue pour une évaluation approfondie.",
|
| 92 |
+
"Normal": "Aucune intervention n'est requise.",
|
| 93 |
+
"Stone": "Hydratation et suivi avec un spécialiste recommandés.",
|
| 94 |
+
"Tumor": "Consultez un oncologue pour un diagnostic précis."
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
pdf.multi_cell(0, 10, recommendations.get(prediction, "Aucune recommandation disponible."))
|
| 98 |
+
|
| 99 |
+
# Sauvegarde et insertion de l'image
|
| 100 |
+
img_path = "temp_image.jpg"
|
| 101 |
+
image.save(img_path)
|
| 102 |
+
pdf.image(img_path, x=60, w=90)
|
| 103 |
+
|
| 104 |
+
# Générer le PDF en mémoire
|
| 105 |
+
pdf_output = io.BytesIO()
|
| 106 |
+
pdf_bytes = pdf.output(dest='S').encode('latin1') # Générer en mémoire
|
| 107 |
+
pdf_output.write(pdf_bytes)
|
| 108 |
+
pdf_output.seek(0)
|
| 109 |
+
|
| 110 |
+
return pdf_output
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
# Fonction JS pour animer les ballons
|
| 115 |
def show_balloons():
|
| 116 |
st.markdown("""
|
|
|
|
| 240 |
</style>
|
| 241 |
""", unsafe_allow_html=True)
|
| 242 |
|
| 243 |
+
# Identifiants d'accès
|
| 244 |
+
USERNAME = "abdouramandalil"
|
| 245 |
+
PASSWORD = "transferlearning"
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
def check_login():
|
| 249 |
+
""" Vérifie l'authentification de l'utilisateur """
|
| 250 |
+
st.sidebar.header("Connexion")
|
| 251 |
+
username = st.sidebar.text_input("Nom d'utilisateur")
|
| 252 |
+
password = st.sidebar.text_input("Mot de passe", type="password")
|
| 253 |
+
|
| 254 |
+
if st.sidebar.button("Se connecter"):
|
| 255 |
+
if username == USERNAME and password == PASSWORD:
|
| 256 |
+
st.session_state["authenticated"] = True
|
| 257 |
+
st.sidebar.success("Connexion réussie !")
|
| 258 |
+
st.rerun()
|
| 259 |
+
else:
|
| 260 |
+
st.sidebar.error("Identifiants incorrects")
|
| 261 |
+
|
| 262 |
+
def logout():
|
| 263 |
+
st.session_state["authenticated"] = False
|
| 264 |
+
st.rerun()
|
| 265 |
+
|
| 266 |
+
if "authenticated" in st.session_state and st.session_state["authenticated"]:
|
| 267 |
+
if st.sidebar.button("Se déconnecter"):
|
| 268 |
+
logout()
|
| 269 |
+
|
| 270 |
+
# Vérification de la connexion
|
| 271 |
+
if "authenticated" not in st.session_state:
|
| 272 |
+
st.session_state["authenticated"] = False
|
| 273 |
+
|
| 274 |
+
if not st.session_state["authenticated"]:
|
| 275 |
+
check_login()
|
| 276 |
+
st.stop()
|
| 277 |
+
|
| 278 |
+
|
| 279 |
# Application Streamlit
|
| 280 |
st.markdown('<div class="title">Application de Classification d\'Images</div>', unsafe_allow_html=True)
|
| 281 |
|
| 282 |
menu = st.sidebar.selectbox("Menu", ["🧠 Accueil", "🧠 Classification de l'état cérébral avec VGG16", "Comparatif entre modèles", "👨💻À propos"])
|
| 283 |
|
| 284 |
if menu == "🧠 Accueil":
|
| 285 |
+
st.write("Bienvenue dans notre application de classification d'images. Cette application a été développée pour la classification d'images dans le contexte du **Brain Tumor MRI images**, un dataset médical contenant des images de tomodensitométrie (CT) de reins, avec des catégories représentant des reins normaux, des kystes, des tumeurs et des calculs rénaux.")
|
| 286 |
|
| 287 |
st.write("""
|
| 288 |
Cette application a pour objectif de classer ces images en différentes catégories (**Healthy** Aucun problème: , **Tumor**: Tumeur cérébrale) à l'aide de modèles de machine learning.
|
| 289 |
Nous avons effectué du Transfer Learning sur trois modèles pré entrainés et avons fait un comparatif des trois avant de choisir **VGG16** comme celui avec les meilleurs caractéristiques.
|
| 290 |
+
Ces modèles ont été entraînés sur le dataset Brain Tumor MRI images et peuvent être utilisés pour prédire la catégorie d'une image donnée, en détectant des anomalies ou en validant l'état du rein à partir des images CT.
|
| 291 |
""")
|
| 292 |
|
| 293 |
# Création des onglets pour chaque modèle
|
|
|
|
| 354 |
|
| 355 |
# Présentation de la fonctionnalité pour l'utilisateur
|
| 356 |
st.markdown("""
|
| 357 |
+
Cette section vous permet de **classer une image d'état des reins** en fonction de son apparence.
|
| 358 |
Le modèle utilise **VGG16**, une architecture d'apprentissage profond optimisée pour analyser les images.
|
| 359 |
Voici ce que vous devez faire :
|
| 360 |
1. Téléchargez une image au format `jpg`, `jpeg` ou `png`.
|
|
|
|
| 372 |
|
| 373 |
# Explication pour l'étape suivante
|
| 374 |
st.markdown("""
|
| 375 |
+
Cliquez sur le bouton **Classifier** pour que le modèle analyse l'image et détermine si l'état des reins est **Normal** ou présente une **Anomalie**.
|
| 376 |
""")
|
| 377 |
|
| 378 |
# Étape 2 : L'utilisateur clique pour classifier l'image
|
|
|
|
| 380 |
# Appel de la fonction de prédiction avec le modèle ResNet50
|
| 381 |
label, probabilities = predict_with_pytorch(MODEL_PYTORCH_PATH, image, class_names)
|
| 382 |
|
| 383 |
+
pdf_file = generate_pdf(label, probabilities, image, MODEL_PYTORCH_PATH)
|
| 384 |
+
|
| 385 |
+
st.download_button("Télécharger le rapport PDF", pdf_file, "rapport_prediction.pdf", "application/pdf")
|
| 386 |
+
|
| 387 |
# Affichage du résultat
|
| 388 |
st.markdown(f"""
|
| 389 |
### Résultat de la classification :
|