Cách tạo ảnh ghép bằng Python

Ảnh ghép là cách tuyệt vời để lưu giữ kỷ niệm theo một nhóm ảnh liên quan. Tuy nhiên, những app ghép ảnh online thường có tiềm ẩn rủi ro bảo mật, còn ứng dụng offline thì lại tốn tiền và thiếu tính năng bạn cần.

Tạo app ghép ảnh

Bằng cách tự tay xây dựng công cụ ghép ảnh, bạn không cần phải quan tâm tới những điều đó. Sau đây là cách tạo app ghép ảnh bằng Python.

Mô đun Tkinter và PIL

Để xây dựng ứng dụng ghép ảnh bạn cần tới mô đun Tkinter và PIL. Tkinter cho phép bạn tạo ứng dụng desktop. Nó cung cấp một loạt widget khiến việc phát triển GUI dễ dàng hơn.

Thư viện Pillow - một nhánh của Python Imaging Library (PIL) - cung cấp các tính năng xử lý ảnh, giúp chỉnh sửa, tạo, chuyển đổi định dạng file và lưu ảnh.

Để cài đặt Tkinter và Pillow, mở terminal và chạy:

pip install tk pillow

Thiết lập GUI và chỉnh sửa ảnh

Bắt đầu bằng cách nhập các mô đun được yêu cầu. Tạo class, ImageCollageApp và đặt tên cùng kích thước của cửa sổ. Xác định một canvas bằng tk.Canvas(), rồi đặt phần tử cha, chiều rộng, cao và màu background.

import tkinter as tk
from tkinter import filedialog, simpledialog, messagebox
from PIL import Image, ImageTk

class ImageCollageApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Image Collage Maker")
        self.images = []
        self.image_refs = []
        self.collage_size = (600, 500)

        self.collage_canvas = tk.Canvas(
            self.root,
            width=self.collage_size[0],
            height=self.collage_size[1],
            bg="white",
        )

        self.collage_canvas.pack()

Tạo hai nút bấm: Add ImageCreate Collage. Xác định phần tử cha, nội dung hiển thị, lệnh để chạy và kiểu font. Sắp xếp các nút bấm bằng cách thêm padding phù hợp. Khởi tạo drag_data để lưu thông tin về thao tác kéo.

Khởi tạo image_positions để lưu vị trí của ảnh trên canvas. Xác định 3 trình xử lý sự kiện để phản hồi với lựa chọn, kéo và thả hình.

        self.btn_add_image = tk.Button(
            self.root,
            text="Add Image",
            command=self.add_images,
            font=("Arial", 12, "bold"),
        )

        self.btn_add_image.pack(pady=10)

        self.btn_create_collage = tk.Button(
            self.root,
            text="Create Collage",
            command=self.create_collage,
            font=("Arial", 12, "bold"),
        )

        self.btn_create_collage.pack(pady=5)
        self.drag_data = {"x": 0, "y": 0, "item": None}
        self.image_positions = []
        self.collage_canvas.bind("<ButtonPress-1>", self.on_press)
        self.collage_canvas.bind("<B1-Motion>", self.on_drag)
        self.collage_canvas.bind("<ButtonRelease-1>", self.on_release)

Xác định một phương thức, on_press. Truy xuất mục canvas gần nhất từ vị trí người dùng click chuột và lưu nó dưới khóa item của từ điển drag_data. Lưu trữ tọa độ xy của click chuột. Bạn sẽ dùng nó để tính khoảng cách người dùng di chuyển chuột trong khi kéo.

    def on_press(self, event):
        self.drag_data["item"] = self.collage_canvas.find_closest(event.x, event.y)[0]
        self.drag_data["x"] = event.x
        self.drag_data["y"] = event.y

Xác định một phương thức, on_drag. Tính khoảng cách theo chiều ngang và dọc mà người dùng đã di chuột trong khi kéo và update vị trí hình ảnh phù hợp. Lưu tọa độ ảnh đã update bằng các khóa x y của từ điển drag_data.

    def on_drag(self, event):
        delta_x = event.x - self.drag_data["x"]
        delta_y = event.y - self.drag_data["y"]
        self.collage_canvas.move(self.drag_data["item"], delta_x, delta_y)
        self.drag_data["x"] = event.x
        self.drag_data["y"] = event.y

Xác định một phương thức, on_release. Xóa tham chiếu tới ảnh mà người dùng đang kéo cùng với tọa độ của nó. Gọi update_image_positions để cập nhật vị trí của mọi hình trên canvas sau khi người dùng kéo và thả nó.

    def on_release(self, event):
        self.drag_data["item"] = None
        self.drag_data["x"] = 0
        self.drag_data["y"] = 0
        self.update_image_positions()

Xác định một phương thức, update_image_positions. Xóa danh sách image_positions và lặp nó trên toàn bộ các mục canvas. Đối với mỗi mục, tìm tọa độ và thêm chúng vào danh sách.

    def update_image_positions(self):
        self.image_positions.clear()

        for item in self.collage_canvas.find_all():
            x, y = self.collage_canvas.coords(item)
            self.image_positions.append((x, y))

Xác định một phương thức, add_images. Tạo hộp thoại nhắc người dùng nhập số ảnh muốn ghép. Nếu người dùng đã cung cấp một số hợp lệ, mở một hộp thoại file, chỉ cho phép người dùng chọn file ảnh. Sau khi người dùng đã chọn một hoặc nhiều ảnh hơn, mở từng ảnh bằng phương thức Image.open() của Pillow.

Gọi resize_image và tạo PhotoImage tương thích Tkinter. Thêm nó vào danh sách image_refs và gọi update_canvas.

    def add_images(self):
        num_images = simpledialog.askinteger(
            "Number of Images", "Enter the number of images:"
        )

        if num_images is not None:
            file_paths = filedialog.askopenfilenames(
                filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif")]
            )

            if file_paths:
                for i in range(min(num_images, len(file_paths))):
                    file_path = file_paths[i]
                    image = Image.open(file_path)
                    resized_image = self.resize_image(image)
                    self.images.append(resized_image)
                    self.image_refs.append(ImageTk.PhotoImage(resized_image))

                self.update_canvas()

Xác định phương thức, resize_image. Lấy chiều rộng và cao của ảnh và tính tỷ lệ khía cạnh của nó. Nếu nhiều hơn một, đặt chiều rộng mới bằng một nửa chiều rộng của ảnh ghép. Tính chiều cao mới tương ứng trong khi vẫn duy trì tỷ lệ khung hình.

Nếu tỷ lệ cạnh nhỏ hơn 1, đặt chiều cao mới bằng nửa của ảnh ghép. Tương tự, tính chiều rộng tương ứng. Dùng phương thức resize của Pillow để trả về ảnh đã được chỉnh lại kích thước bằng các tham số đã được tính.

    def resize_image(self, image):
        img_width, img_height = image.size
        aspect_ratio = img_width / img_height

        if aspect_ratio > 1:
            new_width = self.collage_size[0] // 2
            new_height = int(new_width / aspect_ratio)
        else:
            new_height = self.collage_size[1] // 2
            new_width = int(new_height * aspect_ratio)

        return image.resize((new_width, new_height))

Xác định một phương thức, update_canvas. Xóa toàn bộ mục và hỏi người dùng số hàng và cột mong muốn qua hộp thoại file. Đặt chiều rộng và cao bằng 1/2 kích thước ảnh ghép được chỉ định. Xóa danh sách các vị trí ảnh. Đặt offset xy sang 0, nhờ đó, bạn có thể liên tục theo dõi các offset vị trí để sắp xếp ảnh theo hàng và cột.

    def update_canvas(self):
        self.collage_canvas.delete("all")
        rows = simpledialog.askinteger("Number of Rows", "Enter the number of rows:")

        cols = simpledialog.askinteger(
            "Number of Columns", "Enter the number of columns:"
        )

        collage_width = self.collage_size[0] * cols // 2
        collage_height = self.collage_size[1] * rows // 2
        self.collage_canvas.config(width=collage_width, height=collage_height)
        self.image_positions.clear()
        x_offset, y_offset = 0, 0

Lặp trên danh sách image_refs và tạo ảnh trên canvas bằng offset cụ thể. Đặt anchor sang Northwest để bạn định vị góc trên bên trái ở tọa độ cụ thể. Nối các tọa độ vào danh sách image_positions.

Update x_offset để thêm một nửa chiều rộng của ảnh ghép, để chuẩn bị đặt ảnh tiếp theo. Nếu số ảnh được đặt trong hàng hiện tại là bội số của số cột cụ thể, đặt x_offset sang 0. Điều này chỉ điểm bắt đầu của một hàng mới. Thêm một nửa chiều cao của ảnh ghép để đặt tọa độ y cho hàng tiếp theo.

        for i, image_ref in enumerate(self.image_refs):
            self.collage_canvas.create_image(
                x_offset, y_offset, anchor=tk.NW, image=image_ref
            )

            self.image_positions.append((x_offset, y_offset))
            x_offset += self.collage_size[0] // 2

            if (i + 1) % cols == 0:
                x_offset = 0
                y_offset += self.collage_size[1] // 2

Tạo ảnh ghép và lưu nó

Xác định một phương thức, create_collage. Nếu chưa có ảnh trên ảnh ghép, hiện một cảnh báo. Thu thập chiều rộng và cao của ảnh ghép. Tạo một Image Pillow bằng background màu trắng. Lặp qua danh sách images và dán từng ảnh vào background ở vị trí được xác định.

Lưu ảnh ghép và hiện nó bằng trình xem ảnh mặc định.

    def create_collage(self):
        if len(self.images) == 0:
            messagebox.showwarning("Warning", "Please add images first!")
            return

        collage_width = self.collage_canvas.winfo_width()
        collage_height = self.collage_canvas.winfo_height()
        background = Image.new("RGB", (collage_width, collage_height), "white")

        for idx, image in enumerate(self.images):
            x_offset, y_offset = self.image_positions[idx]
            x_offset, y_offset = int(x_offset), int(y_offset)

            paste_box = (
                x_offset,
                y_offset,
                x_offset + image.width,
                y_offset + image.height,
            )

            background.paste(image, paste_box)

        background.save("collage_with_white_background.jpg")
        background.show()

Tạo một phiên bản của Tkinter và class ImageCollageApp. Hàm mainloop() cho Python biết cần chạy lặp sự kiện Tkinter và lắng nghe các sự kiện cho tới khi bạn đóng cửa sổ này.

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageCollageApp(root)
    root.mainloop()

Kiểm thử các tính năng khác nhau của app ghép ảnh

Khi chạy chương trình này, một cửa sổ sẽ hiện với hai nút bấm, Add Image Create Collage. Khi click nút Add Image, một hộp thoại sẽ hiện hỏi số ảnh cần ghép. Khi nhập số ảnh là 5 và chọn chúng, hộp thoại khác sẽ hiện ra. Nó hỏi số hàng và theo sau là số cột.

Thêm ảnh

Khi nhập hai hàng và 3 cột, cửa sổ này sắp xếp ảnh theo cấu trúc lưới.

App ghép ảnh bằng Python

Cửa sổ xem trước cho tính năng kéo ảnh như ý muốn. Khi click nút Create Collage, chương trình này sẽ lưu ảnh.

Khi xem ảnh này, bạn có thể xác nhận chương trình đã ghép ảnh thành công.

Ghép ảnh bằng Python

Trên đây là cách tạo app ghép ảnh bằng Python. Hi vọng bài viết hữu ích với các bạn.

Thứ Sáu, 08/09/2023 16:37
51 👨 612
0 Bình luận
Sắp xếp theo
    ❖ Python