Posts: 5
Threads: 1
Joined: Oct 2022
Hello,
I'm new to Tkinter and Python and trying to display an image in a label by selecting from a folder.
from asyncore import read
from email.mime import image
import tkinter as tk
from tkinter import filedialog
from turtle import width
import cv2 as cv
from PIL import Image
from PIL import ImageTk
from io import BytesIO
class Application:
def __init__(root, window, window_title, image_path):
root.window = window
root.window.title(window_title)
root.image_path = image_path
root.cv_img = cv.cvtColor(cv.imread(image_path), cv.COLOR_BGR2RGB)
root.height, root.width, no_channels = root.cv_img.shape
root.canvas = tk.Canvas(window, width=500, height=700, bg='azure3', relief='raised')
root.img_show = ImageTk.PhotoImage(image=Image.fromarray(root.cv_img))
root.headline_label = tk.Label(text="IMAGE PROCESSING", bg='azure3')
root.up_window_label = tk.Label(image=root.img_show)
root.down_window_label = tk.Label(bg='white')
root.load_button = tk.Button(text="LOAD IMAGE", command=root.load_image)
root.save_button = tk.Button(text="SAVE FILE", command=root.save_image)
root.close_button = tk.Button(text="CLOSE", command=root.window.destroy)
root.canvas.create_window(80, 20, window=root.headline_label)
root.canvas.create_window(root.width*0.7, root.height*0.7, window=root.up_window_label)
root.canvas.create_window(100, 600, window=root.load_button)
root.canvas.create_window(250, 600, window=root.save_button)
root.canvas.create_window(400, 600, window=root.close_button)
root.canvas.pack()
root.window.mainloop()
def load_image(root):
global img_show
root.import_file_path = filedialog.askopenfilename()
root.new_img = Image.open(root.import_file_path)
root.pic = ImageTk.PhotoImage(image=Image.fromarray(root.new_img))
root.down_window_label = tk.Label(image=root.pic)
root.canvas.create_window(root.width*0.7, root.height*2, window=root.down_window_label)
def save_image(root):
global img_show
root.export_file_path = filedialog.asksaveasfilename(defaultextension='.jpg')
root.img_show.save(root.export_file_path)
Application(tk.Tk(), "IMAGE_PROCESSING_APPLICATION", "OpenCV_Logo.jpeg") After loading the image by clicking the button, this error is given:
Error: TypeError: a bytes-like object is required, not 'JpegImageFile'
It may has to be solved with BytesIO, but I can't find something what helps me.
I'm really thankful for any suggestions!
Posts: 12,022
Threads: 484
Joined: Sep 2016
Please show complete unaltered error traceback, it contains valuable debugging information.
Posts: 5
Threads: 1
Joined: Oct 2022
(Oct-23-2022, 11:47 AM)Larz60+ Wrote: Please show complete unaltered error traceback, it contains valuable debugging information.
Sorry for the missing error traceback and thanks for your reply. The problem got solved now.
Posts: 165
Threads: 7
Joined: Nov 2018
Hey,
a couple comments on your code:
In python classes use the self instance, using self instead of root will allow you to eliminate the global variables. the use of self in classes
when you created the label in the init:
root.up_window_label = tk.Label(image=root.img_show) you recreate it in your function: def load_image(root):
it can be configured-
self.up_window_label.config(image= self.new_img) finally instead of creating canvas windows for each button and label you can use place for exact placement.
self.headline_label = tk.Label(self.canvas,text="IMAGE PROCESSING", bg='azure3')
self.headline_label.place(x=80,y=20)
Posts: 5
Threads: 1
Joined: Oct 2022
(Oct-23-2022, 06:59 PM)joe_momma Wrote: Hey,
a couple comments on your code:
In python classes use the self instance, using self instead of root will allow you to eliminate the global variables. the use of self in classes
when you created the label in the init:
root.up_window_label = tk.Label(image=root.img_show) you recreate it in your function: def load_image(root):
it can be configured-
self.up_window_label.config(image= self.new_img) finally instead of creating canvas windows for each button and label you can use place for exact placement.
self.headline_label = tk.Label(self.canvas,text="IMAGE PROCESSING", bg='azure3')
self.headline_label.place(x=80,y=20)
This is really helpful for me and makes everything a bit easier! Thank you!
Posts: 6,779
Threads: 20
Joined: Feb 2020
If you just want to display images, you can use tkinter.PhotoImage() to load the image.
import tkinter as tk
from tkinter import filedialog
class Application(tk.Tk):
def __init__(self, image_path=None):
super().__init__()
self.title("Image Processing")
self.geometry("400x300")
self.display = tk.Label(self)
self.display.pack(expand=True, fill=tk.BOTH)
# Make a frame to pack the buttons horizontally
buttons = tk.Frame(self)
buttons.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5)
# Make buttons to load image, save image and quit
button = tk.Button(buttons, text="LOAD IMAGE", command=self.load_image)
button.pack(side=tk.LEFT, expand=True, fill=tk.X)
button = tk.Button(buttons, text="SAVE FILE", command=self.save_image)
button.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)
button = tk.Button(buttons, text="CLOSE", command=self.destroy)
button.pack(side=tk.LEFT, expand=True, fill=tk.X)
def load_image(self):
"""Select an image to display"""
filename = filedialog.askopenfilename()
if filename:
self.image = tk.PhotoImage(file=filename)
self.display["image"] = self.image
def save_image(self):
"""Save image to a file"""
filename = filedialog.asksaveasfilename(defaultextension='.jpg')
if filename:
self.image.write(filename)
Application().mainloop() If you add image processing to your image processing application, you'll probably want to use PIL. You'll save the image as a PIL image for doing manipulations. Each time you modify the image you'll need to convert it to a tkImage and display.
Do not create a label each time you change the image. Use the same label over and over. Each time you change the image, change the image attribute for the label.
Not everything needs to be an attribute of your class. For example, I create three buttons, but my application class doesn't save handles to the buttons. If you don't need to keep it, don't keep it. I save the display label because that is used later in the program. I keep the image, because you need to do that to have the image display. I do not keep the buttons or the button form. I never refence those objects after they are created.
There are a lot of people who write tkinter programs as you did, with a class that implements the logic, but is not a tkinter object. I think that is a poor design. In the example above, I made Application a subclass of tk.Tk, the root window. This makes Applicaltion automatically know how to do everything that root knows how to do. It also cleans up all the "self.window.blah-blah-blah".
Do not use canvas unless you want to draw shapes or make a scrolled window. In tkinter you should make widgets that are children of a window and use a layout manager (pack or grid) to position the controls in the window. Place is hardly ever used, except for windows created using a designer tool. Properly used, pack and grid make windows that resize nicely. It is hard to do that using place.
Posts: 5
Threads: 1
Joined: Oct 2022
(Oct-24-2022, 03:20 AM)deanhystad Wrote: If you just want to display images, you can use tkinter.PhotoImage() to load the image.
import tkinter as tk
from tkinter import filedialog
class Application(tk.Tk):
def __init__(self, image_path=None):
super().__init__()
self.title("Image Processing")
self.geometry("400x300")
self.display = tk.Label(self)
self.display.pack(expand=True, fill=tk.BOTH)
# Make a frame to pack the buttons horizontally
buttons = tk.Frame(self)
buttons.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5)
# Make buttons to load image, save image and quit
button = tk.Button(buttons, text="LOAD IMAGE", command=self.load_image)
button.pack(side=tk.LEFT, expand=True, fill=tk.X)
button = tk.Button(buttons, text="SAVE FILE", command=self.save_image)
button.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)
button = tk.Button(buttons, text="CLOSE", command=self.destroy)
button.pack(side=tk.LEFT, expand=True, fill=tk.X)
def load_image(self):
"""Select an image to display"""
filename = filedialog.askopenfilename()
if filename:
self.image = tk.PhotoImage(file=filename)
self.display["image"] = self.image
def save_image(self):
"""Save image to a file"""
filename = filedialog.asksaveasfilename(defaultextension='.jpg')
if filename:
self.image.write(filename)
Application().mainloop() If you add image processing to your image processing application, you'll probably want to use PIL. You'll save the image as a PIL image for doing manipulations. Each time you modify the image you'll need to convert it to a tkImage and display.
Do not create a label each time you change the image. Use the same label over and over. Each time you change the image, change the image attribute for the label.
Not everything needs to be an attribute of your class. For example, I create three buttons, but my application class doesn't save handles to the buttons. If you don't need to keep it, don't keep it. I save the display label because that is used later in the program. I keep the image, because you need to do that to have the image display. I do not keep the buttons or the button form. I never refence those objects after they are created.
There are a lot of people who write tkinter programs as you did, with a class that implements the logic, but is not a tkinter object. I think that is a poor design. In the example above, I made Application a subclass of tk.Tk, the root window. This makes Applicaltion automatically know how to do everything that root knows how to do. It also cleans up all the "self.window.blah-blah-blah".
Do not use canvas unless you want to draw shapes or make a scrolled window. In tkinter you should make widgets that are children of a window and use a layout manager (pack or grid) to position the controls in the window. Place is hardly ever used, except for windows created using a designer tool. Properly used, pack and grid make windows that resize nicely. It is hard to do that using place.
Wow, thank you so much! This really helped me a lot and gave me good understanding about Tkinter.
I managed to integrate different image processing functions using OpenCv and they work out well together. My problem is now to fix the "save function", but it should be only a converting problem between the different image formats, which I will be have fixed soon.
Posts: 6,779
Threads: 20
Joined: Feb 2020
A program that reads and writes image files using opencv and displays them in tkinter.
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
import cv2
class Application(tk.Tk):
def __init__(self, image_path=None):
super().__init__()
self.title("Image Processing")
self.geometry("400x300")
self.image = None # Image used for image processing
self.tkimage = None # Image used to display in tkinter label
self.display = tk.Label(self)
self.display.pack(expand=True, fill=tk.BOTH)
# Make a frame to pack the buttons horizontally
buttons = tk.Frame(self)
buttons.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5)
# Make buttons to load image, save image and quit
button = tk.Button(buttons, text="LOAD IMAGE", command=self.load_image)
button.pack(side=tk.LEFT, expand=True, fill=tk.X)
button = tk.Button(buttons, text="SAVE FILE", command=self.save_image)
button.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)
button = tk.Button(buttons, text="CLOSE", command=self.destroy)
button.pack(side=tk.LEFT, expand=True, fill=tk.X)
def load_image(self):
"""Select an image to display"""
filename = filedialog.askopenfilename()
if filename:
# Read image and convert to RGB
self.image = cv2.imread(filename)
self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
# Convert image to tkinter image format and display
self.tkimage = ImageTk.PhotoImage(Image.fromarray(self.image))
self.display["image"] = self.tkimage
def save_image(self):
"""Save image to a file"""
filename = filedialog.asksaveasfilename(defaultextension='.jpg')
if filename:
# Convert image to BGR and write to file.
cv2.imwrite(filename, cv2.cvtColor(self.image, cv2.COLOR_RGB2BGR))
Application().mainloop()
Posts: 5
Threads: 1
Joined: Oct 2022
I already solved my problem. Thanks for your tips! You helped me a lot.
|