This is the module called 'proc_capturer.py' with OpenCV code, capturing frames from the webcam and putting them in the queue.
def cam_loop(the_q, event):
import cv2
width, height = 800, 600
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
while True:
_ , img = cap.read()
if img is not None:
img = cv2.flip(img, 1)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA)
the_q.put(img)
event.set()
And the Tkinter's module 'proc_tk_gui.py', starting the gui, receiving the frames from the queue and processing them in a hand-made 'mainloop':
def gui_mainloop(the_q, event):
import Tkinter as tk
from PIL import Image, ImageTk
class TkGui(tk.Tk):
def __init__(self):
tk.Tk.__init__(self, None)
self.parent = None
self.lmain = tk.Label(self)
self.lmain.pack()
def update_frame(self, img):
img = Image.fromarray(img)
imgtk = ImageTk.PhotoImage(image=img)
self.lmain.imgtk = imgtk
self.lmain.configure(image=imgtk)
self.update()
gui = TkGui()
while True:
event.wait()
img = the_q.get()
gui.update_frame(img)
Finally, your 'multiprocess-orchestrator' module:
import multiprocessing
from proc_tk_gui import gui_mainloop
from proc_capturer import cam_loop
if __name__ == '__main__':
logger = multiprocessing.log_to_stderr()
logger.setLevel(multiprocessing.SUBDEBUG)
q_frames_captured = multiprocessing.Queue(1)
e_frame_captured = multiprocessing.Event()
p_cap = multiprocessing.Process(target=cam_loop,args=(q_frames_captured, e_frame_captured))
p_gui = multiprocessing.Process(target=gui_mainloop,args=(q_frames_captured, e_frame_captured))
try:
p_cap.start()
p_gui.start()
p_cap.join()
p_gui.join()
except KeyboardInterrupt:
p_cap.terminate()
p_gui.terminate()
I like the idea of having a master module with the multiprocessing logic, and two independent parallel processes only linked with queues and event handlers.
This could develop into a more finite-state machine approach for my project, behave.
Thanks for this good inspiration:
http://www.briansimulator.org/docs/examples-multiprocessing_multiple_runs_with_gui.html
Edit:
It seems from comments in forums that doing your own update loop for tkinter is not really a good thing. The problem is that even though you can force Tkinter to "refresh the window", when it comes to handle events like mouse or button clicking without the mainloop(): you-are-fried. So, mainloop version of 'proc_tk_gui.py' using my dreaded "tkinter after method":
def gui_mainloop(the_q, event):
import Tkinter as tk
from PIL import Image, ImageTk
class TkGui(tk.Tk):
def __init__(self):
tk.Tk.__init__(self, None)
self.parent = None
self.lmain = tk.Label(self)
self.lmain.pack()
def update_frame(self, the_q, the_e):
img = the_q.get()
img = Image.fromarray(img)
imgtk = ImageTk.PhotoImage(image=img)
self.lmain.imgtk = imgtk # remember you need to anchor the image!!!
self.lmain.configure(image=imgtk)
self.lmain.after(10, self.update_frame, the_q, the_e)
gui = TkGui()
gui.update_frame(img, event)
gui.mainloop()
No comments:
Post a Comment