walidchaib commited on
Commit
cd67ded
·
verified ·
1 Parent(s): 93138dd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -73
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # ================================
2
- # 0. PATCH HF + GRADIO BUGS
3
  # ================================
4
  import huggingface_hub
5
  if not hasattr(huggingface_hub, 'HfFolder'):
@@ -13,6 +13,10 @@ if not hasattr(huggingface_hub, 'HfFolder'):
13
  HfFolder._token = token
14
  huggingface_hub.HfFolder = HfFolder
15
 
 
 
 
 
16
  import gradio_client.utils
17
 
18
  original_get_type = gradio_client.utils.get_type
@@ -25,7 +29,7 @@ def patched_get_type(schema):
25
  gradio_client.utils.get_type = patched_get_type
26
 
27
  # ================================
28
- # 1. IMPORTS
29
  # ================================
30
  import gradio as gr
31
  import tensorflow as tf
@@ -33,90 +37,76 @@ import numpy as np
33
  import cv2
34
  from PIL import Image
35
 
36
- tf.keras.mixed_precision.set_global_policy('float32')
37
-
38
  # ================================
39
- # 2. LOAD MODEL (DETECTION)
40
  # ================================
41
- MODEL_PATH = "final_model.keras"
42
-
43
  model = tf.keras.models.load_model(MODEL_PATH, compile=False)
44
 
45
- # IMPORTANT : recompilation avec deux sorties
46
- model.compile(
47
- optimizer='adam',
48
- loss={
49
- 'class': 'binary_crossentropy',
50
- 'bbox': 'mse'
51
- }
52
- )
53
 
54
- # ================================
55
- # 3. CONFIG
56
- # ================================
57
- IMG_SIZE = 224 # IMPORTANT : même taille que training
58
 
59
  # ================================
60
- # 4. PREPROCESS
61
  # ================================
62
  def preprocess_image(img):
63
- original_size = img.size # (width, height)
64
-
65
- img_resized = img.resize((IMG_SIZE, IMG_SIZE))
66
- img_array = np.array(img_resized, dtype=np.float32) / 255.0
67
  img_array = np.expand_dims(img_array, axis=0)
68
-
69
- return img_array, original_size
70
-
71
- # ================================
72
- # 5. PREDICTION (DETECTION)
73
- # ================================
74
- def predict(img):
75
- img_array, (orig_w, orig_h) = preprocess_image(img)
76
-
77
- pred_class, pred_bbox = model.predict(img_array, verbose=0)
78
-
79
- prob = float(pred_class[0][0])
80
- label = "weed" if prob > 0.5 else "crop"
81
-
82
- # bbox normalisée pixels
83
- xmin, ymin, xmax, ymax = pred_bbox[0]
84
-
85
- xmin = int(xmin * orig_w)
86
- xmax = int(xmax * orig_w)
87
- ymin = int(ymin * orig_h)
88
- ymax = int(ymax * orig_h)
89
-
90
- # Convertir en OpenCV
91
- img_cv = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
92
-
93
- # Dessiner rectangle
94
- color = (0, 0, 255) if label == "weed" else (0, 255, 0)
95
-
96
- cv2.rectangle(img_cv, (xmin, ymin), (xmax, ymax), color, 2)
97
-
98
- text = f"{label}: {prob:.2f}"
99
- cv2.putText(img_cv, text, (xmin, max(20, ymin-10)),
100
- cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
101
-
102
- # Convertir обратно en PIL
103
- img_out = Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB))
104
-
105
- return img_out
106
-
107
- # ================================
108
- # 6. GRADIO UI (DETECTION)
 
 
109
  # ================================
110
  iface = gr.Interface(
111
- fn=predict,
112
- inputs=gr.Image(type="pil", label="Image de champ"),
113
- outputs=gr.Image(type="pil", label="Détection (Bounding Box)"),
114
- title="🌱 Détection Culture vs Mauvaise Herbe",
115
- description="Le modèle détecte l'objet et dessine un rectangle autour (crop ou weed)."
116
  )
117
 
118
- # ================================
119
- # 7. RUN
120
- # ================================
121
  if __name__ == "__main__":
122
  iface.launch(share=True)
 
1
  # ================================
2
+ # 0. PATCH pour huggingface_hub (contourne l'absence de HfFolder)
3
  # ================================
4
  import huggingface_hub
5
  if not hasattr(huggingface_hub, 'HfFolder'):
 
13
  HfFolder._token = token
14
  huggingface_hub.HfFolder = HfFolder
15
 
16
+ # ================================
17
+ # 1. PATCH pour contourner le bug de Gradio 4.44.0
18
+ # (TypeError: argument of type 'bool' is not iterable)
19
+ # ================================
20
  import gradio_client.utils
21
 
22
  original_get_type = gradio_client.utils.get_type
 
29
  gradio_client.utils.get_type = patched_get_type
30
 
31
  # ================================
32
+ # 2. IMPORTS STANDARDS
33
  # ================================
34
  import gradio as gr
35
  import tensorflow as tf
 
37
  import cv2
38
  from PIL import Image
39
 
 
 
40
  # ================================
41
+ # 3. CHARGEMENT DU MODÈLE (détection)
42
  # ================================
43
+ MODEL_PATH = "detection_model.h5" # Note: le modèle sauvegardé est .h5 (HDF5)
 
44
  model = tf.keras.models.load_model(MODEL_PATH, compile=False)
45
 
46
+ # Recompiler pour éviter les warnings (non nécessaire pour l'inférence)
47
+ model.compile(optimizer='adam', loss={'class_output':'sparse_categorical_crossentropy', 'bbox_output':'mse'})
 
 
 
 
 
 
48
 
49
+ IMG_SIZE = 224
 
 
 
50
 
51
  # ================================
52
+ # 4. FONCTION DE PRÉDICTION
53
  # ================================
54
  def preprocess_image(img):
55
+ """Redimensionne et normalise l'image pour le modèle."""
56
+ img = img.resize((IMG_SIZE, IMG_SIZE))
57
+ img_array = np.array(img, dtype=np.float32) / 255.0
 
58
  img_array = np.expand_dims(img_array, axis=0)
59
+ return img_array
60
+
61
+ def predict_detection(img):
62
+ """
63
+ Prend une image PIL, renvoie l'image avec boîte englobante dessinée et le texte de classification.
64
+ """
65
+ # Prétraitement
66
+ processed = preprocess_image(img)
67
+
68
+ # Prédiction
69
+ pred_cls, pred_bbox = model.predict(processed, verbose=0)
70
+ cls = np.argmax(pred_cls[0]) # 0 = crop, 1 = weed
71
+ bbox = pred_bbox[0] # [xmin, ymin, xmax, ymax] en coordonnées normalisées (0-1)
72
+
73
+ # Convertir en coordonnées pixel sur l'image originale (taille originale)
74
+ # L'utilisateur a téléchargé une image qui peut ne pas être carrée, nous devons adapter.
75
+ # Nous travaillons sur l'image redimensionnée pour l'affichage, mais la boîte doit être
76
+ # redimensionnée proportionnellement. On va redessiner sur une copie de l'image redimensionnée
77
+ # pour l'affichage.
78
+ img_disp = img.resize((IMG_SIZE, IMG_SIZE)) # même taille que celle utilisée par le modèle
79
+ w, h = img_disp.size
80
+
81
+ # Coordonnées absolues
82
+ xmin = int(bbox[0] * w)
83
+ ymin = int(bbox[1] * h)
84
+ xmax = int(bbox[2] * w)
85
+ ymax = int(bbox[3] * h)
86
+
87
+ # Convertir PIL en array OpenCV (BGR) pour dessiner
88
+ img_cv = cv2.cvtColor(np.array(img_disp), cv2.COLOR_RGB2BGR)
89
+ # Dessiner le rectangle
90
+ cv2.rectangle(img_cv, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2)
91
+ # Ajouter le texte
92
+ label = "Crop" if cls == 0 else "Weed"
93
+ cv2.putText(img_cv, label, (xmin, ymin-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
94
+
95
+ # Reconvertir en PIL pour affichage
96
+ img_result = Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB))
97
+
98
+ return img_result
99
+
100
+ # ================================
101
+ # 5. INTERFACE GRADIO
102
  # ================================
103
  iface = gr.Interface(
104
+ fn=predict_detection,
105
+ inputs=gr.Image(type="pil", label="Chargez une image de champ"),
106
+ outputs=gr.Image(type="pil", label="Résultat avec détection"),
107
+ title="Détection Culture / Mauvaise Herbe",
108
+ description="Ce modèle (MobileNetV2) détecte les cultures et les mauvaises herbes et renvoie la boîte englobante de l'objet principal ainsi que sa classe."
109
  )
110
 
 
 
 
111
  if __name__ == "__main__":
112
  iface.launch(share=True)