Spaces:
Build error
Build error
File size: 15,586 Bytes
0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d f18029c 0921a8d 6f30a12 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
import streamlit as st
from PIL import Image
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import load_model
import random
# Taille d'entrée pour les modèles
INPUT_SIZE = 224
# Chemins des modèles sauvegardés
MODEL_TF_PATH = "best_model.keras"
# Chargement des classes
class_names = ['Cyst', 'Normal', 'Stone', 'Tumor']
# Fonction pour prédire avec TensorFlow
def predict_with_tensorflow(model_path, image):
# Charger le modèle TensorFlow
model = load_model(model_path)
# Vérifier que INPUT_SIZE et class_names sont définis
assert "INPUT_SIZE" in globals() and "class_names" in globals(), \
"Les variables INPUT_SIZE et class_names doivent être définies globalement."
# Prétraitement de l'image
try:
# Redimensionner l'image à la taille attendue par le modèle
image_resized = image.resize((INPUT_SIZE, INPUT_SIZE))
image_array = np.array(image_resized) / 255.0 # Normalisation
image_array = np.expand_dims(image_array, axis=0) # Ajouter une dimension batch
except Exception as e:
raise ValueError(f"Erreur lors du prétraitement de l'image : {e}")
# Prédire avec le modèle
try:
predictions = model.predict(image_array) # Obtenir les probabilités pour chaque classe
predictions = predictions[0] # Récupérer la première ligne (cas batch=1)
except Exception as e:
raise ValueError(f"Erreur lors de la prédiction avec le modèle : {e}")
# Identifier la classe avec la plus haute probabilité
label_idx = np.argmax(predictions) # Index de la classe prédite
predicted_label = class_names[label_idx] # Nom de la classe prédite
return predicted_label, predictions
# Fonction JS pour animer les ballons
def show_balloons():
st.markdown("""
<script type="text/javascript">
function createBalloon(x, y) {
var balloon = document.createElement('div');
balloon.style.position = 'absolute';
balloon.style.left = x + 'px';
balloon.style.top = y + 'px';
balloon.style.width = '50px';
balloon.style.height = '50px';
balloon.style.background = 'url(https://example.com/balloon.png) no-repeat center center';
balloon.style.backgroundSize = 'contain';
balloon.style.animation = 'floatBalloon 6s ease-in-out infinite';
document.body.appendChild(balloon);
}
for (let i = 0; i < 5; i++) {
var x = Math.random() * window.innerWidth;
var y = Math.random() * window.innerHeight;
createBalloon(x, y);
}
</script>
""", unsafe_allow_html=True)
# CSS pour une interface moderne avec dégradés et icônes
st.markdown("""
<style>
body {
background: linear-gradient(135deg, #6e7fef, #f0c6d1);
font-family: 'Arial', sans-serif;
color: #333;
}
.title {
text-align: center;
font-size: 36px;
font-weight: bold;
color: #ff85a2;
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
margin-top: 20px;
}
.upload-section {
text-align: center;
margin: 20px;
}
.btn-primary {
background-color: #6e7fef;
border-color: #6e7fef;
color: white;
font-weight: bold;
}
.btn-primary:hover {
background-color: #5573d7;
}
.result {
text-align: center;
font-size: 24px;
color: #444;
}
.about-section {
margin-top: 40px;
font-size: 16px;
line-height: 1.6;
color: #555;
}
.legend {
font-size: 14px;
color: #555;
}
.sidebar .sidebar-content {
background: linear-gradient(135deg, #ff85a2, #ffeb3b);
color: #333;
padding-top: 20px;
}
.sidebar .sidebar-content .block-container {
padding-left: 20px;
}
.sidebar .sidebar-content .block {
background-color: rgba(255, 255, 255, 0.7);
padding: 10px;
border-radius: 8px;
margin-bottom: 10px;
}
.stSidebar {
background: linear-gradient(to right, #FF6F00, #D92D2F);;
color: white;
font-size: 16px;
}
.logo {
max-width: 200px;
margin: 20px auto;
}
.logo-description {
text-align: center;
font-size: 18px;
color: white;
margin-bottom: 30px;
}
.sidebar select {
width: 100%;
padding: 10px;
background-color: #f3f3f3;
border-radius: 8px;
font-size: 16px;
border: 1px solid #ccc;
}
@keyframes floatBalloon {
0% { transform: translateY(0); opacity: 1; }
50% { transform: translateY(-200px); opacity: 0.5; }
100% { transform: translateY(0); opacity: 1; }
}
</style>
""", unsafe_allow_html=True)
# Application Streamlit
st.markdown('<div class="title">Application de Classification d\'Images</div>', unsafe_allow_html=True)
menu = st.sidebar.selectbox("Menu", ["🧠 Accueil", "Classification de l'état des reins avec ResNet50", "👨💻À propos", "Légendes des modèles"])
if menu == "🧠 Accueil":
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 **CT-KIDNEY-DATASET-Normal-Cyst-Tumor-Stone**, 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.")
st.write("""
Cette application a pour objectif de classer ces images en différentes catégories (**Normal** Aucun problème: , **Cyst**: Kystes rénaux, **Tumor**: Tumeur rénale, **Stone**: Calculs rénaux) à l'aide de modèles de machine learning.
Nous avons effectué du Transfer Learning sur trois modèles pré entrainés et avons fait un comparatif des trois avant de choisir **ResNet50** comme celui avec les meilleurs caractéristiques.
Ces modèles ont été entraînés sur le dataset CT-KIDNEY-DATASET 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.
""")
# Création des onglets pour chaque modèle
tab_resnet50, tab_vgg16, tab_mobilenetv2 = st.tabs(["ResNet50", "VGG16", "MobileNetV2"])
with tab_resnet50:
st.image("resnet50_image.webp", caption="ResNet50", width=700)
st.write("""
**ResNet50** est un réseau de neurones convolutif profond (CNN) très populaire pour la classification d'images, introduit dans l'article "Deep Residual Learning for Image Recognition".
### Avantages :
- Utilise des **connexions résiduelles** pour résoudre les problèmes de dégradation des performances lors de l'augmentation de la profondeur du réseau.
- Excellente précision sur de grandes bases de données d'images comme ImageNet.
- Convient pour le **fine-tuning** sur des données spécifiques grâce à son architecture pré-entraînée.
### Utilisation :
ResNet50 est largement utilisé dans des tâches comme :
- La reconnaissance d'objets.
- La segmentation d'images.
- La détection de maladies en imagerie médicale.
""")
with tab_vgg16:
st.image("vgg16_image.jpg", caption="VGG16", width=700)
st.write("""
**VGG16** est un modèle de CNN développé par l'équipe de recherche Visual Geometry Group (VGG). Il est connu pour sa simplicité et son efficacité dans la classification d'images.
### Avantages :
- Architecture simple avec des couches convolutives empilées suivies de couches entièrement connectées.
- Bonne généralisation, même pour des données en dehors de son domaine d'origine.
- Facilement extensible pour des tâches comme la segmentation et la détection.
### Utilisation :
VGG16 est utilisé pour :
- La classification d'images dans des bases de données variées.
- L'extraction de caractéristiques pour des modèles personnalisés.
- Les applications médicales nécessitant des modèles interprétables.
""")
with tab_mobilenetv2:
st.image("mobilenetv2.webp", caption="MobileNetV2", width=700)
st.write("""
**MobileNetV2** est un modèle léger optimisé pour les appareils mobiles et embarqués. Il repose sur des blocs convolutifs de profondeur et des connexions résiduelles.
### Avantages :
- Très efficace en termes de calcul avec un compromis optimal entre précision et vitesse.
- Convient aux appareils à faible puissance (comme les smartphones).
- Supporte le déploiement facile via TensorFlow Lite ou PyTorch Mobile.
### Utilisation :
MobileNetV2 est utilisé pour :
- La reconnaissance d'images en temps réel sur des appareils mobiles.
- Les applications embarquées nécessitant des modèles compacts.
- Les tâches de vision par ordinateur sur des données limitées en ressources.
""")
st.write("Ces modèles pré-entraînés sont tous des choix puissants, adaptés à divers scénarios. Le choix dépend des besoins en performances, en taille de modèle et en capacité d'adaptation aux appareils cibles.")
elif menu == "Classification de l'état des reins avec ResNet50":
# Ajout d'un sous-titre explicatif pour informer sur la fonctionnalité
st.subheader("Classification avec ResNet50 (TensorFlow)")
# Présentation de la fonctionnalité pour l'utilisateur
st.markdown("""
Cette section vous permet de **classer une image d'état des reins** en fonction de son apparence.
Le modèle utilise **ResNet50**, une architecture d'apprentissage profond optimisée pour analyser les images.
Voici ce que vous devez faire :
1. Téléchargez une image au format `jpg`, `jpeg` ou `png`.
2. Cliquez sur le bouton **Classifier** pour lancer l'analyse.
3. Obtenez le résultat du diagnostic (Normal ou Anomalie) accompagné d'un graphique des probabilités.
""")
# Étape 1 : L'utilisateur télécharge une image
uploaded_file = st.file_uploader("Téléchargez une image des reins (format jpg, jpeg ou png)", type=["jpg", "jpeg", "png"])
if uploaded_file is not None:
# Affiche l'image téléchargée
image = Image.open(uploaded_file)
st.image(image, caption="Image téléchargée avec succès", use_container_width=True)
# Explication pour l'étape suivante
st.markdown("""
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**.
""")
# Étape 2 : L'utilisateur clique pour classifier l'image
if st.button("Classifier"):
# Appel de la fonction de prédiction avec le modèle ResNet50
label, probabilities = predict_with_tensorflow(MODEL_TF_PATH, image)
# Affichage du résultat
st.markdown(f"""
### Résultat de la classification :
**Classe prédite :** {label}
""", unsafe_allow_html=True)
# Affichage des probabilités sous forme de graphique
st.markdown("""
#### Confiance du modèle dans chaque catégorie :
Le graphique ci-dessous montre la probabilité associée à chaque classe. Une probabilité élevée indique la classe la plus probable.
""")
st.bar_chart(probabilities)
# Affichage d'un message visuel en fonction de la classe prédite
if label == "Normal":
st.balloons() # Animation festive si le résultat est "Normal"
st.success("Félicitations ! L'image a été classée comme **Normale**.")
else:
st.error("Désolé, le modèle indique une **Anomalie** dans l'image téléchargée.")
st.markdown("""
#### Que faire en cas d'anomalie ?
Si une anomalie est détectée, il est recommandé de :
- Vérifier l'image téléchargée pour s'assurer qu'elle est correcte.
- Contacter un professionnel de santé pour une analyse approfondie.
""")
elif menu == "Légendes des modèles":
st.subheader("Légendes des modèles")
st.write("Voici des informations détaillées sur le modèle utilisé dans cette application :")
st.write("""
### ResNet50 avec Transfert Learning
**ResNet50** est un réseau de neurones convolutif pré-entraîné sur le dataset ImageNet.
Grâce au **transfert learning**, nous avons adapté ce modèle à notre propre jeu de données pour effectuer des classifications spécifiques.
#### Avantages de ResNet50 :
- **Connexions résiduelles** qui facilitent l'apprentissage pour des réseaux profonds.
- **Performances élevées** pour les tâches de vision par ordinateur, même avec des données limitées.
- Adapté pour des tâches comme la reconnaissance d'images ou la classification médicale.
#### Fonctionnement :
- Nous avons utilisé le modèle pré-entraîné pour extraire des caractéristiques.
- Les couches de classification finales ont été remplacées par des couches adaptées à notre domaine.
### Visualisation des résultats :
- Une image téléchargée est analysée par le modèle.
- Les probabilités des différentes classes sont affichées sous forme de graphique.
""")
elif menu == "👨💻À propos":
st.header("À propos de moi")
st.markdown(
"""
<div style="text-align:center; font-family: Arial; margin: 20px 0;">
<h2>Mon Parcours</h2>
<p>Je suis un passionné de l'intelligence artificielle et de la donnée. Actuellement en Master 2 en IA et Big Data, je travaille sur des solutions innovantes dans le domaine de l'Intelligence Artificielle appliquée à la santé.</p>
</div>
<div style="display: flex; justify-content: center; gap: 30px; flex-wrap: wrap;">
<div style="text-align: center;">
<img src="https://avatars.githubusercontent.com/u/1234567" alt="Ngoue David" style="width: 150px; height: 150px; border-radius: 50%;">
<h4>Ngoue David</h4>
<p>🎓 Master 2 IA & Big Data</p>
<p>📧 <a href="mailto:ngouedavidrogeryannick@gmail.com">ngouedavidrogeryannick@gmail.com</a></p>
<p>🌐 <a href="https://github.com/TheBeyonder237" target="_blank">Profil GitHub</a></p>
</div>
</div>
""", unsafe_allow_html=True) |