2

What I want to do is, I want to have have a user click the close "X" button in an OpenCV window and have the program recognize it, and close that window.

It seems that this is not easy, and after four days of going round in circles and finding out how it can be done on a windows machine I am no closer to finding out how to do it on a Raspberry Pi using Python.

I think I need to get the handle of the OpenCV window ( how? ) and then use that to see if the window is still visible ( what call? ) and if it is not, bring proceedings to a halt ( I can do that bit ).

I have tried cvGetWindowHandle("window_name") but I've downloaded the source and GetWindowHandle doesn't seem to be available from python.

JoraSN
  • 332
  • 2
  • 14
Grumpy-Mike
  • 41
  • 1
  • 5
  • what windowing backend is used by OpenCV on Raspbian? Qt? – Rudolfs Bundulis Jun 15 '15 at 11:27
  • No idea, how would one find that out? – Grumpy-Mike Jun 15 '15 at 12:03
  • I'm not sure how to do that during the runtime, if you built it yourself then gtk is the default for Linux I guess, and something else if you set some specific flags. But anyway that will not help much, since you'll have to access the window through the backend api and receive its events which I guess you do not want to do. I'll try to think if there is an easier way. – Rudolfs Bundulis Jun 15 '15 at 12:49

4 Answers4

2

The code to capture the left button mouse click event and close a window is fairly simple:

if event == cv2.EVENT_LBUTTONDOWN:
    cv2.destroyWindow("window_name")

There is a tutorial on how to use the button click event here which is where I took that code, it provides a full working example in python.

However you are probably running a unix based system on your Rpi and will therefore want to read This answer as you made need a combination of waitKey(1) in order for it to work.

Community
  • 1
  • 1
GPPK
  • 6,546
  • 4
  • 32
  • 57
  • 1
    Sorry that will not work. There is no event returned if the mouse click is in the window bar, which is where the close button is located. – Grumpy-Mike Jun 15 '15 at 11:13
0

I maybe have a solution but I'm not 100% sure so you'll have to check it yourself:) I assume the OpenCV uses X11 underneath (if no none of this makes sense). With X11 you can:

1) Find X11 window handle for your OpenCV window as described here

2) Use XSelectInput to hook into its event loop somewhat similar to what was done here. I assume you should useStructureNotifyMask as the mask to get the XDestroyWindowEvent event. Run the X11 event loop and as soon as you get the corresponding event you can call the OpenCV destroyWindow function.

This suggestion is based on assumptions and I can't give any guarantees it will work, but as far as I understand if OpenCV isn't built with some other specific window manager this should work. As far as I understand Raspbian was shipped with X11 up to some point and then it switched to Wayland. In case you have an image with Wayland then this probably will not work (and I'm sorry but my Linux skills do not contain a recipe on how to determine which one is used:D).

UPDATE

Actually after more reading I seem to feel that gtkshould be able to handle whatever is being used underneath (X11/Wayland). So if you install gtk development libraries you should also be able to connect to the windows deletion signal like described here. The only question then remains on how to obtain the window handle.

My personal advice - use Qt or some other GUI friendly framework to render the OpenCV images instead of doing it directly with OpenCV. OpenCV is an imaging framework but IMHO highgui is too unusable for anything serious.

Community
  • 1
  • 1
Rudolfs Bundulis
  • 11,636
  • 6
  • 33
  • 71
  • Thanks but all those links are way over my head in terms of labyrinthine Linux. The update link is all about C and I am using Python. – Grumpy-Mike Jun 15 '15 at 13:39
  • @Grumpy-Mike can you elaborate what you wanted to to with OpenCV? Maybe I can suggest an easier way to do the same and have full control over the window. – Rudolfs Bundulis Jun 15 '15 at 13:40
  • I am doing a series of things with a video camera. This first one is a video sequencer where colored pegs in a board determine what notes are played. However a user will expect the window to close when you press the close cross, instead it closes and pops up in a random place. I can't believe that any one will expect any other behavior from a window but it seems so intractable to actually make this simple behavior work. – Grumpy-Mike Jun 15 '15 at 13:46
  • @Grumpy-Mike well I know this could look hard for a person with little Qt experience but this question (http://stackoverflow.com/questions/21246766/how-to-efficiently-display-opencv-video-in-qt) uses OpenCV to display frames on a QT widget. You could try and adapt it so you have OpenCV and full control of the window. – Rudolfs Bundulis Jun 16 '15 at 08:47
  • Thanks but that page is in C and I am writing in Python and I think the effort of learning a new topic ( QT Widget ) and translating between the two is just too much effort to be able to close a window by clicking a close box. Also it looks like an old version of openCV as well so that also needs converting. I also fear that this will slow things down and the application requires as fast a processing time as possible. Thanks for your interest anyway, it looks like this problem has no reasonable solution. – Grumpy-Mike Jun 16 '15 at 12:58
  • If it's any help, qt has python bindings so you could still use a combo of OpenCV and Qt. Take a look at http://www.iesensor.com/blog/2014/06/15/using-opencv-in-qt4-gui-using-python/ – Rudolfs Bundulis Jun 16 '15 at 13:15
0

all I want to do is to have a user click the close X in an openCV window

This is how I did it, in a capture loop (RPi stretch, opencv 4.0):

while True: 
    # do your video capture
    # ... 
    cv.imshow("video frame",frame)
    if cv.getWindowProperty('video frame', 1) < 0:
        break

getWindowProperty isn't much documented but what it does is, as its name implies, to return the property of a given window. Two of the flags of interest are WND_PROP_FULLSCREEN (or 0) and WND_PROP_AUTOSIZE (or 1). When the window is closed the function returns -1. Use this to immediately break your loop (or close your window if not in a loop).

References:

calocedrus
  • 2,430
  • 20
  • 25
0

Poll with cv2.getWindowImageRect(windowName). It will return (-1, -1, -1, -1) when the user clicks the window close button.

# check if window was closed or image was resized

xPos, yPos, width, height = cv2.getWindowImageRect(windowName)

if xPos == -1: # if user closed window
    pass # do whatever you want here if the user clicked CLOSE

I haven't found this documented anywhere; discovered it by accident while handling window resizing. (Tested with OpenCV 4.1.0.)

nerdfever.com
  • 1,652
  • 1
  • 20
  • 41