Création d’un Outil d’Annotation d’Images Python personnalisé, ultra-rapide et fonctionnant hors ligne
J'ai développpé un outil d'annotation d'image personnalisé en Python qui fonctionne hors ligne et offre une expérience quasi instantanée. En utilisant des bibliothèques comme labelme, Tkinter et des raccourcis clavier, j'ai créé une solution locale rapide pour mes datasets d'IA, sans latence ni superflu. Lorsqu'on travaille avec des datasets d'images pour l'intelligence artificielle, l'annotation peut rapidement devenir un point d'achoppement. La plupart des outils basés sur le web sont soit trop lents, soit trop chargés en fonctionnalités pour des tâches simples, ou encore mal adaptés à l'utilisation hors ligne. Je m'étais lassé de l'annotation de centaines de boîtes de délimitation à l'aide de la souris dans des interfaces web, c'est pourquoi j'ai décidé de créer un outil d'annotation de bureau en Python. Cet outil est léger, fonctionne hors ligne et accélère le processus grâce aux raccourcis clavier. Que ce soit pour l'annotation de zones d’intérêt (YOLO), le dessin de polygones pour la segmentation, ou la classification d'images, cet outil s’avère particulièrement efficace. Voici comment vous pouvez construire votre propre utilitaire d'annotation en Python : 1. Configuration : Installation de labelme et Tkinter Nous utiliserons labelme pour ses capacités d'annotation et Tkinter pour l'interface utilisateur. Commencez par installer labelme via pip : bash pip install labelme Tkinter est généralement inclus dans les installations standard de Python, mais si vous rencontrez des problèmes, vous pouvez l'installer via le gestionnaire de paquets de votre distribution Linux : bash sudo apt-get install python3-tk 2. Création de l'Interface Utilisateur avec Tkinter Tkinter est une bibliothèque graphique intégrée à Python, idéale pour créer des interfaces simples et rapides. Voici un exemple de base pour initialiser l'interface utilisateur : ```python import tkinter as tk from tkinter import filedialog import os Initialisation de la fenêtre principale root = tk.Tk() root.title("Outil d'Annotation d'Images") Fonction pour sélectionner le dossier de l'image def select_folder(): folder_selected = filedialog.askdirectory() if folder_selected: load_images(folder_selected) Fonction pour charger les images du dossier sélectionné def load_images(folder_path): # Liste des images du dossier image_files = [f for f in os.listdir(folder_path) if f.endswith(('.png', '.jpg', '.jpeg'))] if not image_files: status_label.config(text="Aucune image trouvée") else: global current_image_index current_image_index = 0 show_image(image_files[current_image_index]) Fonction pour afficher l'image courante def show_image(image_file): global image_label image_path = os.path.join(folder_path, image_file) img = tk.PhotoImage(file=image_path) image_label.config(image=img) image_label.image = img status_label.config(text=f"Image {current_image_index + 1}/{len(image_files)} : {image_file}") Boutons pour naviguer entre les images def next_image(): global current_image_index if current_image_index < len(image_files) - 1: current_image_index += 1 show_image(image_files[current_image_index]) def previous_image(): global current_image_index if current_image_index > 0: current_image_index -= 1 show_image(image_files[current_image_index]) Interface utilisateur folder_path = "" image_files = [] current_image_index = 0 status_label = tk.Label(root, text="") status_label.pack(pady=10) button_frame = tk.Frame(root) button_frame.pack(pady=10) select_button = tk.Button(button_frame, text="Sélectionner Dossier", command=select_folder) select_button.grid(row=0, column=0, padx=5) next_button = tk.Button(button_frame, text="Suivant", command=next_image) next_button.grid(row=0, column=2, padx=5) previous_button = tk.Button(button_frame, text="Précédent", command=previous_image) previous_button.grid(row=0, column=1, padx=5) image_label = tk.Label(root) image_label.pack(pady=20) Lancement de l'application root.mainloop() ``` 3. Intégration des Annotations avec labelme Labelme est un outil d'annotation d'images puissant et flexible, parfait pour des tâches complexes. Pour l’intégrer à votre interface Tkinter, vous pouvez utiliser son API pour gérer les annotations. Voici comment vous pouvez ajouter cette fonctionnalité : ```python import labelme Fonction pour initialiser le gestionnaire d'annotation def initialize_annotation_tool(image_file): canvas = labelme.widgets.Canvas() canvas.load_background_image(image_file) root.mainloop() Appel de la fonction d'initialisation lors du chargement d'une image def show_image(image_file): global image_label image_path = os.path.join(folder_path, image_file) img = tk.PhotoImage(file=image_path) image_label.config(image=img) image_label.image = img status_label.config(text=f"Image {current_image_index + 1}/{len(image_files)} : {image_file}") initialize_annotation_tool(image_path) Mise à jour de la fonction pour charger les images def load_images(folder_path): global image_files, current_image_index, folder_selected folder_selected = folder_path image_files = [f for f in os.listdir(folder_path) if f.endswith(('.png', '.jpg', '.jpeg'))] if not image_files: status_label.config(text="Aucune image trouvée") else: current_image_index = 0 show_image(image_files[current_image_index]) ``` 4. Utilisation des Raccourcis Clavier Pour accélérer le processus, vous pouvez ajouter des raccourcis clavier qui permettent de naviguer plus rapidement entre les images et d'effectuer des actions d'annotation. Voici comment cela peut être fait : python root.bind("<Right>", lambda e: next_image()) root.bind("<Left>", lambda e: previous_image()) Placez ces lignes de code juste avant l'appel de root.mainloop(). 5. Enregistrement et Gestion des Annotations La gestion des annotations est cruciale. Vous pouvez enregistrer les annotations au fur et à mesure de leur création en utilisant les fonctionnalités de labelme. Voici un exemple simplifié : ```python import json Fonction pour sauvegarder les annotations def save_annotation(annotation_data, image_file): annotation_path = os.path.join(folder_path, f"{os.path.splitext(image_file)[0]}.json") with open(annotation_path, 'w') as f: json.dump(annotation_data, f, indent=4) Exemple d'usage lors de la fermeture de la fenêtre def on_close(): annotation_data = canvas.get_labeldata() # Obtient les données d'annotation save_annotation(annotation_data, image_files[current_image_index]) root.destroy() Lier la fermeture de la fenêtre à la fonction on_close root.protocol("WM_DELETE_WINDOW", on_close) ``` Avec ces étapes, vous disposez d'un outil d'annotation d'images personnalisé, rapide et efficace, qui fonctionne parfaitement hors ligne et facilite considérablement le processus d'annotation. Que vous soyez un chercheur en IA ou un développeur travaillant sur des datasets d'images, cet outil sera un atout précieux pour accélérer vos tâches de préparation des données.