Tkinter/Python Canvas doesn't display image from OpenCV - python

I have class MainWindow for main window:
import custom_windows as cw
import tkinter as tk
class MainWindow(tk.Toplevel):
def __init__(self, master):
self.master = master
master.title("ORV application")
master.geometry("500x350")
# Set container for buttons
button_container = tk.Frame()
button_container.pack(side=tk.BOTTOM)
# Set get image button
get_image_button = tk.Button(button_container, text="Get image", command=self.click_get_image)
get_image_button.pack(padx=20, pady=10, side=tk.LEFT)
def click_get_image(self):
# Create window with image
image_window = tk.Toplevel(self.master)
cw.CustomWindow(image_window, "images/tour-de-france.jpg")
root = tk.Tk()
main_window = MainWindow(root)
root.mainloop()
From main class I called new window from class CustomWindow:
import tkinter as tk
import cv2 as cv
from PIL import Image as pilImage, ImageTk as pilImageTk
class CustomWindow(tk.Toplevel):
def __init__(self, master, image_path):
self.master = master
master.title("Image")
master.resizable(False, False)
# Open and prepare image
self.image = cv.cvtColor(cv.imread(image_path), cv.COLOR_BGR2RGB)
self.render = pilImageTk.PhotoImage(image=pilImage.fromarray(self.image))
self.height, self.width, self.no_channels = self.image.shape
# Create canvas to display image
canvas = tk.Canvas(master, width=self.width, height=self.height)
canvas.create_image(0, 0, image=self.render, anchor=tk.NW)
canvas.pack()
Image doesn't display in Canvas. I use self to save values from garbage collector.

Related

Python tkinker - scrolling problem with scrollbars

I would like to do scrolling in my photo editing program. But something is not working for me. The code was in theory based on one of the stackoverflow entries and I can't identify the problem. I have tried to remake it in various ways. _inbound_to_mousewheel prints nicely and so does _un_to_mousewheel. The one responsible directly for scrolling doesn't even print.
Is it possible to do a zoom in such a project, and if not, does it need to be rebuilt?
Main window file:
import sys
import tkinter as tk
from tkinter import filedialog, Frame
from PIL import ImageTk, Image
from gui.menu_bar import MenuBar
from gui.workspace import Workspace
def close_all_windows():
sys.exit()
class MainForm(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("myPhotoEditor by Sebastian KÄ…kolewski")
self.geometry("1000x850")
self.protocol("WM_DELETE_WINDOW", close_all_windows)
self.menu_bar = MenuBar(self)
self.config(menu=self.menu_bar)
# region Workspace
self.workspace_frame = Frame(self)
self.workspace_frame.pack(expand=True, fill="both", side="left")
self.workspace = Workspace(self.workspace_frame)
self.workspace.pack(fill="both", expand=True)
file_url = filedialog.askopenfilename()
img = Image.open(file_url)
self.workspace.image = ImageTk.PhotoImage(img)
self.workspace.create_image(0, 0, image=self.workspace.image, anchor='nw')
self.workspace_frame.bind('<Enter>', self._bound_to_mousewheel)
self.workspace_frame.bind('<Leave>', self._unbound_to_mousewheel)
# endregion
def _bound_to_mousewheel(self, event):
print("_bound_to_mousewheel")
self.workspace_frame.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbound_to_mousewheel(self, event):
print("_unbound_to_mousewheel")
self.workspace_frame.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event):
print("_on_mousewheel")
self.workspace_frame.yview_scroll(int(-1 * (event.delta / 120)), "units")
Workspace file:
from tkinter import Canvas, Scrollbar
class Workspace(Canvas):
def __init__(self, master=None):
Canvas.__init__(self, master)
self.master = master
workspace_hbar = Scrollbar(self.master, orient="horizontal")
workspace_hbar.pack(side="bottom", fill="x")
workspace_hbar.config(command=self.xview)
workspace_vbar = Scrollbar(self.master, orient="vertical")
workspace_vbar.pack(side="right", fill="y")
workspace_vbar.config(command=self.yview)
self.config(xscrollcommand=workspace_hbar.set, yscrollcommand=workspace_vbar.set)

Can I add multiple images as canvas items and rotate them simultaneously?

I am trying to rotate images using canvas items. I was successful in doing it with one image. But if I want to perform rotations on multiple canvas items how can I do that? Can someone help? Thanks in advance.
Here is my code:
import tkinter as tk
from PIL import ImageTk
from PIL import Image
import time
class SimpleApp(object):
def __init__(self, master, filename, **kwargs):
self.master = master
self.filename = filename
self.canvas = tk.Canvas(master, width=500, height=500)
self.canvas.pack()
self.update = self.draw().__next__
master.after(100, self.update)
def draw(self):
image = Image.open(self.filename)
angle = 0
while (angle<90):
tkimage = ImageTk.PhotoImage(image.rotate(angle))
canvas_obj = self.canvas.create_image(
250, 250, image=tkimage)
self.master.after_idle(self.update)
yield
angle += 5
time.sleep(0.1)
else
yield
root = tk.Tk()
app = SimpleApp(root, 'cat.jpg')
root.mainloop()

How store event.width in a variable in python?

I have a script that displays the dimensions of the tkinter window and I was wondering how I can set those values into a variable?
Here is the code:
import tkinter as tk
from tkinter import PhotoImage
root = tk.Tk()
canvas = tk.Canvas(root)
canvas.pack(fill="both", expand=True)
def canvas_changed(event):
global WW
WW = event.width
global HH
HH = event.height
img = PhotoImage(file="competeButton.png")
foo = canvas.create_image(image=img, width=WW, height=HH)
foo.pack(fill="both", expand=True)
root.mainloop()
Many thanks in advance for any help.
There's nothing special you have to do. Data is data, whether it comes from a widget or a database or anything else.
Here's an example that saves the value to a global variable:
def canvas_changed(event):
global canvas_width
canvas_width = event.width
Create a class with all your image and the resizing of it. Then issue an if statement to call those values every time it changes. Here is an example of what you might do:
import tkinter as tk
from PIL import Image, ImageTk
class MainFrame(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.canvas = tk.Canvas(self)
self.canvas.pack(fill=tk.BOTH, expand=1)
self.canvas.bind("<Configure>", self.resize)
self.img = ImageTk.PhotoImage(Image.open(r"competeButton.png"))
self.canvas_img = self.canvas.create_image(0, 0, anchor="nw", image=self.img)
def resize(self, event):
img = Image.open(r"competeButton.png").resize((event.width, event.height), Image.ANTIALIAS)
self.img = ImageTk.PhotoImage(img)
self.canvas.itemconfig(self.canvas_img, image=self.img)
if __name__ == "__main__":
main_frame = MainFrame()
main_frame.mainloop()

Can't get image to display in tkinter

I am trying to get an image to display in a tkinter canvas.
I know the Canvas works with shapes and text, but image isn't working.
I am using PIL ImageTK.PhotoImage, however it also doesn't work creating a Tkinter.PhotoImage using a '.ppm' image.
The 'png' image is stored in the same directory as the python file.
import tkinter as tk
from PIL import Image, ImageTk
class Window:
def __init__(self):
self.window = tk.Tk()
self.window.title("COMP")
self.window.geometry("1200x600")
topframe = tk.Frame(self.window, highlightbackground='black', highlightthickness=1)
topframe.pack(side='top')
self.noteview = NoteView(topframe, self.songString)
class NoteView:
def __init__(self, frame):
self.canvas = tk.Canvas(frame, width=60, height=200)
self.canvas.pack()
self.canvas.create_text(15, 190, text='hi')
im = Image.open('png.png')
self.image = ImageTk.PhotoImage(im)
self.canvas.create_image(20, 20, anchor='nw', image=self.image)
w = Window()
TypeError: 'PhotoImage' object is not callable
The proble is that the tkinter somehow bings the image to the window, not in your case. You should use self.canvas.image = ImageTk.PhotoImage(im) and self.canvas.create_image(20, 20, anchor='nw', image=self.canvas.image). Hope that's helpful!

add a button directly to a resizable picture(i.e ontop) without using canvas

import tkinter as tk
import PIL
from PIL import ImageTk
from PIL import Image, ImageTk
from tkinter import Frame
button_flag = True
def click():
"""
respond to the button click
"""
global button_flag
# toggle button colors as a test
if button_flag:
self.button1.config(bg="white")
self.button_flag = False
else:
sef.button1.config(bg="green")
self.button_flag = True
class Example(Frame):
def __init__(self, master, *pargs):
Frame.__init__(self, master, *pargs)
self.image = Image.open('slide 1.png')
self.img_copy= self.image.copy()
self.photo = tk.PhotoImage(file="video.png")
self.photo1 = self.photo.subsample(2, 2)
self.background_image = ImageTk.PhotoImage(self.image)
self.background = tk.Label(self, image=self.background_image, text="heyyy")
self.background.pack(fill="both", expand=True)
self.background.bind('<Configure>', self._resize_image)
self.button1 = tk.Button(root, compound=tk.TOP, width=155, height=55, image=self.photo1,
text="optional text", bg='green', command=click)
self.button1.pack()
def _resize_image(self,event):
new_width = event.width
new_height = event.height
self.image = self.img_copy.resize((new_width, new_height))
self.background_image = ImageTk.PhotoImage(self.image)
self.background.configure(image = self.background_image)
root = tk.Tk()
root.title('webmanager')
root.state('zoomed')
e = Example(root)
e.pack(fill="both", expand=True)
root.mainloop()
I also would like to know if this can be aplicable to slide shows (ie adding a button to each picture). well for now the only thing ive accomplished is making the button look like a header and then the image follows but fairly the both are resizable. but i really need the image to fill the screen and then the button on it. THANKS

Categories