import streamlit as st
import numpy as np
import cv2
#from PIL import Image
# Configuration de la page pour éviter le comportement de retour en arrière
st.set_page_config(layout="wide")
# Initialisation des variables d'état
if 'color_rgb' not in st.session_state:
st.session_state['color_rgb'] = np.array([128, 128, 128], dtype=np.uint8)
if 'color_space' not in st.session_state:
st.session_state['color_space'] = "RGB"
# Fonctions de conversion de couleurs
def create_opencv_color_square(color_array):
img = np.full((400, 400, 3), color_array, dtype=np.uint8)
bordered_img = cv2.copyMakeBorder(src=img, top=1, bottom=1, left=1, right=1, borderType=cv2.BORDER_CONSTANT,value=[64,64,64])
return bordered_img
def rgb_to_gray(rgb):
return cv2.cvtColor(np.uint8([[rgb]]), cv2.COLOR_RGB2GRAY)[0][0]
def bgr_to_rgb(bgr):
return cv2.cvtColor(np.uint8([[bgr]]), cv2.COLOR_BGR2RGB)[0][0]
def rgb_to_bgr(rgb):
return cv2.cvtColor(np.uint8([[rgb]]), cv2.COLOR_RGB2BGR)[0][0]
def rgb_to_hsv(rgb):
return cv2.cvtColor(np.uint8([[rgb]]), cv2.COLOR_RGB2HSV)[0][0]
def hsv_to_rgb(hsv):
return cv2.cvtColor(np.uint8([[hsv]]), cv2.COLOR_HSV2RGB)[0][0]
def rgb_to_lab(rgb):
return cv2.cvtColor(np.uint8([[rgb]]), cv2.COLOR_RGB2LAB)[0][0]
def lab_to_rgb(lab):
return cv2.cvtColor(np.uint8([[lab]]), cv2.COLOR_LAB2RGB)[0][0]
# Fonction pour initialiser les valeurs des sliders en fonction de l'espace de couleur
def init_slider_values():
if 'slider_initialized' not in st.session_state:
st.session_state['slider_initialized'] = {}
color_space = st.session_state['color_space']
# Initialiser les valeurs des sliders uniquement si elles n'existent pas déjà ou si l'espace couleur a changé
if color_space not in st.session_state['slider_initialized'] or not st.session_state['slider_initialized'][color_space]:
if color_space == "Niveau de gris":
#st.session_state['gray_value'] = int(st.session_state['color_rgb'][0])
st.session_state['gray_value'] = int(rgb_to_gray(st.session_state['color_rgb']))
print(st.session_state['gray_value'])
elif color_space == "RGB":
st.session_state['r_value'] = int(st.session_state['color_rgb'][0])
st.session_state['g_value'] = int(st.session_state['color_rgb'][1])
st.session_state['b_value'] = int(st.session_state['color_rgb'][2])
elif color_space == "BGR":
bgr_val = rgb_to_bgr(st.session_state['color_rgb'])
st.session_state['b_value_bgr'] = int(bgr_val[0])
st.session_state['g_value_bgr'] = int(bgr_val[1])
st.session_state['r_value_bgr'] = int(bgr_val[2])
elif color_space == "HSV":
hsv_val = rgb_to_hsv(st.session_state['color_rgb'])
st.session_state['h_value'] = int(hsv_val[0])
st.session_state['s_value'] = int(hsv_val[1])
st.session_state['v_value'] = int(hsv_val[2])
elif color_space == "Lab":
lab_val = rgb_to_lab(st.session_state['color_rgb'])
#print(lab_val)
st.session_state['l_value'] = int(lab_val[0]/2.55)
st.session_state['a_value'] = int(lab_val[1]) - 128
st.session_state['b_value_lab'] = int(lab_val[2]) - 128
st.session_state['slider_initialized'][color_space] = True
# Fonction pour mettre à jour la couleur RGB en fonction des valeurs des sliders
def update_color_from_sliders():
color_space = st.session_state['color_space']
if color_space == "Niveau de gris":
gray = st.session_state['gray_value']
#print(gray)
st.session_state['color_rgb'] = np.array([gray, gray, gray], dtype=np.uint8)
elif color_space == "RGB":
r = st.session_state['r_value']
g = st.session_state['g_value']
b = st.session_state['b_value']
st.session_state['color_rgb'] = np.array([r, g, b], dtype=np.uint8)
elif color_space == "BGR":
b_val = st.session_state['b_value_bgr']
g_val = st.session_state['g_value_bgr']
r_val = st.session_state['r_value_bgr']
st.session_state['color_rgb'] = bgr_to_rgb(np.array([b_val, g_val, r_val], dtype=np.uint8))
elif color_space == "HSV":
h = st.session_state['h_value']
s = st.session_state['s_value']
v = st.session_state['v_value']
st.session_state['color_rgb'] = hsv_to_rgb(np.array([h, s, v], dtype=np.uint8))
elif color_space == "Lab":
l = int(st.session_state['l_value']*2.55)
a = st.session_state['a_value']
b_val = st.session_state['b_value_lab']
st.session_state['color_rgb'] = lab_to_rgb(np.array([l, a + 128, b_val + 128], dtype=np.uint8))
# Fonction pour changer l'espace de couleur
def change_color_space():
st.session_state['slider_initialized'][st.session_state['color_space']] = False
# Ne pas mettre à jour la couleur RGB ici, juste changer l'espace
# Interface utilisateur principale
def main():
#st.title("Manipulation des espaces colorimétriques")
st.markdown("""""", unsafe_allow_html=True)
st.markdown("
Manipuler les espaces colorimétriques
", unsafe_allow_html=True)
#st.markdown("
", unsafe_allow_html=True)
# Initialisation
if 'slider_initialized' not in st.session_state:
st.session_state['slider_initialized'] = {}
for cs in ["Niveau de gris", "RGB", "BGR", "HSV", "Lab"]:
st.session_state['slider_initialized'][cs] = False
# Structure de l'application
col_settings, col_visual, col_definitions,other = st.columns([1, 1, 1,1],gap="large",border=False,vertical_alignment="top")
with col_settings:
st.markdown("Réglages
", unsafe_allow_html=True)
#st.markdown("---")
# Sélection de l'espace colorimétrique (avec callback pour initialiser les sliders)
color_space = st.selectbox(
"Choisissez un espace colorimétrique",
("Niveau de gris", "RGB", "BGR", "HSV", "Lab"),
key="color_space",
on_change=change_color_space
)
# Initialiser les valeurs des sliders
init_slider_values()
# Afficher les sliders en fonction de l'espace colorimétrique
if color_space == "Niveau de gris":
st.slider("Niveau de gris", 0, 255, key="gray_value", on_change=update_color_from_sliders)
elif color_space == "RGB":
st.slider("Rouge (R)", 0, 255, key="r_value", on_change=update_color_from_sliders)
st.slider("Vert (G)", 0, 255, key="g_value", on_change=update_color_from_sliders)
st.slider("Bleu (B)", 0, 255, key="b_value", on_change=update_color_from_sliders)
elif color_space == "BGR":
st.slider("Bleu (B)", 0, 255, key="b_value_bgr", on_change=update_color_from_sliders)
st.slider("Vert (G)", 0, 255, key="g_value_bgr", on_change=update_color_from_sliders)
st.slider("Rouge (R)", 0, 255, key="r_value_bgr", on_change=update_color_from_sliders)
elif color_space == "HSV":
st.slider("Teinte (H)", 0, 179, key="h_value", on_change=update_color_from_sliders)
st.slider("Saturation (S)", 0, 255, key="s_value", on_change=update_color_from_sliders)
st.slider("Valeur (V)", 0, 255, key="v_value", on_change=update_color_from_sliders)
elif color_space == "Lab":
st.slider("Luminosité (L)", 0, 100, key="l_value", on_change=update_color_from_sliders)
st.slider("Composante a", -128, 127, key="a_value", on_change=update_color_from_sliders)
st.slider("Composante b", -128, 127, key="b_value_lab", on_change=update_color_from_sliders)
with col_visual:
st.markdown("Visualisation
", unsafe_allow_html=True)
st.markdown("---")
# Afficher l'échantillon de couleur et ses coordonnées
if color_space == "Niveau de gris":
nb = rgb_to_gray(st.session_state['color_rgb'])
st.image(create_opencv_color_square(nb),
caption=f"Niveau de gris : {int(st.session_state['color_rgb'][0])}")
elif color_space == "RGB":
st.image(create_opencv_color_square(st.session_state['color_rgb']),
caption=f"RGB : ({int(st.session_state['color_rgb'][0])}, {int(st.session_state['color_rgb'][1])}, {int(st.session_state['color_rgb'][2])})")
elif color_space == "BGR":
bgr_color = rgb_to_bgr(st.session_state['color_rgb'])
st.image(create_opencv_color_square(st.session_state['color_rgb']),
caption=f"BGR : ({int(bgr_color[0])}, {int(bgr_color[1])}, {int(bgr_color[2])})")
elif color_space == "HSV":
hsv_color = rgb_to_hsv(st.session_state['color_rgb'])
st.image(create_opencv_color_square(st.session_state['color_rgb']),
caption=f"HSV : ({int(hsv_color[0])}, {int(hsv_color[1])}, {int(hsv_color[2])})")
elif color_space == "Lab":
lab_color = rgb_to_lab(st.session_state['color_rgb'])
#print(lab_color)
st.image(create_opencv_color_square(st.session_state['color_rgb']),
caption=f"Lab : ({int(lab_color[0]/2.55)}, {int(lab_color[1]) - 128:.0f}, {int(lab_color[2]) - 128:.0f})")
with col_definitions:
#st.markdown("Définitions des paramètres
", unsafe_allow_html=True)
st.markdown("Définitions
", unsafe_allow_html=True)
st.markdown("---") # Ajout d'une ligne de séparation
if 'color_space' in st.session_state and st.session_state.color_space == "Niveau de gris":
st.markdown("**Niveau de gris :**")
st.markdown("* La valeur de chaque pixel varie de `0` à `255`.")
st.markdown("* `0` représente le noir et `255` représente le blanc.")
st.markdown("* Les valeurs intermédiaires représentent différentes nuances de gris.")
elif 'color_space' in st.session_state and st.session_state.color_space == "RGB":
st.markdown("**RGB (Rouge, Vert, Bleu) :**")
st.markdown("* Chaque pixel est représenté par une combinaison de trois canaux de couleur primaires : le **Rouge (R)**, le **Vert (G)** et le **Bleu (B)**.")
st.markdown("* La valeur de chaque canal varie généralement de `0` à `255`.")
st.markdown("* `0` signifie l'absence de cette couleur primaire, et `255` signifie sa pleine intensité.")
st.markdown("* En combinant différentes intensités de ces trois couleurs, on peut obtenir un large spectre de couleurs.")
st.markdown("* Par exemple :")
st.markdown(" * `(255, 0, 0)` représente le rouge pur.")
st.markdown(" * `(0, 255, 0)` représente le vert pur.")
st.markdown(" * `(0, 0, 255)` représente le bleu pur.")
st.markdown(" * `(255, 255, 255)` représente le blanc.")
st.markdown(" * `(0, 0, 0)` représente le noir.")
st.markdown("**Applications :**")
st.markdown("* Apprentissage profond")
st.markdown("* Génération d'images")
st.markdown("* Là où la fidélité des couleurs est importante")
elif 'color_space' in st.session_state and st.session_state.color_space == "BGR":
st.markdown("**Format d'OpenCV.**")
st.markdown("**BGR (Bleu, Vert, Rouge) :**")
st.markdown("* Similaire à RGB, mais l'ordre des canaux de couleur est inversé : **Bleu (B)**, **Vert (G)** et **Rouge (R)**.")
st.markdown("* La valeur de chaque canal varie généralement de `0` à `255`, avec la même signification qu'en RGB.")
st.markdown("* Par exemple, la représentation BGR du rouge pur serait `(0, 0, 255)`. ")
st.markdown("**Applications :**")
st.markdown("* Uniquement pour l'interopérabilité si l'espace utilisé est BGR. **Sinon transformer en RGB.**")
elif 'color_space' in st.session_state and st.session_state.color_space == "HSV":
st.markdown("Représente les couleurs en fonction de trois composantes plus intuitives pour la perception humaine. Il sépare l'information de la couleur (teinte) de son intensité et de sa pureté")
st.markdown("**HSV (Teinte, Saturation, Valeur) :**")
st.markdown(" * **Teinte (Hue)** : Indique le type de couleur (rouge, jaune, vert, bleu, violet, magenta, rouge). Elle est généralement représentée par un angle sur un cercle de couleurs, allant de `0°` à `360°` (ou normalisée de `0` à `1`). **Pour OpenCV, l'angle va de 0 à 180°.**")
st.markdown(" * **Saturation (Saturation)** : Décrit la pureté de la couleur. Une saturation élevée signifie une couleur vive et intense, tandis qu'une saturation faible tend vers le gris (`0` signifie un gris pur). Elle varie généralement de `0` à `1` ou de `0%` à `100%`.**Pour OpenCV, la saturation varie de 0 à 255.**")
st.markdown(" * **Valeur (Value)** : Représente la luminosité de la couleur. Une valeur élevée signifie une couleur claire, tandis qu'une valeur faible tend vers le noir (`0` signifie le noir). Elle varie généralement de `0` à `1` ou de `0%` à `100%`.**Pour OpenCV, la value varie de 0 à 255.**")
st.markdown("**Applications :**")
st.markdown("* Segmentation d'objets ou de régions de couleur spécifique")
st.markdown("* Détection d'objets plus robuste que RGB")
st.markdown("* Analyse de couleurs dominantes et filtrage de couleurs")
st.markdown("* Analyse de textures par rapport à la couleur")
st.markdown("* Vision par ordinateur dans des conditions d'éclairage variable")
elif 'color_space' in st.session_state and st.session_state.color_space == "Lab":
st.markdown("Espace colorimétrique conçu pour être **perceptuellement uniforme**, ce qui signifie qu'une même différence numérique de couleur correspond à une différence visuellement similaire pour l'œil humain.")
st.markdown("**Lab (Luminosité, a, b) :**")
st.markdown(" * **Luminosité (L)** : Représente la clarté de la couleur, allant de `0` (noir absolu) à `100` (blanc diffus).")
st.markdown(" * **a** : Représente la position sur l'axe vert-rouge. Les valeurs négatives indiquent le vert, et les valeurs positives indiquent le rouge. La plage typique est d'environ `-128` à `+127` (cela peut varier).")
st.markdown(" * **b** : Représente la position sur l'axe bleu-jaune. Les valeurs négatives indiquent le bleu, et les valeurs positives indiquent le jaune. La plage typique est également d'environ `-128` à `+127` (cela peut varier).")
st.markdown("* L'espace Lab est souvent utilisé dans le traitement d'image pour des tâches comme la mesure de la couleur et la correction des couleurs, car il est moins dépendant des dispositifs (écrans, imprimantes) que les espaces RGB ou CMYK.")
st.markdown("**Applications :**")
st.markdown("* Segmentation où la disctinction doit correspondre à la perception humaine")
st.markdown("* Mesure et comparaison de la différence de couleur")
st.markdown("* Ajout de couleurs réalistes à des images en noir et blanc")
st.markdown("* Analyse d'images médicales ou scientifiques")
else:
st.info("Sélectionnez un espace colorimétrique pour afficher sa définition.")
if __name__ == "__main__":
main()