Spaces:
Runtime error
Runtime error
| from PIL import Image | |
| import numpy as np | |
| import math | |
| import gradio as gr | |
| import io | |
| from collections import Counter | |
| from sklearn.cluster import KMeans | |
| import colorsys | |
| def rgb_to_hsv(rgb): | |
| """Convertit RGB vers HSV""" | |
| r, g, b = rgb / 255.0 | |
| return np.array(colorsys.rgb_to_hsv(r, g, b)) | |
| def extract_dominant_colors(image, max_colors=100): | |
| """Extrait les couleurs dominantes en regroupant par teintes""" | |
| if image.mode != 'RGB': | |
| image = image.convert('RGB') | |
| # Convertit en tableau numpy | |
| np_image = np.array(image) | |
| pixels = np_image.reshape(-1, 3) | |
| if len(pixels) == 0: | |
| return np.array([]) | |
| # Si on a moins de couleurs que la limite, on retourne toutes les couleurs uniques | |
| unique_pixels = np.unique(pixels, axis=0) | |
| if len(unique_pixels) <= max_colors: | |
| return unique_pixels | |
| # Sinon, on utilise K-means pour regrouper les couleurs similaires | |
| kmeans = KMeans(n_clusters=max_colors, random_state=42, n_init=10) | |
| kmeans.fit(pixels) | |
| # Retourne les centres des clusters (couleurs dominantes) | |
| return kmeans.cluster_centers_.astype(int) | |
| def sort_colors_by_hue(colors): | |
| """Trie les couleurs par teinte (HSL)""" | |
| def get_hue(rgb): | |
| r, g, b = rgb / 255.0 | |
| h, s, v = colorsys.rgb_to_hsv(r, g, b) | |
| return h | |
| def get_brightness(rgb): | |
| return np.mean(rgb) | |
| # Trie d'abord par teinte, puis par luminosité | |
| sorted_colors = sorted(colors, key=lambda rgb: (get_hue(rgb), get_brightness(rgb))) | |
| return np.array(sorted_colors) | |
| def create_color_palette(colors, square_size=50): | |
| if len(colors) == 0: | |
| return None | |
| num_colors = len(colors) | |
| # Calcul du nombre de colonnes et lignes pour faire un carré | |
| grid_size = math.ceil(math.sqrt(num_colors)) | |
| palette_size = grid_size * square_size | |
| # Crée une image vide | |
| palette = Image.new("RGB", (palette_size, palette_size), (255, 255, 255)) | |
| for i, color in enumerate(colors): | |
| r, g, b = color | |
| # Crée un carré de la couleur | |
| color_square = Image.new("RGB", (square_size, square_size), (int(r), int(g), int(b))) | |
| x = (i % grid_size) * square_size | |
| y = (i // grid_size) * square_size | |
| palette.paste(color_square, (x, y)) | |
| return palette | |
| def process_image(input_image, max_colors, sort_by_hue): | |
| if input_image is None: | |
| return None, "Veuillez uploader une image" | |
| try: | |
| # Extraction des couleurs dominantes | |
| colors = extract_dominant_colors(input_image, max_colors) | |
| # Tri par teinte si demandé | |
| if sort_by_hue and len(colors) > 0: | |
| colors = sort_colors_by_hue(colors) | |
| # Création de la palette | |
| palette = create_color_palette(colors) | |
| if palette is not None: | |
| message = f"Palette créée avec {len(colors)} couleurs dominantes" | |
| return palette, message | |
| else: | |
| return None, "Aucune couleur trouvée dans l'image" | |
| except Exception as e: | |
| return None, f"Erreur lors du traitement : {str(e)}" | |
| def download_palette(input_image, max_colors, sort_by_hue): | |
| if input_image is None: | |
| return None | |
| try: | |
| colors = extract_dominant_colors(input_image, max_colors) | |
| if sort_by_hue and len(colors) > 0: | |
| colors = sort_colors_by_hue(colors) | |
| palette = create_color_palette(colors) | |
| if palette: | |
| # Sauvegarde dans un buffer | |
| buffer = io.BytesIO() | |
| palette.save(buffer, format="PNG") | |
| buffer.seek(0) | |
| return buffer | |
| except: | |
| return None | |
| # Création de l'interface Gradio | |
| with gr.Blocks(title="Extracteur de Palette de Couleurs") as demo: | |
| gr.Markdown("# 🎨 Extracteur de Palette de Couleurs") | |
| gr.Markdown("Upload une image pour extraire les couleurs dominantes et créer une palette visuelle") | |
| with gr.Row(): | |
| with gr.Column(): | |
| input_image = gr.Image(type="pil", label="Image d'entrée") | |
| max_colors = gr.Slider(minimum=5, maximum=200, value=50, step=5, label="Nombre maximum de couleurs") | |
| sort_by_hue = gr.Checkbox(value=True, label="Trier par teintes") | |
| with gr.Row(): | |
| submit_btn = gr.Button("🎨 Extraire les couleurs", variant="primary") | |
| download_btn = gr.DownloadButton("💾 Télécharger la palette", variant="secondary") | |
| with gr.Column(): | |
| output_image = gr.Image(label="Palette de couleurs", interactive=False) | |
| status_text = gr.Textbox(label="Statut", interactive=False) | |
| # Traitement principal | |
| submit_btn.click( | |
| fn=process_image, | |
| inputs=[input_image, max_colors, sort_by_hue], | |
| outputs=[output_image, status_text] | |
| ) | |
| # Téléchargement | |
| download_btn.click( | |
| fn=download_palette, | |
| inputs=[input_image, max_colors, sort_by_hue], | |
| outputs=[download_btn] | |
| ) | |
| # Exemples | |
| gr.Examples( | |
| examples=[ | |
| ["https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/1200px-React-icon.svg.png", 50, True], | |
| ["https://upload.wikimedia.org/wikipedia/commons/thumb/6/61/HTML5_logo_and_wordmark.svg/1200px-HTML5_logo_and_wordmark.svg.png", 30, True] | |
| ], | |
| inputs=[input_image, max_colors, sort_by_hue], | |
| outputs=[output_image, status_text], | |
| fn=process_image | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |