Python GUI 9‑Grid Image Stitching with Customizable Cell Size
This tutorial explains how to build a Python GUI application using tkinter and Pillow that lets users select nine images, adjust the cell size, and automatically merge them into a 3×3 grid, complete with code examples and usage instructions.
This article demonstrates how to create a Python GUI application for 9‑grid image stitching using tkinter as the interface library and the Pillow library for image processing.
First, ensure the required libraries are installed; tkinter comes with Python 3.4+ and Pillow can be installed via pip install Pillow .
The following code provides a complete example. It defines a NineGridApp class that creates the main window, loads images, allows the user to select images, change the cell size, and merge the images into a single canvas.
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk, ImageOps
class NineGridApp:
def __init__(self, master):
self.master = master
master.title("9宫格图片拼接")
self.images_paths = [None] * 9
self.image_labels = [tk.Label(master) for _ in range(9)]
for i, label in enumerate(self.image_labels):
label.grid(row=i // 3, column=i % 3)
self.select_button = tk.Button(master, text="选择图片", command=self.select_images)
self.select_button.grid(row=3, column=0, columnspan=3)
self.merge_button = tk.Button(master, text="拼接图片", command=self.merge_images, state=tk.DISABLED)
self.merge_button.grid(row=4, column=0, columnspan=3)
self.cell_size = 200 # 默认每个单元格大小
self.layout_label = tk.Label(master, text=f"单元格尺寸: {self.cell_size}x{self.cell_size}")
self.layout_label.grid(row=5, column=0, columnspan=3)
self.resize_entry = tk.Entry(master)
self.resize_entry.insert(0, "200") # 默认输入
self.resize_entry.grid(row=6, column=1)
self.resize_button = tk.Button(master, text="更改尺寸", command=self.change_cell_size)
self.resize_button.grid(row=6, column=2)
def select_images(self):
for i in range(9):
if self.images_paths[i] is None:
filename = filedialog.askopenfilename()
if filename:
self.images_paths[i] = filename
img = Image.open(filename)
resized_img = self.resize_image_to_fit(img, (self.cell_size, self.cell_size))
photo = ImageTk.PhotoImage(resized_img)
self.image_labels[i].configure(image=photo)
self.image_labels[i].image = photo
else:
break
if all(self.images_paths):
self.merge_button.config(state=tk.NORMAL)
def resize_image_to_fit(self, img, max_size):
ratio = min(max_size[0] / img.width, max_size[1] / img.height)
new_size = (int(img.width * ratio), int(img.height * ratio))
return img.resize(new_size, Image.ANTIALIAS)
def change_cell_size(self):
try:
new_size = int(self.resize_entry.get())
if new_size > 0:
self.cell_size = new_size
self.layout_label.config(text=f"单元格尺寸: {self.cell_size}x{self.cell_size}")
for label, img_path in zip(self.image_labels, self.images_paths):
if img_path:
img = Image.open(img_path)
resized_img = self.resize_image_to_fit(img, (self.cell_size, self.cell_size))
photo = ImageTk.PhotoImage(resized_img)
label.configure(image=photo)
label.image = photo
except ValueError:
pass # 忽略非整数输入
def merge_images(self):
images = [Image.open(path) for path in self.images_paths]
size = (self.cell_size * 3, self.cell_size * 3)
canvas = Image.new('RGB', size)
for i, img in enumerate(images):
x = (i % 3) * self.cell_size
y = (i // 3) * self.cell_size
img_resized = self.resize_image_to_fit(img, (self.cell_size, self.cell_size))
canvas.paste(img_resized, (x, y))
canvas.show()
root = tk.Tk()
app = NineGridApp(root)
root.mainloop()The line from tkinter import filedialog imports the file‑dialog module, which provides convenient dialogs for opening, saving, and selecting directories, simplifying file‑selection tasks in GUI applications.
When the user clicks “选择图片”, they can select nine images one by one; each selected image is displayed in a label. Once all nine images are chosen, the “拼接图片” button becomes active, and clicking it merges the images into a 3×3 grid that is displayed.
Users can change the cell size via a text entry and a button; the application rescales all loaded images to the new size while preserving aspect ratio. Non‑numeric inputs are ignored to prevent crashes.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.