import os # Fix pour les erreurs de permission Streamlit sur Hugging Face if "HOME" not in os.environ or os.environ["HOME"] == "/": os.environ["HOME"] = "/tmp" os.makedirs("/tmp/.streamlit", exist_ok=True) import streamlit as st import cv2 import numpy as np from PIL import Image st.set_page_config(layout="wide") st.title("Détection et Isolation de Couleurs sur Image") st.sidebar.header("Paramètres de l'image et de la couleur") # 1. Téléchargement de l'image uploaded_file = st.sidebar.file_uploader("Choisissez une image...", type=["jpg", "jpeg", "png"]) if uploaded_file is not None: # --- DÉBUT DU BLOC DE TRAITEMENT LORSQU'UNE IMAGE EST TÉLÉCHARGÉE --- st.sidebar.success("Fichier chargé avec succès !") # Pour confirmer que le fichier est bien là # Lire le fichier BINAIRE UNE SEULE FOIS ici file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8) st.sidebar.text(f"Taille du fichier en bytes: {len(file_bytes)}") # Vérifier si les bytes sont lus # Décodage de l'image BGR avec OpenCV img_bgr = cv2.imdecode(file_bytes, 1) if img_bgr is None: st.sidebar.error("Impossible de décoder l'image. Est-ce un format supporté ?") st.stop() # Arrête l'exécution du script Streamlit pour ce cycle else: st.sidebar.success(f"Image décodée. Dimensions: {img_bgr.shape}") # Convertir BGR en RGB pour l'affichage Streamlit (image originale) img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) st.subheader("Image Originale") st.image(img_rgb, caption="Image Originale", use_column_width=True) # 2. Choix de la couleur (tout le reste du code de traitement est maintenant ici) color_choice = st.sidebar.selectbox( "Choisissez une couleur prédéfinie ou personnalisée :", ("Bleu", "Vert", "Rouge", "Jaune", "Orange", "Violet", "Personnalisé") ) h_lower, s_lower, v_lower = 0, 0, 0 h_upper, s_upper, v_upper = 179, 255, 255 if color_choice == "Bleu": lower_bound = np.array([100, 150, 0]) upper_bound = np.array([140, 255, 255]) elif color_choice == "Vert": lower_bound = np.array([40, 50, 50]) upper_bound = np.array([80, 255, 255]) elif color_choice == "Rouge": # Le rouge est spécial car il chevauche le 0/179 sur le cercle chromatique HSV # Il faut généralement deux plages pour le rouge pur st.sidebar.warning("Le rouge peut nécessiter deux plages HSV. Cette démo utilise une plage simple.") lower_bound = np.array([0, 100, 100]) upper_bound = np.array([10, 255, 255]) # Second range for red (optional, for more complete red detection) # lower_red2 = np.array([160, 100, 100]) # upper_red2 = np.array([179, 255, 255]) elif color_choice == "Jaune": lower_bound = np.array([20, 100, 100]) upper_bound = np.array([40, 255, 255]) elif color_choice == "Orange": lower_bound = np.array([10, 100, 100]) upper_bound = np.array([25, 255, 255]) elif color_choice == "Violet": lower_bound = np.array([130, 50, 50]) upper_bound = np.array([160, 255, 255]) elif color_choice == "Personnalisé": st.sidebar.subheader("Définir la plage HSV personnalisée") h_lower = st.sidebar.slider("Teinte (H) Min", 0, 179, 0) h_upper = st.sidebar.slider("Teinte (H) Max", 0, 179, 179) s_lower = st.sidebar.slider("Saturation (S) Min", 0, 255, 0) s_upper = st.sidebar.slider("Saturation (S) Max", 0, 255, 255) v_lower = st.sidebar.slider("Valeur (V) Min", 0, 255, 0) v_upper = st.sidebar.slider("Valeur (V) Max", 0, 255, 255) lower_bound = np.array([h_lower, s_lower, v_lower]) upper_bound = np.array([h_upper, s_upper, v_upper]) if uploaded_file is not None: # Convertir l'image BGR en HSV hsv_image = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV) # Créer un masque pour la couleur sélectionnée mask = cv2.inRange(hsv_image, lower_bound, upper_bound) # Appliquer le masque à l'image originale # On utilise bitwise_and pour n'afficher que les pixels qui correspondent au masque isolated_color_bgr = cv2.bitwise_and(img_bgr, img_bgr, mask=mask) # Convertir le résultat en RGB pour l'affichage Streamlit isolated_color_rgb = cv2.cvtColor(isolated_color_bgr, cv2.COLOR_BGR2RGB) st.subheader(f"Couleur isolée : {color_choice}") st.image(isolated_color_rgb, caption=f"{color_choice} isolé", use_column_width=True) st.subheader("Masque généré") st.image(mask, caption="Masque (blanc = couleur détectée)", use_column_width=True) st.markdown(""" **Comment ça marche ?** 1. **Conversion HSV :** L'image originale est convertie de l'espace couleur BGR (utilisé par OpenCV) à HSV (Teinte, Saturation, Valeur). HSV est idéal pour la détection de couleurs car la teinte (H) isole la couleur elle-même, indépendamment de la luminosité ou de l'intensité. 2. **Définition de la Plage HSV :** Pour chaque couleur, une plage inférieure (`lower_bound`) et une plage supérieure (`upper_bound`) sont définies en termes de valeurs H, S et V. 3. **Création du Masque :** La fonction `cv2.inRange()` est utilisée pour créer un masque binaire. Tous les pixels de l'image HSV qui tombent dans la plage définie obtiennent une valeur de 255 (blanc), les autres 0 (noir). 4. **Application du Masque :** La fonction `cv2.bitwise_and()` combine l'image originale avec le masque. Seuls les pixels où le masque est blanc sont conservés de l'image originale ; les autres deviennent noirs. """) else: st.info("Veuillez télécharger une image pour commencer.")