35

I have the following code:

total_frames = 50
cv2.cv.NamedWindow("Dragonfly Simulation")
cv2.cv.StartWindowThread()
for i in range(total_frames):
    # do stuff
    img_name = # something
    img = cv2.cv.LoadImage(img_name)
    cv2.cv.ShowImage("Dragonfly Simulation", img)
    cv2.cv.WaitKey(2)
cv2.cv.DestroyWindow("Dragonfly Simulation")
cv2.cv.WaitKey(1)
# rest of code

So what does it do:

  1. Opens a window
  2. In a loop, shows an image on the window
  3. Once finished, closes the window
  4. Runs the rest of the code

However in this case I have the total_frame given before. I don't want that.

Instead, I want a code that does the following:

  1. Opens a window
  2. In a loop, shows an image on the window
  3. Waits for the user to close that window
  4. When the user closes that window, exit loop, goes on with the rest of the code.

However, I cannot find a function in OpenCV that can detect when user closes a window. Can anyone suggest a workaround please?

threxx
  • 1,213
  • 1
  • 31
  • 59
dessskris
  • 555
  • 1
  • 4
  • 13
  • Maybe there are some exceptions you can catch? For example try acces window, if it fails with NoWindowExistsException/NullPointerException then go with your code. – Marek Jan 25 '16 at 22:19
  • @jotto umm, sorry I'm new to OpenCV, how do I check for the exception? with my current code, if I close the window, the code stops. also, from the manual of ShowImage: "If the window was not created before this function, it is assumed creating a window with CV_WINDOW_AUTOSIZE" – dessskris Jan 25 '16 at 22:23
  • I'm not familiar with OpenCV at all. I have just thought that instance will remain after closing the Window. Maybe this is what you are looking for? To store some reference of cv globally so you can access it no matter if Window is closed? I am just speculating. – Marek Jan 25 '16 at 22:25
  • @jotto umm I'm modelling a neuron simulation, so I want to run the simulation for as long as the user wants (instead of a specified time duration or number of frames). Therefore wanting to detect when the user closes such window. I guess alternatively I could detect keyboard press? not entirely sure how to do that though... – dessskris Jan 25 '16 at 22:29
  • Can you close window during loop? – Marek Jan 25 '16 at 22:37
  • http://stackoverflow.com/questions/9321389/how-to-check-if-an-opencv-window-is-closed maybe this will help you. – Marek Jan 25 '16 at 22:39
  • @jotto I tried closing window during loop, then the whole code stops running and ctrl+c won't kill the process :( also saw the linked question, but can't seem to run GetWindowHandle, can't find its documentation either... – dessskris Jan 25 '16 at 22:42
  • I don't think GetWindowHandle is exposed to python side. You will have to code in C++ https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=112804&p=772836 – otterb Jan 27 '16 at 11:12

9 Answers9

50

I was just looking for a way to detect when the window has been closed using the X button of the window in addition to waiting for a key press, but I couldn't find an answer anywhere (IsWindowVisible and cvGetWindowHandle are not available in the Python cv2 module).

So I played around and this is how it works:

while cv2.getWindowProperty('window-name', 0) >= 0:
    keyCode = cv2.waitKey(50)
    # ...

cv2.getWindowProperty() returns -1 as soon as the window is closed.


For explanation, see the documentation for the enumeration of cv::WindowPropertyFlags: getting the flag with index 0 is the fullscreen property, but actually it doesn't matter which flag to use, they all become -1 as soon as the window is closed.


Note: This might only work for certain GUI backends. Notably, it will not work with the GTK backend used in Debian/Ubuntu packages. To use the Qt backend instead, you have to install opencv-python via pip.

Christian Rauch
  • 86
  • 3
  • 10
Simon Hänisch
  • 4,740
  • 2
  • 30
  • 42
  • 1
    Yes, your solution works but unfortunately writes into stderr "OpenCV Error: Null pointer (NULL window) in cvGetModeWindow_GTK, file /build/opencv-SviWsf/opencv-2.4.9.1+dfsg/modules/highgui/src/window_gtk.cpp, line 555" – Vladyslav Savchenko Oct 06 '16 at 20:40
  • @VladyslavSavchenko in Python or in C++? I don't get any error in Python, and also I used OpenCV version 3.1... you can try wrapping it in a try/catch and exit in the catch statement. – Simon Hänisch Oct 07 '16 at 10:34
  • Yes, in Python, try..catch can't help, because the opencv writes into stderr instead of throwing any python exception (but don't care about it, I rewrote it already on wx : ) ). Thank you for your help! – Vladyslav Savchenko Oct 10 '16 at 08:19
  • 3
    Which operating system are you using? I can't get this to work on Ubuntu; `getWindowProperty` always returns `0.0` even though the window has been closed. – HelloGoodbye Aug 14 '19 at 17:40
  • 3
    This doesn't work for me, since the >= catches the window not being visible status. I used this: ```python while cv2.getWindowProperty(name, cv2.WND_PROP_VISIBLE) > 0: keyCode = cv2.waitKey(50) else: print('break') ``` – DeusXMachina Oct 23 '19 at 15:37
  • You are a hero. I was about to go mad about restarting the ipython console everytime i forgot to hit a key inside the window and clicked the X button... – Matthias Güntert Jan 03 '20 at 21:42
  • @VladyslavSavchenko if it is just writing to stderr but otherwise works is it really a big problem? – eric May 11 '20 at 15:09
  • @eric yesterday: it is not a problem, it is a fact. – Vladyslav Savchenko May 13 '20 at 11:47
  • This only worked for me with the Qt GUI backend, which is used when installing via pip (`pip3 install opencv-python`). It does not work with the GTK backend that is used by default for the Debian/Ubuntu packages (`sudo apt install python3-opencv`). – Christian Rauch Jul 28 '21 at 09:42
  • If messages to stderr annoy you see this [answer](https://stackoverflow.com/questions/5081657/how-do-i-prevent-a-c-shared-library-to-print-on-stdout-in-python/17954769#17954769) – bt3 May 24 '23 at 18:09
33

As of version 2.2 there is a simple solution (this is modified from the loop in hist.py):

    cv2.imshow('image',im)
    while True:
        k = cv2.waitKey(100) # change the value from the original 0 (wait forever) to something appropriate
...
        elif k == 27:
            print('ESC')
            cv2.destroyAllWindows()
            break        
        if cv2.getWindowProperty('image',cv2.WND_PROP_VISIBLE) < 1:        
            break        
    cv2.destroyAllWindows()
David Kohen
  • 431
  • 4
  • 4
6

I tested on C++ using the getWindowProperty('image', WND_PROP_VISIBLE), but it does not work. So I used the WND_PROP_AUTOSIZE and it works.

I did like this:

cv::namedWindow("myTitle", WINDOW_AUTOSIZE);

while(1)
{
    cv::imshow("myTitle", myImage);


    if (cv::getWindowProperty("myTitle", WND_PROP_AUTOSIZE) == -1)
        break;
}
Derzu
  • 7,011
  • 3
  • 57
  • 60
  • 1
    Works in python as well: `cv2.imshow("image", image) if cv2.getWindowProperty('image',1) < 0: break` Where `cv2.getWindowProperty(, 1)` refers to the autosize flag. [https://docs.opencv.org/3.1.0/d7/dfc/group__highgui.html#gaeedf4023e777f896ba6b9ffb156f57b8] – Eli Oct 15 '18 at 09:36
4
        if cv2.getWindowProperty('windowname',1) == -1 :
            break
        cv2.imshow('windowname', image)
  • 6
    Your answer is only code, try adding references to documentations or explain what it does. While sometimes all you need to answer the core question is some code the more detail you can provide the better. – LW001 Oct 02 '17 at 09:10
3

I used the following code t check if a key is pressed or the window is closed at the same time.

    while cv2.getWindowProperty(camera.get_name(), cv2.WND_PROP_VISIBLE) > 0:
        if cv2.waitKey(100) > 0:
            break

    cv2.destroyAllWindows()
Jop Knoppers
  • 676
  • 1
  • 10
  • 22
2
import cv2
import numpy as np

# total_frames = 50
cv2.namedWindow("Dragonfly Simulation")
cv2.startWindowThread()
# for i in range(total_frames):
while True:
    # do stuff
    img = np.random.randint(0,255,(200,300)).astype(np.uint8)
    cv2.imshow("Dragonfly Simulation", img)
    key = cv2.waitKey(200)
    print key
    if key in [ord('a'), 1048673]:
        print 'a pressed!'
    elif key in [27, 1048603]: # ESC key to abort, close window
        cv2.destroyAllWindows()
        break

# do the rest of processing after break 
print 'results:'

Sure, you can check user inputs using waitKey and here is a small example based on your code. I changed old cv interface to cv2. I think cv is obsolete.

(Edit) I moved cv2.destroyAllWindows() to inside the while loop to make it clear that the window closes when the user pressed ESC key (which you can assign a key of your choice). I do not think opencv has a proper event handler to catch the window close event like in other GUI toolkit (wxPython etc). So you will need to define how your users should close the window and watch out for that.

otterb
  • 2,660
  • 2
  • 29
  • 48
0

I made a simple function based on this post. It works in opencv 4.5.2

def wait_with_check_closing(win_name):
    """ 
        https://stackoverflow.com/questions/35003476/"
        "opencv-python-how-to-detect-if-a-window-is-closed/37881722
    """
    while True:
        keyCode = cv2.waitKey(50)
        if keyCode != -1:
            break
        win_prop = cv2.getWindowProperty(win_name, cv2.WND_PROP_VISIBLE)
        if win_prop <= 0:
            break


It can be used instead of cv2.waitKey(0) like following example.

# Usage
cv2.imshow(title, img_resized)
# cv2.waitKey(0)
wait_with_check_closing(title)
cv2.destroyAllWindows()
Jaeyoon Jeong
  • 569
  • 4
  • 8
0

https://www.programcreek.com/python/example/110676/cv2.WND_PROP_VISIBLE

For my scenario, it had to be the following. I had to call k = cv2.waitKey(1) & 0xFF before checking status of the window for it to work

def show_webcam(mirror=False):
    cam = cv2.VideoCapture(0)
    # cv2.startWindowThread()
    window_name="A_star webcam"
    while True:
        ret_val, img = cam.read()
        if mirror: 
            img = cv2.flip(img, 1)
        cv2.imshow(window_name, img)
        k = cv2.waitKey(1) & 0xFF 
        if not (cv2.getWindowProperty(window_name,cv2.WND_PROP_VISIBLE)):
            break
        
        if cv2.waitKey(1) == 27: 
            break  # esc to quit
     
    cv2.destroyAllWindows()

The libraries installed are

autopep8==1.6.0
numpy==1.22.1
opencv-python==4.5.5.62
pycodestyle==2.8.0
toml==0.10.2
Ebrahim Karam
  • 841
  • 1
  • 11
  • 22
0

@David Kohen's answer is working great for me. But if you have many images to show its better to convert it to a function

 def waitUntilX(window):
    while True:
        k = cv2.waitKey(100) # change the value from the original 0 (wait forever) to something appropriate
        if k == 27:
            print('ESC')
            cv2.destroyAllWindows()
            break        
        if cv2.getWindowProperty(window,cv2.WND_PROP_VISIBLE) < 1:        
            break        
    cv2.destroyAllWindows()

Usage

invertedmask = cv2.bitwise_not(mask)
cv2.imshow('inverted mask', invertedmask)
waitUntilX('inverted mask')
mustafa candan
  • 567
  • 5
  • 16