Spaces:
Sleeping
Sleeping
| # ================================ | |
| # 0. PATCH pour huggingface_hub (contourne l'absence de HfFolder) | |
| # ================================ | |
| import huggingface_hub | |
| if not hasattr(huggingface_hub, 'HfFolder'): | |
| class HfFolder: | |
| _token = None | |
| def get_token(): | |
| return HfFolder._token | |
| def save_token(token): | |
| HfFolder._token = token | |
| huggingface_hub.HfFolder = HfFolder | |
| # ================================ | |
| # 1. PATCH pour contourner le bug de Gradio 4.44.0 | |
| # (TypeError: argument of type 'bool' is not iterable) | |
| # ================================ | |
| import gradio_client.utils | |
| original_get_type = gradio_client.utils.get_type | |
| def patched_get_type(schema): | |
| if isinstance(schema, bool): | |
| return "boolean" | |
| return original_get_type(schema) | |
| gradio_client.utils.get_type = patched_get_type | |
| # ================================ | |
| # 2. IMPORTS STANDARDS | |
| # ================================ | |
| import gradio as gr | |
| import tensorflow as tf | |
| import numpy as np | |
| import cv2 | |
| from PIL import Image | |
| # ================================ | |
| # 3. CHARGEMENT DU MODÈLE (détection) | |
| # ================================ | |
| # MODEL_PATH = "detection_model.h5" # Note: le modèle sauvegardé est .h5 (HDF5) best_model.keras | |
| MODEL_PATH = "best_model.keras" # Note: le modèle sauvegardé est .h5 (HDF5) | |
| model = tf.keras.models.load_model(MODEL_PATH, compile=False) | |
| # Recompiler pour éviter les warnings (non nécessaire pour l'inférence) | |
| model.compile(optimizer='adam', loss={'class_output':'sparse_categorical_crossentropy', 'bbox_output':'mse'}) | |
| IMG_SIZE = 224 | |
| # ================================ | |
| # 4. FONCTION DE PRÉDICTION | |
| # ================================ | |
| def preprocess_image(img): | |
| """Redimensionne et normalise l'image pour le modèle.""" | |
| img = img.resize((IMG_SIZE, IMG_SIZE)) | |
| img_array = np.array(img, dtype=np.float32) / 255.0 | |
| img_array = np.expand_dims(img_array, axis=0) | |
| return img_array | |
| def predict_detection(img): | |
| """ | |
| Prend une image PIL, renvoie l'image avec boîte englobante dessinée et le texte de classification. | |
| """ | |
| # Prétraitement | |
| processed = preprocess_image(img) | |
| # Prédiction | |
| pred_cls, pred_bbox = model.predict(processed, verbose=0) | |
| cls = np.argmax(pred_cls[0]) # 0 = crop, 1 = weed | |
| bbox = pred_bbox[0] # [xmin, ymin, xmax, ymax] en coordonnées normalisées (0-1) | |
| # Convertir en coordonnées pixel sur l'image originale (taille originale) | |
| # L'utilisateur a téléchargé une image qui peut ne pas être carrée, nous devons adapter. | |
| # Nous travaillons sur l'image redimensionnée pour l'affichage, mais la boîte doit être | |
| # redimensionnée proportionnellement. On va redessiner sur une copie de l'image redimensionnée | |
| # pour l'affichage. | |
| img_disp = img.resize((IMG_SIZE, IMG_SIZE)) # même taille que celle utilisée par le modèle | |
| w, h = img_disp.size | |
| # Coordonnées absolues | |
| xmin = int(bbox[0] * w) | |
| ymin = int(bbox[1] * h) | |
| xmax = int(bbox[2] * w) | |
| ymax = int(bbox[3] * h) | |
| # Convertir PIL en array OpenCV (BGR) pour dessiner | |
| img_cv = cv2.cvtColor(np.array(img_disp), cv2.COLOR_RGB2BGR) | |
| # Dessiner le rectangle | |
| cv2.rectangle(img_cv, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2) | |
| # Ajouter le texte | |
| label = "Crop" if cls == 0 else "Weed" | |
| cv2.putText(img_cv, label, (xmin, ymin-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) | |
| # Reconvertir en PIL pour affichage | |
| img_result = Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)) | |
| return img_result | |
| # ================================ | |
| # 5. INTERFACE GRADIO | |
| # ================================ | |
| iface = gr.Interface( | |
| fn=predict_detection, | |
| inputs=gr.Image(type="pil", label="Chargez une image de champ"), | |
| outputs=gr.Image(type="pil", label="Résultat avec détection"), | |
| title="Détection Culture / Mauvaise Herbe", | |
| 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. " | |
| ) | |
| if __name__ == "__main__": | |
| iface.launch(share=True) |