Tkinter and cv2: "not responding" popup when imshow launched from tk app

aapost aapost at idontexist.club
Tue Mar 14 16:22:55 EDT 2023


On 3/14/23 06:54, John O'Hagan wrote:
> Hi list
> 
> I'm trying to use cv2 to display images created as numpy arrays, from
> within a tkinter app (which does other things with the arrays before
> they are displayed as images). The arrays are colour-coded
> visualisations of genomes and can be over a billion elements in size,
> and I've found the PIL methods to display images in tkinter are too
> slow and memory-heavy.
> 
> Here is minimal code that demonstrates the problem in the subject line:
> 
> import cv2
> from tkinter import *
> 
> images=['a.jpg', 'b.jpg', 'c.jpg'] #change to image paths
> 
> cv2.namedWindow('W', cv2.WND_PROP_FULLSCREEN)
> cv2.setWindowProperty('W', cv2.WND_PROP_FULLSCREEN,
> cv2.WINDOW_FULLSCREEN)
> counter=[0]
> def show():
>     cv2.imshow('W', cv2.imread(images[counter[0] % len(images)]))
>     cv2.waitKey(1)
>     counter[0] += 1
> 
> root=Tk()
> root.wm_attributes("-topmost", 1)
> Button(root, text=' Show ', command=show).pack()
> mainloop()
> 
> It works up to a point - I can cycle through the images by clicking the
> button - but if I mouse-click on the displayed image (e.g. to use the
> zooming and panning features of cv2), nothing happens, and a few
> seconds later the image greys out and a popup appears saying "'Unknown'
> is not responding" and giving the option of waiting or forcing close
> (but sometimes these options are greyed out too). Clicking "wait", if
> available, closes the popup but it comes back a few seconds later. If I
> then click on the tkinter window titlebar, the popup changes to "'Tk'
> is not responding". Clicking on the button still works and after a few
> clicks the popup closes.
> 
> This happens under both x11 and wayland, but under wayland, I  also get
> this error:
> 
> "QSocketNotifier: Can only be used with threads started with QThread
> qt.qpa.wayland: Wayland does not support QWindow::requestActivate()"
> 
> and only every second button press displays a new image ,with only
> every second image displayed.
> 
> I think this particular popup is a Gnome thing, but AIUI most DEs have
> something similar to detect stuck apps. But the app is not stuck.
> 
> I suspect this is some kind of interaction between the call to
> cv2.waitKey (which is necessary but I've never understood why!) and the
> tkinter event loop, but it's beyond my knowledge.
> 
> Any suggestions about causes or workarounds?
> 
> Thanks
> 
> --
> 
> John
> 
> 


I don't get any of the zoom/panning behavior with waitKey(1). But a 
couple notes from the web:


https://docs.opencv.org/2.4/modules/highgui/doc/user_interface.html

Note

This function should be followed by waitKey function which displays the 
image for specified milliseconds. Otherwise, it won’t display the image. 
For example, waitKey(0) will display the window infinitely until any 
keypress (it is suitable for image display). waitKey(25) will display a 
frame for 25 ms, after which display will be automatically closed. (If 
you put it in a loop to read videos, it will display the video 
frame-by-frame)

https://pythonexamples.org/python-opencv-imshow/

cv2.waitKey(0) is important for holding the execution of the python 
program at this statement, so that the image window stays visible. If 
you do not provide this statement, cv2.imshow() executes in fraction of 
a second and the program closes all the windows it opened, which makes 
it almost impossible to see the image on the window.




if I change waitKey to 0, I get the ability to zoom/pan, but it places 
the tk window in a blocked state because it is waiting on cv2 to return. 
If I hit the ESC key, it releases the wait and gives control back to the 
tk window, allowing me to press show again to continue to the next image.

I can try to change waitKey to a high ms like 10000000 and have zoom/pan 
for that amount of time before it gives control back to tk (not a 
sensical approach).

The fact that you can still see the image after tk takes back control is 
I believe just a matter of design, some examples show 
cv2.destroyAllWindows() after waitKey(0) to clean that up, but of course 
if you are reusing the same window, that destroys the target.

You can resolve that if you move
cv2.namedWindow('W', cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty('W', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

to inside the show, and destroy it after the wait, and make waitKey 0, 
this allows creation/cleanup of that window per image

Hitting ESC when done zooming/panning on each image to get back to tk.


More information about the Python-list mailing list