Een fotocollage maken met Python
Een collage is een prachtige manier om herinneringen te laten zien en sets met afbeeldingen weer te geven. Online collagemakers kunnen problemen hebben met de beveiliging en offline apps kunnen geld kosten en de functies missen die je nodig hebt.
Je kunt je zorgen wegnemen en absolute autoriteit behouden door je eigen fotocollagemaker te maken. Maar hoe maak je zo’n tool?
De Tkinter en PIL-module
Om een grafische gebruikersinterface voor een applicatie voor beeldcollages te maken, is het nodig om zowel de Tkinter-bibliotheek als de Python Imaging Library (PIL) te gebruiken. De eerste maakt het mogelijk om desktop-gebaseerde applicaties te maken door verschillende visuele elementen of “widgets” aan te bieden, die het proces van het ontwerpen van grafische gebruikersinterfaces (GUI’s) stroomlijnen.
De Pillow-bibliotheek, een afgeleide van de gerenommeerde Python Imaging Library (PIL), biedt een reeks functies voor het manipuleren van afbeeldingen die taken zoals het bewerken, genereren en opslaan van verschillende soorten visuele mediabestanden vergemakkelijken.
De installatie van Tkinter en Pillow kan worden gestart door een commandoregelinterface te openen en het volgende commando uit te voeren:
pip install tk pillow
GUI Setup and Image Manipulation
Je kunt de broncode voor dit project vinden in de speciale GitHub repository, die dient als digitale opslagplaats van alle bestanden en documentatie die erbij horen.
Om te beginnen is het noodzakelijk om de benodigde modules te importeren. Vervolgens maken we een nieuwe klasse genaamd ImageCollageApp
die zal dienen als het hoofdobject van de applicatie. De eerste stap bestaat uit het instellen van de titel en de afmetingen van het venster. Vervolgens genereren we een canvas met de methode tk.Canvas()
en configureren we het bovenliggende element, de breedte, hoogte en achtergrondkleur.
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()
Zorg ervoor dat de gebruiker toestemming heeft gegeven voor bestandsinvoer voordat je een object FileReader maakt om afbeeldingsbestanden van hun apparaat te lezen.
Initieer een datastructuur genaamd “image\_positions” voor het opslaan van de visuele positionering van media-elementen binnen de grafische gebruikersinterface. Implementeer drie aparte gebeurtenisbehandelingsroutines voor het selecteren, verplaatsen en loslaten van acties die geassocieerd zijn met genoemde media-elementen.
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)
Om de functionaliteit beschreven in het gegeven codefragment te implementeren, moeten we eerst een methode genaamd “on\_press” definiëren. Deze methode wordt geactiveerd wanneer de gebruiker met de muis klikt terwijl hij op het canvas tekent.Het doel van deze methode is om het canvasobject op te halen dat het dichtst bij het punt ligt waarop de gebruiker met de muis heeft geklikt en dit op te slaan in het “drag\_data” woordenboek. Daarnaast slaan we de X- en Y-coördinaten van de muisklik op, zodat we later kunnen berekenen hoe ver de gebruiker de muis heeft verplaatst tijdens het slepen.
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
Om de functionaliteit beschreven in het gegeven codefragment te implementeren, is het nodig om een methode genaamd “on\_drag” te definiëren die wordt geactiveerd wanneer de gebruiker de muis beweegt terwijl hij de linkerknop ingedrukt houdt. Deze methode berekent de horizontale en verticale afstanden die de cursor aflegt tijdens het slepen met behulp van de variabelen “dx” en “dy”. Op basis van deze waarden kan de positie van de afbeelding worden bijgewerkt door de attributen “x” en “y” van het object “image” in de widget “self.canvas” te wijzigen. Bovendien moeten de nieuwe coördinaten voor de afbeelding worden opgeslagen in het “drag\_data” woordenboek dat is geassocieerd met de huidige instantie van de klasse, waardoor ze in meerdere frames blijven bestaan.
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
Om alle achtergebleven verwijzingen naar de eerder gesleepte afbeelding op te ruimen en de positionering van alle visuele elementen op het canvas opnieuw te berekenen als reactie op een “release”-gebeurtenis, kun je een “on\_release”-methode implementeren die deze problemen aanpakt. Specifiek moet deze methode de verwijzing naar de afbeelding wissen die werd begeleid door de cursor van de gebruiker tijdens het slepen, terwijl ook de functie “update\_image_positions” wordt aangeroepen om de lay-out van alle weergegeven afbeeldingen te herzien na het stoppen van de interactie met de gebruiker.
def on_release(self, event):
self.drag_data["item"] = None
self.drag_data["x"] = 0
self.drag_data["y"] = 0
self.update_image_positions()
Op een elegante manier zullen we een functie “update_image_positions” definiëren, die de inhoud van de “image_positions” array wist en iteratief door elk onderdeel van het canvas gaat. Tijdens dit proces identificeren we voor elk onderdeel de positiegegevens en voegen deze toe aan de genoemde matrix.
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))
Zeker! Hier is een voorbeeldimplementatie in Python met Tkinter en de Pillow-bibliotheek:pythonimport tkinter as tkfrom tkinter import filedialogimport osfrom PIL import Imagedef add_images():#creëer een nieuw vensterwindow = tk.Toplevel(root)#vraag gebruiker hoeveel afbeeldingen hij wil uploadennum_images = tk.Entry(venster)num_images.pack()num_entries = tk.Label(window, text=“Enter number of images:")num_entries.pack()# waarde uit entry fieldnum_values = num_images.get()if num_values.isdigit() and int(
Gebruik de functie resize_image
om de huidige afbeelding in het geheugen te herschalen, waardoor een nieuwe Tkinter-compatibele PhotoImage
.Voeg vervolgens deze bijgewerkte referentie toe aan de lijst image_refs
voordat het canvas wordt bijgewerkt met de methode 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()
Hier is een voorbeeldimplementatie van de methode resize_image
in Python:pythondef resize_image(self, image):# Verkrijg de huidige afmetingen van de afbeeldingimg_width, img_height = image.size# Bereken de hoogte-breedteverhouding van de afbeeldingaspect_ratio = img_height / img_width# Controleer of de hoogte-breedteverhouding groter is dan 1 (d.w.z.., portretoriëntatie)if aspect_ratio > 1:# Stel de nieuwe breedte in op de helft van de collagebreedtenew_width = self.collage_width / 2# Bereken de overeenkomstige nieuwe hoogte met behoud van de hoogte-breedteverhoudingew_height = int((
Als de hoogte-breedteverhouding van de collage kleiner is dan één, halveren we zowel de hoogte als de breedte door de juiste afmetingen te berekenen op basis van de oorspronkelijke grootte van de collage. We kunnen dan de functie resize
van Pillow gebruiken om een vergrote versie van de collage te genereren met deze aangepaste afmetingen terwijl de verhoudingen behouden blijven.
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))
Definieer een methode met de naam “update\_canvas” met de volgende stappen:1. Wis alle items op het canvas door de respectieve klikbare koppelingen die bij elk item horen te verwijderen uit de vorige opstelling van afbeeldingen.2. Geef de gebruiker de mogelijkheid om het gewenste aantal rijen en kolommen in te voeren via een dialoogvenster voor bestanden. De opgegeven afmetingen moeten overeenkomen met de eerder in dit document gegeven specificaties.3. Bepaal het totale aantal benodigde kolommen op basis van het aantal door de gebruiker ingevoerde rijen. In ons voorbeeld gaan we uit van zes kolommen per rij. Bereken de breedte en hoogte van de collage dienovereenkomstig. Dit betekent dat als de gebruiker vier rijen selecteert, de breedte tweemaal de breedte van één kolom (6) is plus een spatie ertussen. Dientengevolge
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
Iterate door elk item in de image_refs
lijst en creëer een visuele representatie ervan op het canvas door gebruik te maken van de opgegeven offset. Positioneer de linkerbovenhoek van de afbeelding op de aangewezen coördinaten door het ankerpunt in te stellen op de noordwestelijke hoek. Voeg de overeenkomstige coördinaten toe aan de lijst image_positions
voor verdere referentie.
Om de volgende afbeelding effectief te rangschikken binnen het raster, is het essentieel om de variabele x_offset
bij te werken door de helft van de collage
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
De collage maken en opslaan
Om een aantrekkelijke visuele weergave van verschillende digitale activa te genereren, ontwikkelen we een functie die bekend staat als create_collage
. Dit algoritme controleert eerst of er media-items zijn opgenomen in de compositie of niet. Als er geen zijn, wordt er een waarschuwingsbericht weergegeven. Vervolgens bepaalt deze techniek de afmetingen van de elektronische montage door de breedte en de hoogte te bepalen. Vervolgens wordt een nieuw leeg Pillow Image-object geconstrueerd met een maagdelijk witte achtergrond. Dan zal de functie de catalogus van bestanden doorlopen en ze precies op het doek plaatsen op hun vooraf bepaalde coördinaten met behulp van de krachtige PIL-bibliotheek van Python voor efficiënte manipulatie van afbeeldingsgegevens.
Gebruik de vooraf ingestelde afbeeldingsviewer om de digitale collage tentoon te stellen door deze eerst op te slaan en gebruik te maken van de ingebouwde mogelijkheden voor een optimale visualisatie.
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()
Gebruik de mogelijkheden van de Tkinter-bibliotheek door een nieuwe instantie van de ImageCollage-toepassing te maken, die is uitgerust met de benodigde attributen en methoden om visuele collages te genereren op basis van gebruikersinvoer. Zodra deze is ingesteld, start je de uitvoering van de Tkinter-gebeurtenislus met behulp van de mainloop()-methode. Dit commando zorgt ervoor dat de Python-interpreter continu alle gebeurtenissen in het venster controleert en verwerkt, waardoor de toestand van het venster behouden blijft totdat het handmatig wordt gesloten door de eindgebruiker.
if __name__ == "__main__":
root = tk.Tk()
app = ImageCollageApp(root)
root.mainloop()
Testen van verschillende functies van de Image Collage Maker
Bij het uitvoeren van de applicatie wordt een interface met twee opties weergegeven: “Afbeelding toevoegen” en “Collage maken”. Nadat er op de optie “Afbeelding toevoegen” is geklikt, verschijnt er een pop-up waarin de gebruiker wordt gevraagd hoeveel afbeeldingen hij in zijn collage wil opnemen. Nadat ‘5’ is ingevoerd als het gewenste aantal afbeeldingen en ze zijn geselecteerd uit de gegeven lijst, verschijnt er nog een dialoogvenster waarin informatie wordt gevraagd over zowel het aantal horizontale rijen als verticale kolommen die moeten worden gebruikt bij het maken van de collage.
Na het invoegen van twee rijen en drie kolommen visuele elementen binnen de aangewezen grensruimte, rangschikt de grafische gebruikersinterface ze systematisch als een matrixconfiguratie, waardoor een samenhangende weergave ontstaat die de positionering en volgorde van elke individuele component benadrukt.
In het voorbeeld kun je de afbeeldingen manipuleren door ze naar wens te verplaatsen. Als je op de knop “Collage maken” klikt, slaat de software de resulterende afbeelding op.
Bij het bekijken van de visuele weergave van de gegenereerde collage is het duidelijk dat de softwaretoepassing het beoogde doel heeft bereikt met betrekking tot het samenstellen van een samenhangende en visueel aantrekkelijke verzameling afbeeldingen.
De functionaliteit van de Image Collage Maker verbeteren
In plaats van een op tabellen gebaseerde structuur te gebruiken, is het mogelijk om gebruikers een selectie voorgedefinieerde sjablonen aan te bieden waaruit ze kunnen kiezen. Neem daarnaast functionaliteiten op die het mogelijk maken om de achtergrondkleur te veranderen, geschreven inhoud toe te voegen, beeldverbeteringen toe te passen en decoratieve elementen van online bronnen te integreren.
Maak tijdens het integreren van deze functionaliteiten een eenvoudige methode voor het wijzigen van de samengestelde afbeelding mogelijk door opties te bieden om bewerkingen ongedaan te maken of opnieuw te tekenen. Geef gebruikers bovendien de mogelijkheid om het bijsnijden, het formaat en de oriëntatie van individuele afbeeldingen aan te passen aan hun voorkeuren. Neem bovendien een functie op waarmee de uiteindelijke uitvoer kan worden opgeslagen in een bestandsindeling naar keuze.