import gradio as gr from PIL import Image import numpy as np import cv2 import matplotlib.pyplot as plt # Fonctions de traitement d'image def load_image(image): return image def apply_negative(image): """ Transforme l'image en son négatif en inversant les valeurs de chaque pixel. En résumé chaque pixel est soustrait de 255. """ img = np.array(image) negative = 255 - img return Image.fromarray(negative) def binarize_image(image, threshold): """ D'abord l'image est convertie en niveau de gris. Puis on utilise un seuil moyen pour la binarison de l'image. """ img = np.array(image) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_binary = np.where( img_gray < threshold, 0, 255).astype(np.uint8) return Image.fromarray(img_binary) def resize_image(image, width, height): """ Demande à l'utilisateur de choisir la hauteur et la largeur finale de l'image. Ensuite resize cette image à partir de ces informations """ return image.resize((width, height)) def rotate_image(image, angle): """ Faire tourner l'image sur des angles données """ return image.rotate(angle) def histogramme(image): """ Afficher l'histogramme de l'image. La fonction fait la différence entre les images à un canal et celles à trois """ img_array = np.array(image) gray_image = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) fig, axis = plt.subplots(figsize=(8, 4)) axis.set_title("Histogramme des niveaux de gris") histo = cv2.calcHist([img_array], [0], None, [256], [0, 256]) axis.plot(histo, color='black') fig.canvas.draw() data = np.frombuffer(fig.canvas.buffer_rgba(), dtype=np.uint8) data = data.reshape(fig.canvas.get_width_height()[::-1] + (4,)) plt.close(fig) return Image.fromarray(data[:,:,:3]) def contours_Sobel(image): """ Détecter et afficher les contours des images """ img = np.array(image) gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=5) sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=5) sobel = np.sqrt(sobel_x**2 + sobel_y**2) sobel = np.uint8(sobel) return Image.fromarray(sobel) def filtre_Gaussien(image, kernel_size=5): """ Appliquer un Filtre Gaussien avec une matrice définissable par l'utilisateur à l'image """ img = np.array(image) flou = cv2.GaussianBlur(img, (kernel_size, kernel_size), 0) return Image.fromarray(flou) def erosion(image): croix = np.array([ [0,1,0], [1,1,1], [0,1,0]], dtype=np.uint8) croix = croix*255 image_test = np.array(image) img_erosion = cv2.erode(image_test, croix) return Image.fromarray(img_erosion) def dilatation(image): croix = np.array([ [0,1,0], [1,1,1], [0,1,0]], dtype=np.uint8) croix = croix*255 image_test = np.array(image) img_dilate = cv2.dilate(image_test, croix) return Image.fromarray(img_dilate) def update_fields(operation): if operation == "Redimensionner": return (gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)) elif operation == "Binarisation": return (gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)) elif operation == "Rotation": return (gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)) elif operation == "Filtre Gaussien": return (gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)) else: return (gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)) def image_processing(image, operation, threshold=128, width=100, height=100, angle=0, kernel_size=5): if operation == "Négatif": return apply_negative(image) elif operation == "Binarisation": return binarize_image(image, threshold) elif operation == "Redimensionner": return resize_image(image, width, height) elif operation == "Rotation": return rotate_image(image, angle) elif operation == "Contours Sobel": return contours_Sobel(image) elif operation == "Filtre Gaussien": return filtre_Gaussien(image, kernel_size) elif operation == "Erosion": return erosion(image) elif operation == "Dilatation": return dilatation(image) return image def load_image_and_histogram(image): hist_image = histogramme(image) return hist_image # Interface Gradio with gr.Blocks() as demo: gr.Markdown("## Image Master") with gr.Row(): image_input = gr.Image( type="pil", label="Charger Image" ) operation = gr.Radio( ["Négatif", "Binarisation", "Redimensionner", "Rotation", "Contours Sobel", "Filtre Gaussien", "Erosion", "Dilatation" ], label="Opération") threshold = gr.Slider(0, 255, 128, label="Seuil de binarisation", visible=False) width = gr.Slider(minimum=50, maximum=1000, value=100, step=10, label="Largeur", visible=False) height = gr.Slider(minimum=50, maximum=1000, value=100, step=10, label="Hauteur", visible=False) angle = gr.Slider(minimum=-180, maximum=180, value=0, step=1, label="Angle de Rotation", visible=False) kernel_size = gr.Slider(minimum=1, maximum=21, value=5, step=2, label="Taille du Noyau (Flou)", visible=False) image_output = gr.Image(label="Image Modifiée") submit_button = gr.Button("Appliquer") histogram_output = gr.Image(label="Histogramme") operation.change(update_fields, inputs=[operation], outputs=[width, height, threshold, angle, kernel_size]) image_input.change(load_image_and_histogram, inputs=image_input, outputs=histogram_output) submit_button.click(image_processing, inputs=[image_input, operation, threshold, width, height, angle, kernel_size], outputs=image_output) demo.launch()