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

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()

Related

How Can I use this code to directly change my image more than one time by using after command

I really not sure where i do blunders but I try it many time but not get result, actually I wanted to change my image in tkinter window after sometime without creating a button, I find some code from here and do changes on it but I am not able to change image after once, the image is change only once, after second image is static and not change in visible, please help to find a solution.
val = 2000 #milisecond
val1 = 1000 #milisecond
val2 = 5000 #milisecond
from tkinter import *
from PIL import Image, ImageTk
class myGUI(object):
def __init__(self):
self.root = Tk()
self.canvas = Canvas(width=800, height=800, bg='white')
self.canvas.pack()
filename="image1.png"
image = Image.open(filename)
self.photo = ImageTk.PhotoImage(image)
self.img = self.canvas.create_image(250, 250, image=self.photo)
self.root.after(val, self.change_photo)
self.root.mainloop()
def change_photo(self):
filename = "image2.png"
image = Image.open(filename)
self.photo = ImageTk.PhotoImage(image)
self.canvas.itemconfig(self.img, image=self.photo)
# From Here I will not achieve my goal
def __init__(self):
self.root.after(val1, self.change_photo1)
def change_photo1(self):
filename = "image1.png"
image = Image.open(filename)
self.photo = ImageTk.PhotoImage(image)
self.canvas.itemconfig(self.img, image=self.photo)
if __name__ == "__main__":
gui = myGUI()
You need to call .after() inside change_photo() function. As you want to cycle the images, suggest to use itertools.cycle() as below:
from tkinter import *
from PIL import ImageTk
from itertools import cycle
class myGUI(object):
def __init__(self):
self.root = Tk()
self.canvas = Canvas(width=800, height=800, bg='white')
self.canvas.pack()
self.val = 1000
filenames = ("image1.png", "image2.png")
self.images = cycle(filenames)
self.photo = ImageTk.PhotoImage(file=next(self.images))
self.img = self.canvas.create_image(250, 250, image=self.photo)
self.root.after(self.val, self.change_photo)
self.root.mainloop()
def change_photo(self):
self.photo = ImageTk.PhotoImage(file=next(self.images))
self.canvas.itemconfig(self.img, image=self.photo)
self.root.after(self.val, self.change_photo)
if __name__ == "__main__":
gui = myGUI()
Example without using cycle:
from tkinter import *
from PIL import ImageTk
class myGUI(object):
def __init__(self):
self.root = Tk()
self.canvas = Canvas(width=800, height=800, bg='orange')
self.canvas.pack()
self.val = 1000
self.images = ("image1.png", "image2.png")
self.img = self.canvas.create_image(250, 250)
self.change_photo()
self.root.mainloop()
def change_photo(self, index=0):
if index < len(self.images):
self.photo = ImageTk.PhotoImage(file=self.images[index])
self.canvas.itemconfig(self.img, image=self.photo)
self.root.after(self.val, self.change_photo, index+1)
else:
print("No more image")
if __name__ == "__main__":
gui = myGUI()

Tkinter/Python Canvas doesn't display image from OpenCV

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.

What is the function used to update frame image automatically in python?

I asked this question before and the previous one linked to another question but it didn't solve the problem.
I have a number of images, which are updated frequently in a file.
The names of images are on the same pattern (e.g: img1.jpg , img2.jpg ...)
I am programming a GUI on python tkinter to start from the first image and automatically update after 30 second.
after many tries, I have no idea how to achieve that because mainloop()function freezes the GUI and the problem is that I need them in one GUI.
Here is the code I used to open and resize images:
from PIL import Image, ImageTk
x=1
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.pack(fill=BOTH, expand=1)
load = Image.open("./images/img%s.jpg"%x)
load=load.resize((1350,800))
render = ImageTk.PhotoImage(load)
img = Label(self, image=render)
img.image = render
img.place(x=0, y=0)
root = Tk()
app = Window(root)
root.wm_title("Tkinter window")
root.geometry("1350x800")
root.mainloop()
I tried to use label.after(3000,function) but no results came up so I deleted it from the code.
Is there any way to solve this problem?
Thanks in advance
Too big for the comments, But this is a working version of your code:
from tkinter import *
from PIL import Image, ImageTk
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.pack(fill=BOTH, expand=1)
self.x = 1 #assigning x to 1 to start with img1
self.load = Image.open(f"./images/img{self.x}.jpg").resize((1350,800),Image.ANTIALIAS) #loading first img
self.render = ImageTk.PhotoImage(self.load) #instantiating first img
self.img = Label(self, image=self.render) #labelizing it
self.img.image = self.render #keeping reference
self.img.pack() #packing it because place(x=0,y=0) will lead to overwriting of image
self.master.after(3000,self.update) #calling the function continoursly
def update(self):
self.x+=1 #increasing the x by 1 over each call to function
if self.x < 9:
self.load = Image.open(f"./images/img{self.x}.jpg").resize((1350,800),Image.ANTIALIAS)
self.render = ImageTk.PhotoImage(self.load)
self.img.config(image=self.render) #changing the image of label
self.master.after(3000,self.update)
root = Tk()
app = Window(root)
root.wm_title("Tkinter window")
root.geometry("1350x800")
root.mainloop()
Hope this helped, do let me know if any errors or doubts.
Cheers
This code solved my problem:
#from tkinter import *
from PIL import Image, ImageTk
import os
from tkinter import Frame,Label,BOTH,Tk
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.pack(fill=BOTH, expand=1)
self.x = 1
self.load = Image.open(f"./images/img{self.x}.jpg").resize((1350,800),Image.ANTIALIAS)
self.render = ImageTk.PhotoImage(self.load)
self.img = Label(self, image=self.render)
self.img.image = self.render
self.img.pack()
self.master.after(3000,self.update)
def update(self):
if self.x<len(os.listdir("./images/")):
self.x+=1
self.load = Image.open(f"./images/img{self.x}.jpg").resize((1350,800),Image.ANTIALIAS)
self.render = ImageTk.PhotoImage(self.load)
self.img.config(image=self.render)
self.master.after(3000,self.update)
else:
self.x=1
self.master.after(1,self.update)
root = Tk()
app = Window(root)
root.wm_title("Tkinter window")
root.geometry("1350x800")
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()

MatPlotLib Plot w/ Python Tkinter

I am trying to display a MatPlotLib Plot of a BMP Image in the same window or canvas as the image. The code can already display the image, and I already have the data graph, I am just having trouble embedding the graph into the GUI. I tried referencing http://matplotlib.org/examples/user_interfaces/embedding_in_tk2.html but I was a little stumped trying to impliment it into this code.
Ideally, I would have the plot display right underneath the image.
Here is my code:
import tkinter as tk
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk
from scipy import misc
import os
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.pos = []
self.master.title("BMP Image GUI")
self.pack(fill=BOTH, expand=1)
self.counter = 0
menu = Menu(self.master)
self.master.config(menu=menu)
# File Bar
file = Menu(menu)
file.add_command(label="Open Image 1", command=self.openImage1)
file.add_command(label="Exit", command=self.client_exit)
menu.add_cascade(label="File", menu=file)
self.canvas = tk.Canvas(self)
self.canvas.pack(fill=tk.BOTH, expand=True)
self.image = None
self.image2 = None
def client_exit(self):
exit()
def openImage1(self):
filename = filedialog.askopenfilename(initialdir=os.getcwd(), title="Select BMP File",
filetypes=[("BMP Files", "*.bmp")])
if not filename:
return
# Image 1 Data Graph
image = misc.imread(filename, flatten=False, mode="RGB")
sumArray1 = []
for i in range(0, image.shape[0]-1):
sumArray1.append(np.sum(image[i]))
np.asarray(sumArray1)
fig = plt.figure(figsize=(10,3.75), dpi=96)
plt.plot(sumArray1)
# Image 1
load = Image.open(filename)
load1 = load.resize((960, 720), Image.ANTIALIAS)
w, h = load1.size
width, height = root.winfo_screenmmwidth(), root.winfo_screenheight()
if self.image is None:
self.render = ImageTk.PhotoImage(load1)
self.image = self.canvas.create_image((w / 2, h / 2), image=self.render)
root.geometry("%dx%d" % (w, height))
root = tk.Tk()
root.geometry("%dx%d" % (300, 300))
root.title("BMP Image GUI")
app = Window(root)
app.pack(fill=tk.BOTH, expand=1)
root.mainloop()
I don't know if this is efficient, but created a second canvas as canvas2 and it seems to do that job. Before, I was working on the same canvas as the BMP image and it wasn't showing up. Maybe there is a way to do it only using one canvas.
if self.image is None:
self.render = ImageTk.PhotoImage(load1)
self.image = self.canvas.create_image((w / 2, h / 2), image=self.render)
root.geometry("%dx%d" % (w, height))
self.canvas2 = FigureCanvasTkAgg(fig, master=root)
self.canvas2.show()
self.canvas2.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=0)
self.canvas2._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=0)

Categories