OpenCV closing a window with a mouse click on a Raspberry Pi - python

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.

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.

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.

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:
https://docs.opencv.org/3.1.0/d7/dfc/group__highgui.html#gaaf9504b8f9cf19024d9d44a14e461656
OpenCV Python: How to detect if a window is closed?

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.)

Related

Getting screenshot via printwindow not redrawing if laptop screen off

My goal is to take screenshots off an application while the laptop screen is off, but instead the screenshot will always be the same as just before turning off the screen. It does not redraw itself once the screen is off, and remains frozen.
I'm obtaining a screenshot using printwindow from Python (using method described here: Python Screenshot of inactive window PrintWindow + win32gui
This method works nicely as long as I have my laptop screen on, but if I turn it off, it simply returns the last image before the screen turned off. I've tried using win32gui.RedrawWindow, hoping that this would force a redraw, but I haven't gotten it to work, even trying all the different flags. I've also tried getting screenshots via pyautogui, but this also has the same problem. Is there any way to redraw the application while the laptop screen is off?
It would be nice if there were a straightforward way to do what you want to do, but unfortunately it's just not possible without some convoluted low-level work.
In the underlying WinAPI, native windows redraw themselves only when they receive WM_PAINT messages, and they only receive WM_PAINT messages if they are visible. They don't get the messages if they're behind another window, or if they're dragged off screen, or minimized, or their visibility is set to False. They also aren't visible when the screen is off. Since they aren't visible, they simply never get told to redraw themselves. That's why the screen capture image doesn't change after the screen is turned off.
There is no command you can issue that will override this -- it is implemented as a fundamental part of the windowing paradigm.
One solution is to have the application paint itself in something that's not a window (e.g., a dialog box) and capture that rather than capturing the screen. You could also modify the application by overriding OnPaint and using a timer to invalidate and call your OnPaint function periodically (since WM_PAINT messages won't be received).
If it were me I'd override OnPaint, make my application draw itself to a background context bitmap rather than the normal window, then use a timer to invalidate and redraw periodically and just take the bitmap of the background context whenever I wanted to capture the output.
If you don't own the code for the applications that are running, you may still be able to get applications to redraw themselves by running everything in a virtual machine. I've done that successfully for headless computing in the past, but it was many OS versions ago and things may be different now, so YMMV...
Information on manual screenshots under VMWare is here.
Information on programmatic screenshots under Hyper-V is here.

How to emulate mouse/keyboard events in a unfocused/minimized window?

I am trying to do some automation with Python, but I want to execute it and still being able to use my machine freely. So I am using PyWin32 to emulate some clicks and typing but it only works if I run the script while the window is open and focused.
There is a way to make my script only focus on a window, and still be able to click on that window without taking control over the mouse, even if the window is not focused (if it works when is minimized, is best!)?
i do not know the PyWin32 package but from a win32 api point of view the thing should be easy.
get a HWND of that window and post (PostMessage) the events you want to the window.
eg: WM_LBUTTONDOWN & WM_LBUTTONUP, WM_RBUTTONDOWN & WM_RBUTTONUP, WM_MOUSEMOVE...
look at the win32 help how to set the wParam & lParam data for the specific events.
i controlled diablo 3 this way for example ;)
Edit:
there is no need to be in focus or maximized for this
Edit Edit:
may be you should look after autoit, a widely used scrip language for window automation. I never used it but read the name very often in this context. it may also be usable from python.

How to show a fullscreen image from the command line interface without a window manager using Python

I have a python script that, when executed, wait's until it gets input from the user. I now want to know if it is posible to keep showing an image fullscreen until the user has given the input? I have searched for a solution but all i can find are tools that window managers to show the picture, but this is not installed. It'll probably only run on Debian.
I'm kind of searching for the same idea as omxplayer, but instead of movies it has to display pictures.
Using pygame is probably the easiest way of displaying an image fullscreen on the Linux framebuffer or on the X Windows root window (i.e. without a window manager).
The answers to the question Frame buffer module of python have all the details on how to achieve this.

Python, transparent window with a red outine of a rectangle

Hi I am new to this whole coding thing I was suggested to use Python. The version I have now is 2.7. I need help with making a transparent window to the copacity of 100 so that you can actually see through it and I also want to know how to make a fairy thick, out line of a rectangle in the colour red.
Help me please :S Thanks!
Unfortunatelly, there is not such an easy thing as sa "trasnparent window" - althougmodern widnow managaers do have various opacity controls for the windows, those just affect the windows as a whole - and do not integrate at all with the program running "inside" the windows. There may even be, for some of them, a way to call functions to explicitly set up the opacity level of a given window, but I don't think it willbe possible for all of them.
That said, it is possible to get grab of the "root" window and draw directly on the screen - -bypassing the window manager. There are APIs for that at least on Windows and Linux (you have to mention in what operating system you need that working) - but it will amount to not a trivial research work, since this is not what is expected of a "well behaved app" - for which the GUI toolkits are written and documented. You will need to write xlib code in Linux, and directly call win32 api's on windows - both are possible from Python - as possible as under-documented.
And once you get to draw the rectangle, since you are bypassing the window manager, you willhave to care about every low-level detail of your app: mouse event handling, screen-redrawing (and notifying the system of drawing taking effect over other windows), and so on.

pygtk window with box that ignores all X(mouse)events (passes them through)

I'd like to do the following: Create a fullscreen, always on top pygtk window with a webkit widget displaying some html, but with a box that is completely transparent, so that the windows below are visible. (This seems to be possible: Is it possible to render web content over a clear background using WebKit?)
What I'd like is to (sometimes) pass all mouse events that occur in the transparent box down to the windows below my application's window, so that I can interact with them normally. So not just visually transparent, but also transparent to mouse events.
Theoretically, I suppose I could catch all events I am interested in with a pygtk Eventbox, find the window directly below mine with wnck, and pass this event to it with python-xlib.
This doesn't exactly seem like the most elegant solution; is there a better way?
Forwarding the events won't work well as you guessed; it creates a lot of race conditions, and some apps will ignore stuff from XSendEvent anyway.
What you can do is set the input shape mask. See http://www.x.org/releases/current/doc/xextproto/shape.html and then look at XFixesSetWindowShapeRegion() in /usr/include/X11/extensions/Xfixes.h which lets you specify a shape "kind" (here you want ShapeInput).
Something like:
XRectangle rect;
XserverRegion region = XFixesCreateRegion(display, &rect, 1);
XFixesSetWindowShapeRegion(display, window, ShapeInput, 0, 0, region);
XFixesDestroyRegion(display, region);
The ability to set ShapeInput is "only" 5-6 years old so if you care about really crappy old versions of X11, you might be hosed.

Categories

Resources