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

John O'Hagan research at johnohagan.com
Tue Mar 14 22:00:44 EDT 2023


On Tue, 2023-03-14 at 08:07 -0400, Thomas Passin wrote:
> On 3/14/2023 6:54 AM, 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.

[...]

> I don't know anything about the specifics here, but with billions of 
> elements you will not be able to show more than a small fraction on
> the 
> screen.  

Hi Thomas

Thanks for your reply.

In the real app I use interpolating methods to fit the whole image on
the screen. In cv2:

cv2.imshow('W', cv2.resize(array, (width, height))

It's very quick, fractions of a second even for a billion+ sized array.
The PIL/Tk equivalent:

im = ImageTk.PhotoImage(Image.fromarray(array).resize((width, height)))
canvas.create_image(width/2, height/2, image=im)

did the same thing but was very, very slow for such large arrays (15
minutes or more per image, with memory heavily swapped out).

Having said all that, the specific problem I'm having isn't related to
the size of the arrays. The code I posted above triggers the problem
even with small images.

> So I think that a progressive disclosure approach would pay 
> off.  Sample the arrays down to a more workable size before creating
> the 
> screen images.  If you want to zoom in, resample them and recreate
> new 
> images that only cover the zoomed in region in more detail.
> 
> It would also be useful to cache the generated images so they can be 
> re-displayed without needing to be regenerated each time.

This is exactly the approach I took in the first draft (except the
caching idea)! I wasn't using interpolating methods and was limited to
a minimum of one pixel per array element, and therefore limited in how
much of the array could be displayed. Even this got pretty slow in
tkinter if fully zoomed out, although the caching would have helped
with that. But the project brief requires the whole genome to be
visible by default.

Thanks



More information about the Python-list mailing list