tkinter - Cache overflowing while showing an image stream using python 3 on a Raspberry Pi 2 Model B running Jessie and up to date -
i’m new python. i’m working on ‘proof of concept’ piece of code; using picamera on raspberry pi running jessie.
i’ve based code on tutorial code from: https://pythonprogramming.net/tkinter-adding-text-images/
once hit button show image, code starts picamera , starts capture_continuous, passes stream, applies crosshairs it.
it works well… after bit on 2 minutes, disk drive lights , starts slow drastically. once program break, fine. i’ve looked @ couple of logs, can’t life of me find out cache overflowing or why. i’ve tried bunch of different ways , tried leave in comments. suspected had having clear image in tkinter, doesn’t seem work , makes video flash unevenly.
any great! i’ve started explore using opencv instead. still installing that.
thanks!
the code:
# simple enough, import tkinter. tkinter import * import picamera import picamera.array import time import threading import io import numpy np pil import image, imagetk # here, creating our class, window, , inheriting frame # class. frame class tkinter module. (see lib/tkinter/__init__) class window(frame): # create array representing 1280x720 image of # cross through center of display. shape of # array must of form (height, width, color) # define settings upon initialization. here can specify def __init__(self, master=none): # parameters want send through frame class. frame.__init__(self, master) #reference master widget, tk window self.master = master #with that, want run init_window, doesn't yet exist self.init_window() #creation of init_window def init_window(self): # changing title of our master widget self.master.title("gui") # allowing widget take full space of root window self.pack(fill=both, expand=1) # creating menu instance menu = menu(self.master) self.master.config(menu=menu) # create file object) file = menu(menu) # adds command menu option, calling exit, , # command runs on event client_exit file.add_command(label="exit", command=self.client_exit) #added "file" our menu menu.add_cascade(label="file", menu=file) # create file object) edit = menu(menu) # adds command menu option, calling exit, , # command runs on event client_exit edit.add_command(label="show img", command=self.showimg) edit.add_command(label="show text", command=self.showtext) #added "file" our menu menu.add_cascade(label="edit", menu=edit) self.trim_running_bool = false def showimg(self): self.trim_running_bool = true trim_thrd_thread = threading.thread(target=self._cam_thread_def) trim_thrd_thread.start() self.update_idletasks() def _cam_thread_def(self): img_stream = io.bytesio() frame_count = 0 picamera.picamera() camera: camera.resolution = (400, 300) ## while true: ### tried way xxx in range(0,900): img_stream = io.bytesio() frame_count = frame_count + 1 print(frame_count," ", xxx) if self.trim_running_bool == false: print("break") break camera.capture(img_stream, 'jpeg', use_video_port=true) img_stream.seek(0) img_load = image.open(img_stream) xl_line in range(0,196,4): img_load.putpixel((xl_line, 149), (xl_line, 0, 0)) xll=xl_line+2 img_load.putpixel((xl_line, 150), (xl_line, xl_line, xl_line)) img_load.putpixel((xl_line, 151), (xl_line, 0, 0)) (xl_line) xr_line in range(208,400,4): clr = 400 - xr_line img_load.putpixel((xr_line, 149), (clr, 0, 0)) img_load.putpixel((xr_line, 150), (clr, clr, clr)) img_load.putpixel((xr_line, 151), (clr, 0, 0)) (xr_line) yt_line in range(0,146,4): clrt = int(yt_line * 1.7) img_load.putpixel((199, yt_line), (clrt, 0, 0)) img_load.putpixel((200, yt_line), (clrt, clrt, clrt)) img_load.putpixel((201, yt_line), (clrt, 0, 0)) (yt_line) yb_line in range(158,300,4): clrb = int((300 - yb_line) * 1.7) img_load.putpixel((199, yb_line), (clrb, 0, 0)) img_load.putpixel((200, yb_line), (clrb, clrb, clrb)) img_load.putpixel((201, yb_line), (clrb, 0, 0)) (yb_line) img_render = imagetk.photoimage(img_load) # labels can text or images img = label(self, image=img_render) img.image = img_render img.place(x=0, y=0) self.update_idletasks() img_stream.seek(0) img_stream.truncate(0) # tried these: ## img_stream.flush() ## print("flushed ", img_stream) ## print("2nd ",img_stream) ## del img_load ## ## ## rawcapture.truncate(0) ## ## rawcapture.seek(0) ## rawcapture.truncate(0) ## del render ## img.image = none ## foregnd_image = none (xxx) pass def showtext(self): text = label(self, text="hey there lookin!") text.pack() def client_exit(self): self.trim_running_bool = false exit() # root window created. here, window, # can later have windows within windows. root = tk() root.geometry("400x300") #creation of instance app = window(root) #mainloop root.mainloop()
each time through loop creating new image object , new label, other objects. memory leak, since never destroy old image or old label.
generally speaking, should create 1 label, use the_label.configure(image=the_image)
every time through loop. that, don't need create new labels or call place
on it.
even better, since label automatically updates when associated image changes, need change the bits in image object , label should update automatically.
the simplest solution move image creation function of objects creating local objects can automatically garbage collected when function returns.
the first step create single label , single image in main thread:
class window(frame): def __init__(self, master=none): ... self.image = photoimage(width=400, height=300) self.label = label(self, image=self.image) ...
next, create function copies new data image. unfortunately, tkinter's implementation of copy
method doesn't support full power of underlying image object. workaround described here: http://tkinter.unpythonic.net/wiki/photoimage#copy_a_subimage.
note: workaround example general purpose workaround uses more arguments need. in following example can omit many of arguments. documentation underlying tk photo object copy
method here: http://tcl.tk/man/tcl8.5/tkcmd/photo.htm#m17
the implementation (i'm guessing; don't have way test it):
def new_image(self): # code create new image goes here... ... img_render = imagetk.photoimage(img_load) # copy new image bits existing image object self.tk.call(self.image, 'copy', img_render)
finally, loop update image simpler:
while true: self.new_image() # presumeably there's sort of sleep here you're # not updating image faster camera can # capture it.
i don't know how fast new_image
can run. if can run in 200ms or less don't need threads. instead, can use after
run function periodically.
note: haven't worked tkinter photo images in long time, , have no way test this. use guide, rather definitive solution.
Comments
Post a Comment