Categories We Write About

Build an image labeling app with Python

Creating an image labeling app with Python involves building a simple GUI (Graphical User Interface) that allows users to load images, annotate them (e.g., with bounding boxes or labels), and save the annotations. Below is a complete guide using Tkinter for the GUI and Pillow for image handling.


Dependencies

Install required packages:

bash
pip install pillow

Image Labeling App with Tkinter

python
import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTk import os import json class ImageLabelingApp: def __init__(self, root): self.root = root self.root.title("Image Labeling App") self.image_panel = tk.Label(self.root) self.image_panel.pack() self.control_frame = tk.Frame(self.root) self.control_frame.pack() tk.Button(self.control_frame, text="Load Image", command=self.load_image).pack(side=tk.LEFT) tk.Button(self.control_frame, text="Next", command=self.next_image).pack(side=tk.LEFT) tk.Button(self.control_frame, text="Save Label", command=self.save_label).pack(side=tk.LEFT) self.label_entry = tk.Entry(self.control_frame) self.label_entry.pack(side=tk.LEFT) self.label_entry.insert(0, "Enter label") self.canvas = tk.Canvas(self.root, cursor="cross") self.canvas.pack() self.canvas.bind("<Button-1>", self.on_click) self.images = [] self.image_index = 0 self.labels = {} self.current_image_path = "" self.rect_start = None self.rect = None def load_image(self): directory = filedialog.askdirectory(title="Select Image Folder") if directory: self.images = [os.path.join(directory, f) for f in os.listdir(directory) if f.lower().endswith(('.png', '.jpg', '.jpeg'))] self.image_index = 0 self.labels = {} self.load_current_image() def load_current_image(self): if self.image_index < len(self.images): self.current_image_path = self.images[self.image_index] img = Image.open(self.current_image_path) self.tk_img = ImageTk.PhotoImage(img) self.canvas.config(width=self.tk_img.width(), height=self.tk_img.height()) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_img) self.rect_start = None self.rect = None else: messagebox.showinfo("Done", "No more images.") def next_image(self): self.image_index += 1 self.load_current_image() def on_click(self, event): if not self.rect_start: self.rect_start = (event.x, event.y) else: x0, y0 = self.rect_start x1, y1 = event.x, event.y label = self.label_entry.get() if self.current_image_path not in self.labels: self.labels[self.current_image_path] = [] self.labels[self.current_image_path].append({ "label": label, "box": [x0, y0, x1, y1] }) self.canvas.create_rectangle(x0, y0, x1, y1, outline="red") self.rect_start = None def save_label(self): if not self.labels: messagebox.showwarning("No Data", "No labels to save.") return save_path = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("JSON files", "*.json")]) if save_path: with open(save_path, "w") as f: json.dump(self.labels, f, indent=4) messagebox.showinfo("Saved", f"Labels saved to {save_path}") if __name__ == "__main__": root = tk.Tk() app = ImageLabelingApp(root) root.mainloop()

Features

  • Load all images from a folder.

  • Click twice to draw bounding boxes.

  • Assign a label using a text entry.

  • Save all labeled data as a JSON file with the format:

json
{ "image1.jpg": [ { "label": "cat", "box": [x0, y0, x1, y1] } ] }

Optional Enhancements

  • Add support for multi-label annotations per image.

  • Implement undo for last rectangle.

  • Display existing labels when reloading.

  • Use more advanced libraries like OpenCV for higher performance or more complex GUIs with PyQt or Kivy.

This script provides a minimal, functional image annotation tool that you can easily customize for datasets or machine learning purposes.

Share This Page:

Enter your email below to join The Palos Publishing Company Email List

We respect your email privacy

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Categories We Write About