[Tkinter] createing a tkinter photoimage from array in python3 - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: [Tkinter] createing a tkinter photoimage from array in python3 (/thread-528.html) |
createing a tkinter photoimage from array in python3 - pootle - Oct-17-2016 I started with this post and have tried to convert it to python3 - where the tkinter special in pilow has been 'replaced' by 'equivalent' functionality in tkinter. After much searching and testing I have eventually resorted to writing a file and reading it into the tkinter photoimage object, which is really naff, but is the only way I have found to make it work. Surely there is away to pass the data direct to photoimage? Interestingly my write / read a file approach is still faster than the original version in python 2.7! Here is my python 3 version of the code: import tkinter from PIL import Image import numpy import time import io #python2 version (original) -> 120fps #full physical file io and new image each cycle -> 130fps #reuse PIL Image instead of create new each time -> 160fps class mainWindow(): times=1 timestart=time.clock() data=numpy.array(numpy.random.random((400,500))*100,dtype=int) theimage = Image.frombytes('L', (data.shape[1],data.shape[0]), data.astype('b').tostring()) def __init__(self): self.root = tkinter.Tk() self.frame = tkinter.Frame(self.root, width=500, height=400) self.frame.pack() self.canvas = tkinter.Canvas(self.frame, width=500,height=400) self.canvas.place(x=-2,y=-2) self.root.after(0,self.start) # INCREASE THE 0 TO SLOW IT DOWN self.root.mainloop() def start(self): global data global theimage self.theimage.frombytes(self.data.astype('b').tobytes()) self.theimage.save('work.pgm') self.photo = tkinter.PhotoImage(file='work.pgm') self.canvas.create_image(0,0,image=self.photo,anchor=tkinter.NW) self.root.update() self.times+=1 if self.times%33==0: print("%.02f FPS"%(self.times/(time.clock()-self.timestart))) self.root.after(10,self.start) self.data=numpy.roll(self.data,-1,1) if __name__ == '__main__': x=mainWindow() RE: createing a tkinter photoimage from array in python3 - Larz60+ - Oct-17-2016 Hello, This code is for python 3. It creates an image in a Label widget. It should work in Canvas with little modification You will need to change the path to your image from tkinter import * from PIL import Image, ImageTk class TryImage: def __init__(self, parent, image_path=None): self.image_path = image_path self.parent = parent def image_to_label(self): self.bar = Frame(self.parent, relief=RIDGE, borderwidth=5) self.bar.pack(fill=X, side=TOP) self.bar.columnconfigure(0, weight=1) self.bar.rowconfigure(0, weight=1) self.icon = ImageTk.PhotoImage(Image.open(self.image_path)) self.icon_size = Label(self.bar) self.icon_size.image = self.icon self.icon_size.configure(image=self.icon) self.icon_size.pack(side=LEFT) if __name__ == '__main__': root = Tk() ti = TryImage(root, 'images/showroom.png') ti.image_to_label() root.mainloop()Larz60+ RE: createing a tkinter photoimage from array in python3 - pootle - Oct-18-2016 Well some more digging and I prised the answer out of a combination of several different places. Larz60's approach is the way I was already doing it - loading a file, but I eventually found out that the data needs to be in ppm format which is pretty simple to generate. This approach goes twice as fast as writing / reading a file and isn't really stressing the PC either: import tkinter import numpy import time #python2 version (original) -> 120fps #full physical file io and new image each cycle -> 130fps #reuse PIL Image instead of create new each time -> 160fps #and... direct image into tkinter using ppm byte array -> 240 fps class mainWindow(): times=1 timestart=time.clock() data=numpy.array(numpy.random.random((400,500))*900,dtype=numpy.uint16) def __init__(self): self.root = tkinter.Tk() self.frame = tkinter.Frame(self.root, width=500, height=400) self.frame.pack() self.canvas = tkinter.Canvas(self.frame, width=500,height=400) self.canvas.place(x=-2,y=-2) xdata = b'P5 500 400 255 ' + self.data.tobytes() self.photo = tkinter.PhotoImage(width=500, height=400, data=xdata, format='PPM') self.imid = self.canvas.create_image(0,0,image=self.photo,anchor=tkinter.NW) self.root.after(1,self.start) # INCREASE THE 0 TO SLOW IT DOWN self.root.mainloop() def start(self): global data xdata = b'P5 500 400 255 ' + numpy.clip(self.data,0,255).tobytes() self.photo = tkinter.PhotoImage(width=500, height=400, data=xdata, format='PPM') if True: self.canvas.itemconfig(self.imid, image = self.photo) else: self.canvas.delete(self.imid) self.imid = self.canvas.create_image(0,0,image=self.photo,anchor=tkinter.NW) self.times+=1 if self.times%33==0: print("%.02f FPS"%(self.times/(time.clock()-self.timestart))) self.root.update() self.root.after(0,self.start) self.data=numpy.roll(self.data,-1,1) if __name__ == '__main__': x=mainWindow() |