MODLI commited on
Commit
16d1754
·
verified ·
1 Parent(s): 8aa706b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +161 -131
app.py CHANGED
@@ -3,16 +3,14 @@ import torch
3
  import torch.nn.functional as F
4
  from transformers import AutoImageProcessor, AutoModelForImageClassification
5
  from PIL import Image
 
6
  import requests
7
  from io import BytesIO
8
- import numpy as np
9
- import os
10
- import tempfile
11
 
12
- # 🔥 MODÈLE SPÉCIALISÉ DANS LA MODE
13
- MODEL_NAME = "google/vit-base-patch16-224"
14
 
15
- print("🔄 Chargement du modèle de mode...")
16
 
17
  try:
18
  processor = AutoImageProcessor.from_pretrained(MODEL_NAME)
@@ -22,80 +20,112 @@ try:
22
  model.to(device)
23
  model.eval()
24
 
25
- print(f"✅ Modèle chargé sur {device}")
26
 
27
  except Exception as e:
28
- print(f"❌ Erreur chargement: {e}")
29
- processor = None
30
- model = None
 
 
 
 
 
 
 
 
31
 
32
- # 🎯 MAPPING COMPLET DES CATÉGORIES EN FRANÇAIS
33
  FASHION_LABELS = {
34
- # Vêtements supérieurs
35
- 0: "T-shirt", 1: "Pull", 2: "Chemise", 3: "Sweat à capuche", 4: "Veste",
36
- 5: "Manteau", 6: "Blouse", 7: "Haut", 8: "Top", 9: "Débardeur",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- # Vêtements inférieurs
39
- 10: "Pantalon", 11: "Jean", 12: "Short", 13: "Jupe", 14: "Legging",
40
- 15: "Pantalon de sport", 16: "Pantalon cargo", 17: "Pantalon chino",
 
41
 
42
- # Robes et ensembles
43
- 18: "Robe", 19: "Robe de soirée", 20: "Robe d'été", 21: "Robe cocktail",
44
- 22: "Combinaison", 23: "Ensemble", 24: "Tenue",
45
 
46
- # Sous-vêtements
47
- 25: "Soutien-gorge", 26: "Culotte", 27: "Maillot de bain",
48
- 28: "Pyjama", 29: "Nuisette",
49
 
50
  # Chaussures
51
- 30: "Basket", 31: "Sandale", 32: "Botte", 33: "Talons",
52
- 34: "Escarpin", 35: "Chaussure de sport", 36: "Mocassin",
53
- 37: "Derby", 38: "Chausson",
54
 
55
  # Accessoires
56
- 39: "Sac à main", 40: "Sac à dos", 41: "Chapeau", 42: "Casquette",
57
- 43: "Écharpe", 44: "Gants", 45: "Ceinture", 46: "Lunettes de soleil",
58
- 47: "Bijou", 48: "Montre", 49: "Cravate",
 
 
 
59
 
60
- # Sports
61
- 50: "Tenue de sport", 51: "Maillot de football", 52: "Short de sport",
62
- 53: "Survêtement", 54: "Veste de sport",
63
 
64
- # Enfants
65
- 55: "Vêtement bébé", 56: "Vêtement enfant",
 
66
 
67
- # Divers
68
- 57: "Uniforme", 58: "Costume", 59: "Smoking",
69
- 60: "Robe de mariée", 61: "Accessoire mode",
70
- }
 
 
 
 
 
 
71
 
72
- def get_human_readable_label(label_idx):
73
- """Convertit un numéro de catégorie en nom français"""
74
- if label_idx in FASHION_LABELS:
75
- return FASHION_LABELS[label_idx]
76
-
77
- # Catégories génériques basées sur les plages
78
- if 100 <= label_idx < 200:
79
- return "Vêtement supérieur"
80
- elif 200 <= label_idx < 300:
81
- return "Vêtement inférieur"
82
- elif 300 <= label_idx < 400:
83
- return "Accessoire mode"
84
- elif 400 <= label_idx < 500:
85
- return "Chaussure"
86
- elif 500 <= label_idx < 600:
87
- return "Vêtement sport"
88
- elif 600 <= label_idx < 700:
89
- return "Vêtement casual"
90
- elif 700 <= label_idx < 800:
91
- return "Vêtement formel"
92
- elif 800 <= label_idx < 900:
93
- return "Vêtement décontracté"
94
- else:
95
- return "Article vestimentaire"
 
96
 
97
  def classify_fashion(image):
98
- """Classification avec noms en français"""
99
  try:
100
  if image is None:
101
  return "❌ Veuillez uploader une image de vêtement"
@@ -103,83 +133,85 @@ def classify_fashion(image):
103
  if processor is None or model is None:
104
  return "⚠️ Modèle en cours de chargement... Patientez 30s"
105
 
106
- # 📸 Gestion de l'image
107
- try:
108
- if isinstance(image, str):
109
- processed_image = Image.open(image)
110
- else:
111
- processed_image = image
112
-
113
- if processed_image.mode != 'RGB':
114
- processed_image = processed_image.convert('RGB')
115
-
116
- except Exception as e:
117
- return f"❌ Format d'image non supporté: {str(e)}"
118
-
119
- # 🔥 PRÉTRAITEMENT
120
  processed_image = processed_image.resize((224, 224), Image.Resampling.LANCZOS)
121
 
122
- # Transformation pour le modèle
123
  inputs = processor(images=processed_image, return_tensors="pt")
124
  inputs = {k: v.to(device) for k, v in inputs.items()}
125
 
126
- # 🔥 INFÉRENCE
127
  with torch.no_grad():
128
  outputs = model(**inputs)
129
 
130
  # 📊 POST-TRAITEMENT
131
  probabilities = F.softmax(outputs.logits, dim=-1)
132
- top_probs, top_indices = torch.topk(probabilities, 5)
133
 
134
- # Conversion en résultats français
135
  results = []
136
  for i in range(len(top_indices[0])):
137
  label_idx = top_indices[0][i].item()
138
- label_name = get_human_readable_label(label_idx)
139
  score = top_probs[0][i].item() * 100
140
- if score > 1.0: # Seuil de 1% pour éviter le bruit
141
- results.append({"label": label_name, "score": score})
 
 
 
 
 
 
 
142
 
143
- # 📋 AFFICHAGE DES RÉSULTATS
144
  if not results:
145
- return "❌ Aucune catégorie vestimentaire détectée avec confiance suffisante"
146
 
147
- output = "## 🎯 RÉSULTATS DE CLASSIFICATION:\n\n"
 
148
 
149
  for i, result in enumerate(results):
150
- output += f"{i+1}. **{result['label']}** - {result['score']:.1f}%\n"
 
151
 
152
- # 📊 STATISTIQUES
153
- total_confidence = sum(result['score'] for result in results)
154
  output += f"\n---\n"
155
- output += f"📈 **Confiance totale:** {total_confidence:.1f}%\n"
 
 
 
 
 
 
 
 
156
 
157
- # 💡 CONSEILS
158
- output += "\n💡 **Pour améliorer les résultats:**\n"
159
- output += "• Prenez la photo sur fond uni\n"
160
- output += " Assurez-vous d'un bon éclairage\n"
161
- output += "• Cadrez uniquement le vêtement\n"
 
162
 
163
  return output
164
 
165
  except Exception as e:
166
- return f"❌ Erreur de traitement: {str(e)}"
167
 
168
- # 🖼️ EXEMPLES DE TEST AVEC URLs FIABLES
169
- EXAMPLE_URLS = [
170
- "https://i.imgur.com/7QqRj7Z.jpeg", # T-shirt simple
171
- "https://i.imgur.com/9Z8ZQ2W.jpeg", # Robe élégante
172
- "https://i.imgur.com/3QqRj7Z.jpeg", # Chemise classique
173
- "https://i.imgur.com/5Z8ZQ2W.jpeg", # Veste moderne
174
- "https://i.imgur.com/1QqRj7Z.jpeg", # Jean décontracté
175
- ]
176
-
177
- # 🎨 INTERFACE SIMPLIFIÉE SANS EXEMPLES PROBLÉMATIQUES
178
- with gr.Blocks(title="Classificateur de Vêtements Expert", theme=gr.themes.Soft()) as demo:
179
 
180
  gr.Markdown("""
181
- # 👗 CLASSIFICATEUR EXPERT DE VÊTEMENTS
182
- *Reconnaissance intelligente avec labels en français*
183
  """)
184
 
185
  with gr.Row():
@@ -193,39 +225,37 @@ with gr.Blocks(title="Classificateur de Vêtements Expert", theme=gr.themes.Soft
193
  )
194
 
195
  gr.Markdown("""
196
- ### 📋 CONSEILS
197
- ✅ JPEG/PNG recommandés
198
- Évitez HEIC (Apple)
199
- 📷 Photo nette et bien éclairée
200
- 🎯 Cadrage simple du vêtement
 
201
  """)
202
 
203
- classify_btn = gr.Button("🚀 Analyser le vêtement", variant="primary")
 
204
 
205
  with gr.Column(scale=2):
206
- gr.Markdown("### 📊 RÉSULTATS DÉTAILLÉS")
207
  output_text = gr.Markdown(
208
- value="⬅️ Uploader une image pour commencer l'analyse"
209
  )
210
 
211
- # 🎯 BOUTONS EXEMPLES SIMPLES (optionnel - commenté pour éviter les erreurs)
212
- # gr.Markdown("### 🖼️ EXEMPLES DE TEST")
213
- # with gr.Row():
214
- # for i, url in enumerate(EXAMPLE_URLS):
215
- # gr.Button(f"Exemple {i+1}", variant="secondary").click(
216
- # fn=lambda u=url: Image.open(BytesIO(requests.get(u).content)),
217
- # inputs=[],
218
- # outputs=image_input
219
- # )
220
-
221
- # 🎮 INTERACTION PRINCIPALE
222
- classify_btn.click(
223
  fn=classify_fashion,
224
  inputs=[image_input],
225
  outputs=output_text
226
  )
227
 
228
- # 🔄 AUTO-CLASSIFICATION À L'UPLOAD
 
 
 
 
 
 
229
  image_input.upload(
230
  fn=classify_fashion,
231
  inputs=[image_input],
 
3
  import torch.nn.functional as F
4
  from transformers import AutoImageProcessor, AutoModelForImageClassification
5
  from PIL import Image
6
+ import numpy as np
7
  import requests
8
  from io import BytesIO
 
 
 
9
 
10
+ # 🔥 MODÈLE SPÉCIALISÉ DANS LA MODE - FASHION MNIST
11
+ MODEL_NAME = "nickmuchi/vit-finetuned-fashion-mnist" # Modèle fine-tuné sur la mode
12
 
13
+ print("🔄 Chargement du modèle spécialisé mode...")
14
 
15
  try:
16
  processor = AutoImageProcessor.from_pretrained(MODEL_NAME)
 
20
  model.to(device)
21
  model.eval()
22
 
23
+ print(f"✅ Modèle mode chargé sur {device}")
24
 
25
  except Exception as e:
26
+ print(f"❌ Erreur chargement modèle mode: {e}")
27
+ # Fallback sur un modèle général
28
+ try:
29
+ processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
30
+ model = AutoModelForImageClassification.from_pretrained("google/vit-base-patch16-224")
31
+ model.to(device)
32
+ model.eval()
33
+ print("✅ Modèle général chargé en fallback")
34
+ except:
35
+ processor = None
36
+ model = None
37
 
38
+ # 🎯 LABELS SPÉCIFIQUES FASHION-MNIST (10 catégories précises)
39
  FASHION_LABELS = {
40
+ 0: "👕 T-shirt/Haut",
41
+ 1: "👖 Pantalon",
42
+ 2: "🧥 Pull",
43
+ 3: "👗 Robe",
44
+ 4: "🧥 Manteau",
45
+ 5: "👞 Sandale",
46
+ 6: "👔 Chemise",
47
+ 7: "👟 Sneaker",
48
+ 8: "👜 Sac",
49
+ 9: "👢 Botte"
50
+ }
51
+
52
+ # 🎨 MAPPING DÉTAILLÉ POUR MEILLEURE PRÉCISION
53
+ DETAILED_LABELS = {
54
+ # Pantalons
55
+ "Pantalon": ["Jeans", "Pantalon droit", "Pantalon slim", "Pantalon cargo", "Pantalon chino"],
56
+ "👖 Pantalon": ["Jeans", "Pantalon droit", "Pantalon slim", "Pantalon cargo", "Pantalon chino"],
57
 
58
+ # Hauts
59
+ "👕 T-shirt/Haut": ["T-shirt", "Débardeur", "Top", "Haut sans manches", "Haut manches courtes"],
60
+ "👔 Chemise": ["Chemise homme", "Chemise femme", "Chemise boutonnée", "Chemise casual"],
61
+ "🧥 Pull": ["Pull-over", "Sweater", "Pull col roulé", "Gilet", "Cardigan"],
62
 
63
+ # Robes
64
+ "👗 Robe": ["Robe d'été", "Robe cocktail", "Robe de soirée", "Robe casual", "Robe maxi"],
 
65
 
66
+ # Manteaux
67
+ "🧥 Manteau": ["Veste", "Blouson", "Manteau long", "Doudoune", "Veste légère"],
 
68
 
69
  # Chaussures
70
+ "👞 Sandale": ["Sandale", "Tong", "Sandale plateforme"],
71
+ "👟 Sneaker": ["Basket", "Sneaker", "Chaussure de sport"],
72
+ "👢 Botte": ["Botte", "Bottine", "Botte en cuir"],
73
 
74
  # Accessoires
75
+ "👜 Sac": ["Sac à main", "Sac à dos", "Sac bandoulière", "Pochette"]
76
+ }
77
+
78
+ def get_detailed_classification(label_idx, confidence):
79
+ """Retourne une classification détaillée"""
80
+ base_label = FASHION_LABELS.get(label_idx, "Vêtement")
81
 
82
+ # Pour les pantalons, on précise si c'est un jean
83
+ if "Pantalon" in base_label and confidence > 30:
84
+ return "👖 Jeans" if confidence > 50 else "👖 Pantalon"
85
 
86
+ # Pour les hauts, on affine
87
+ if "T-shirt" in base_label and confidence > 40:
88
+ return "👕 T-shirt"
89
 
90
+ if "Chemise" in base_label and confidence > 40:
91
+ return "👔 Chemise"
92
+
93
+ if "Robe" in base_label and confidence > 40:
94
+ return "👗 Robe"
95
+
96
+ if "Manteau" in base_label and confidence > 40:
97
+ return "🧥 Veste/Manteau"
98
+
99
+ return base_label
100
 
101
+ def enhance_classification(results):
102
+ """Améliore la classification avec des règles métier"""
103
+ enhanced_results = []
104
+
105
+ for result in results:
106
+ label = result['label']
107
+ score = result['score']
108
+
109
+ # Règles pour améliorer la précision
110
+ if "Pantalon" in label and score > 30:
111
+ new_label = "👖 Jeans" if score > 50 else "👖 Pantalon"
112
+ elif "T-shirt" in label and score > 40:
113
+ new_label = "👕 T-shirt"
114
+ elif "Chemise" in label and score > 40:
115
+ new_label = "👔 Chemise"
116
+ elif "Robe" in label and score > 40:
117
+ new_label = "👗 Robe"
118
+ elif "Manteau" in label and score > 40:
119
+ new_label = "🧥 Veste/Manteau"
120
+ else:
121
+ new_label = label
122
+
123
+ enhanced_results.append({"label": new_label, "score": score})
124
+
125
+ return enhanced_results
126
 
127
  def classify_fashion(image):
128
+ """Classification précise des vêtements"""
129
  try:
130
  if image is None:
131
  return "❌ Veuillez uploader une image de vêtement"
 
133
  if processor is None or model is None:
134
  return "⚠️ Modèle en cours de chargement... Patientez 30s"
135
 
136
+ # 📸 Prétraitement de l'image
137
+ if isinstance(image, str):
138
+ processed_image = Image.open(image)
139
+ else:
140
+ processed_image = image
141
+
142
+ # Conversion en RGB et redimensionnement
143
+ if processed_image.mode != 'RGB':
144
+ processed_image = processed_image.convert('RGB')
145
+
 
 
 
 
146
  processed_image = processed_image.resize((224, 224), Image.Resampling.LANCZOS)
147
 
148
+ # 🔥 INFÉRENCE
149
  inputs = processor(images=processed_image, return_tensors="pt")
150
  inputs = {k: v.to(device) for k, v in inputs.items()}
151
 
 
152
  with torch.no_grad():
153
  outputs = model(**inputs)
154
 
155
  # 📊 POST-TRAITEMENT
156
  probabilities = F.softmax(outputs.logits, dim=-1)
157
+ top_probs, top_indices = torch.topk(probabilities, 3) # Top 3 seulement
158
 
159
+ # Conversion en résultats
160
  results = []
161
  for i in range(len(top_indices[0])):
162
  label_idx = top_indices[0][i].item()
163
+ label_name = FASHION_LABELS.get(label_idx, f"Vêtement {label_idx}")
164
  score = top_probs[0][i].item() * 100
165
+
166
+ # Application des règles métier
167
+ detailed_label = get_detailed_classification(label_idx, score)
168
+
169
+ if score > 10: # Seuil minimal de 10%
170
+ results.append({"label": detailed_label, "score": score})
171
+
172
+ # 📋 Amélioration de la classification
173
+ results = enhance_classification(results)
174
 
 
175
  if not results:
176
+ return "❌ Aucun vêtement reconnu avec certitude\n\n💡 Essayez avec une photo plus nette"
177
 
178
+ # 📊 AFFICHAGE DES RÉSULTATS
179
+ output = "## 🎯 TYPE DE VÊTEMENT IDENTIFIÉ:\n\n"
180
 
181
  for i, result in enumerate(results):
182
+ if result['score'] > 15: # Seuil de 15% pour afficher
183
+ output += f"{i+1}. **{result['label']}** - {result['score']:.1f}%\n"
184
 
185
+ # 💡 CONSEILS SPÉCIFIQUES
 
186
  output += f"\n---\n"
187
+ output += "💡 **Pour une meilleure précision:**\n"
188
+ output += "• 📷 Photo nette sur fond uni\n"
189
+ output += "• 🎯 Cadrez uniquement le vêtement\n"
190
+ output += "• 🌞 Bon éclairage sans ombres\n"
191
+ output += "• 🔍 Évitez les motifs trop complexes\n"
192
+
193
+ # 🎯 DIAGNOSTIC AUTO
194
+ best_guess = results[0]['label']
195
+ confidence = results[0]['score']
196
 
197
+ if confidence > 60:
198
+ output += f"\n **Certitude élevée:** {best_guess}\n"
199
+ elif confidence > 30:
200
+ output += f"\n⚠️ **Certitude moyenne:** Probablement {best_guess}\n"
201
+ else:
202
+ output += f"\n❓ **Certitude faible:** Peut-être {best_guess}\n"
203
 
204
  return output
205
 
206
  except Exception as e:
207
+ return f"❌ Erreur: {str(e)}"
208
 
209
+ # 🎨 INTERFACE SIMPLIFIÉE
210
+ with gr.Blocks(title="Reconnaissance de Vêtements", theme=gr.themes.Soft()) as demo:
 
 
 
 
 
 
 
 
 
211
 
212
  gr.Markdown("""
213
+ # 👖 RECONNAISSANCE DE VÊTEMENTS
214
+ *Identification précise du type de vêtement*
215
  """)
216
 
217
  with gr.Row():
 
225
  )
226
 
227
  gr.Markdown("""
228
+ ### 🎯 CONSEILS DE PHOTO
229
+ **Format:** JPEG ou PNG
230
+ **Cadrage:** Vêtement bien visible
231
+ **Fond:** Uni de préférence
232
+ **Éclairage:** Lumière naturelle
233
+ ❌ **À éviter:** Photos floues ou sombres
234
  """)
235
 
236
+ analyze_btn = gr.Button("🔍 Analyser le vêtement", variant="primary")
237
+ clear_btn = gr.Button("🧹 Nouvelle image", variant="secondary")
238
 
239
  with gr.Column(scale=2):
240
+ gr.Markdown("### 📊 RÉSULTATS D'ANALYSE")
241
  output_text = gr.Markdown(
242
+ value="⬅️ Uploader une image de vêtement pour l'analyse"
243
  )
244
 
245
+ # 🎮 INTERACTIONS
246
+ analyze_btn.click(
 
 
 
 
 
 
 
 
 
 
247
  fn=classify_fashion,
248
  inputs=[image_input],
249
  outputs=output_text
250
  )
251
 
252
+ clear_btn.click(
253
+ fn=lambda: (None, "⬅️ Prêt pour une nouvelle analyse"),
254
+ inputs=[],
255
+ outputs=[image_input, output_text]
256
+ )
257
+
258
+ # 🔄 AUTO-ANALYSE
259
  image_input.upload(
260
  fn=classify_fashion,
261
  inputs=[image_input],