I made an application to display the image of the pc camera in tkinter every 1 mm.
Therefore, I would like to add a function to execute another loop processing without interrupting the video display.
The point is, I want to use two root.after in parallel.
Since the video processing is looped every 1 millisecond in root.after in the main thread, I tried to write it using threading to execute another loop processing (xfunc) in another thread, but I executed xfunc During that time, the video processing of the main thread stops. I would like to know if the usage of threading is correct.Corresponding source code
What I tried
import tkinter as tk import cv2 from PIL import Image from PIL import ImageTk import sys import threading import time wi = 600 he = 400 root = tk.Tk () root.geometry ("600x400") canvas = tk.Canvas (root, width = wi, height = he) canvas.place (x = 0, y = 0) def capStart (): #Camera capture process global c, w, h, img c = cv2.VideoCapture (0) c.set (cv2.CAP_PROP_FRAME_WIDTH, wi) c.set (cv2.CAP_PROP_FRAME_HEIGHT, he) w, h = c.get (cv2.CAP_PROP_FRAME_WIDTH), c.get (cv2.CAP_PROP_FRAME_HEIGHT) def update (): #Display captured video on tkinter (I don't want to stop processing) global img ret, frame = c.read () if ret: img = ImageTk.PhotoImage (Image.fromarray (cv2.cvtColor (frame, cv2.COLOR_BGR2RGB))) canvas.create_image (wi * 0.5, he * 0.5, image = img) else: else: print ("Fail") root.after (1, update) def xfunc (): # Time-consuming looping. I want to perform this process in parallel without stopping updata (). for i in range (10000000): con = i print (con) root.after (1000, th1) # Root.after (1000, xfunc) # This was also useless def subthreadRun (): thread_1 = threading.Thread (target = xfunc) thread_1.setDaemon (True) thread_1.start () capStart () update () subthreadRun () root.mainloop ()
I couldn't even use concurrent.futures.Supplementary information (FW/tool version, etc.)
Answer # 1
Since the video processing is looped every 1 millisecond in root.after
If you are updating the video, estimate the FPS and set an appropriate value.
Since 1ms->1000fps, around 60fps (16ms) should usually be sufficient.
While running xfunc, the video processing of the main thread stops.
The cause is mainly
Update interval is too fast → Loop every 1ms
Because the main loop is doing time-consuming processing
As a countermeasure, in addition to loosening the update interval
Preprocessing is done on the sub thread side as much as possible. In particular
Processing performed on the Tk side (main thread): ImageTk.PhotoImage
Processing performed on the sub thread side: Image.fromarray (cv2.cvtColor (frame, cv2.COLOR_BGR2RGB)))
There are several ways to notify tkinter (main thread) from a sub thread
How to use the queue 1:
Read from queue using root.after on the main thread side
Event notification with event_generate from the subthread side. Read from queue.
Notify with root.after_idle from the sub thread side ・ Execute in the main thread
Time-consuming loop processing. I want to perform this process in parallel without stopping updata ().
It is better to make a part of the process of update itself a subthread.
I didn't know what th1 in root.after (1000, th1) was,
Functions that are specified and executed in root.after are executed in the main thread.
So time-consuming processes will block the mainloop,
It connects without GUI response.
* This is not the answer code.
A sample logging and an indication of using root.after in a thread.
#!/usr/bin/env python3.8 import tkinter as tk from threading import Thread import logging # POINT: You can see that the second and subsequent xfunc are executed by MainThread. def xfunc (root): logging.info ("xfunc") root.after (1000, xfunc, root) def xfunc2 (root): # If running in another thread, you can use time.sleep to wait 1 second import time while True: logging.info ("xfunc2") time.sleep (1) def main (): root = tk.Tk () button = tk.Button (root, text = "Quit", command = root.quit) button.pack () thread = Thread (target = xfunc, args = (root,), daemon = True) thread.start () root.mainloop () if __name__ == "__main__": logging.basicConfig ( level = logging.DEBUG, format = "[% (threadName) -10s]% (message) s") main ()
Logging makes it easier to see in which thread the function is running.
It stops because the tkinter event loop stops.
All functions executed by root.after, functions registered by bind, etc.
It runs in root.mainloop. Since the GUI is drawn and event processing is done in the mainloop,
These functions must finish processing immediately and return control to the mainloop.
Take a log and see if the main thread is doing any time-consuming work.
Just recently, there was a code I wrote to check the operation with cv2.VideoCapture/tkinter, so
I can't explain it, but I hope it will be helpful.
I think it will be helpful when separating the update () function into the sub thread side (cv2) and the main thread (tkinter).
If you get an error at the end of the program, depending on the situation,
The order of releasing resources must be explicit.
Answer # 2
I wonder if this is the only answer after organizing the situation a little.
Apart from the performance issues of the update () function, only the main points.
def xfunc (): # Time-consuming looping. I want to perform this process in parallel without stopping updata (). for i in range (10000000): con = i print (con) root.after (1000, th1) # Root.after (1000, xfunc) # This was also useless
Problem: Functions executed in root.after are executed by tkinter in the main thread.
It is only executed the first time in another thread.
Solution: You can use time.sleep to wait 1 second for another thread
def xfunc (): import time while True: for i in range (10000000): con = i print (con) time.sleep (1)
- parallel processing using python multiprocessingpool and multiprocessingqueue does not work well
- python - parallel processing with asyncio
- python about iterative processing with specified numbers
- python - i don't know how to process blocking processes in parallel
- i want to speed up the processing of [python] for
- python - [tkinter] multiple selectable combobox
- python 3x - python3 tkinter no response when closing window
- python 3x - python3 tkinter treeview data update
- python - pltshow does not run unless you close the tkinter window
- python 3x - tkinter i want to write code concisely
- i want to output the entry result of tkinter with python
- python 3x - button execution action in tkinter when executing code
- python - while syntax processing
- python 3x - change font size for python3 tkinter entry
- python iterative processing num is not defend
- python - reopening the file dialog in tkinter results in an error
- [python] [tkinter] i want to change the acquisition contents of the second and subsequent menu lists by selecting the previous p
- python - avoid processing when duplicated
- i want to add processing to the python library
- Python Tkinter not seeing 'TimePL' instance of Label widget
- python : How can a scrollbar be attached to a label in tkinter
- python : Why root.attributes('-topmost', False) fires every other time?
- python : How to write functions for buttons to work?
- Working buttons in TKinter in Python in OOP
- python : How to create a large text input field?
- python : How to keep the scale of buttons, text, etc in tkinter?
- python : how to bind keyboard input in Tkinter
- python : how to find out the size of a Tkinter window?
- python : How to make txt to html text converter