20

For my image processing algorithm I'm using python / OpenCV. The output of my algorithm shall be updated im the same window over and over again.

However sometimes the window freezes and doesn't update at all, but the algorithm is still running and updated the picture a multiple times in the meantime. The window turns dark gray on this Ubuntu machine.

Here is an excerpt of the involved code:

for i in range(0,1000):
    img = loadNextImg()
    procImg = processImg(img)
    cv2.imshow("The result", procImg)
    cv2.waitKey(1)

N.B.: processImg() takes about 1-2 s for its procedures. The line cv2.imshow(procImg) creates the window in first instance (i.e. there is no preceding invocation)

user3085931
  • 1,757
  • 4
  • 29
  • 55
  • 3
    It's `cv2.waitKey` that actually pumps the messages for the GUI to work. It needs to be called frequently enough for the UI to actually respond to all the necessary events (like repaints, etc). If the processing takes this long, and you want to have a responsive UI at the same time, you need to do the processing in a separate thread. – Dan Mašek May 04 '16 at 23:25
  • @DanMašek In a single-threaded program working sequentially I expected first to execute another command, after a current task is completed (in this case update the image). Thanks for the tip with the threading, but to be honest this makes it unnecessary complicated – user3085931 May 05 '16 at 19:49
  • 2
    If you don't want to deal with threads (although that's not what i'd consider complicated, but I understand that YMMV), the other possibility is to provide some way to pump the messages (call waitKey) while you're doing the processing (in between the individual steps). It's going to be clumsy, but at least this way the window will remain fairly responsive. – Dan Mašek May 05 '16 at 19:55

10 Answers10

19

My suggestion is to use Matplotlib pyplot for displaying the image. I do it the following way.

import matplotlib.pyplot as plt
# load image using cv2....and do processing.
plt.imshow(cv2.cvtColor(image, cv2.BGR2RGB))
# as opencv loads in BGR format by default, we want to show it in RGB.
plt.show()

I know it does not solve the problem of cv2.imshow, but it solves our problem.

Dharma
  • 2,425
  • 3
  • 26
  • 40
  • 2
    In version `4.1.2` of `cv2` (included via `opencv-python`), it seems the flag you passed to `cvtColor` has changed from `cv2.BGR2RGB` to `cv2.COLOR_BGR2RGB`. – blthayer Jan 24 '20 at 19:54
  • This is a workaround suggestion, not solution. My preferred solution is given by @MohanavelT in other [answer](https://stackoverflow.com/a/54303648/1317493) -currently below. – MaciekS Jan 13 '21 at 08:08
10

Increasing the wait time solves this issue. However in my opinion this is unnecessary time spent on sleeping (20 ms / frame), even though it's not much.

Changing

cv2.waitKey(1)

to

cv2.waitKey(20)

prevents the window from freezing in my case. The duration of this required waiting time may vary on different machines.

user3085931
  • 1,757
  • 4
  • 29
  • 55
4

Just add cv2.destroyAllWindows() just after cv2.waitKey()

Mohanavel T
  • 371
  • 4
  • 17
  • I'd suggest to wrap `imshow`-related code into `try-except-finally` statement and put the `cv2.destoryAllWindows()` into `finally` clause, so that the window will be destroyed even in case of exception. – MaciekS Jan 13 '21 at 08:12
3

I have the very same issue and I noticed that the fps the window is updated is getting slower and slower until it freezes completely. Increasing the waitKey(x) to something higher just extends the duration where the images are updated but when the time that cv2.imshow() needs to calculate exceeds the time from wait(Key) it just stops updating.

(Skip this complainment:) I think the cv2.imshow() with waitKey() combination is a complete design error, why isn't imshow() just blocking until the UI is updated? That would make life so much easier without having to call waitKey() everytime...

P.S.: There is a possibility to start an own thread for opencv windows inside opencv:

import cv2
img = cv2.imread("image.jpg")
cv2.startWindowThread()
cv2.namedWindow("preview")
cv2.imshow("preview", img)

source: cv2.imshow command doesn't work properly in opencv-python

Well this doesn't work for me because I always get this errors when I run it:

(python3:1177): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
Attempt to unlock mutex that was not locked
Aborted

Maybe you could try it and report if it is working for you?

Edit: Okay I solved the problem for me by creating a separate script imshow.py:

import cv2
import os.path

while True:
    if os.path.exists("image.pgm"):
        image = cv2.imread("image.pgm")
        if not image is None and len(image) > 0:
            cv2.imshow("Frame", image)
            cv2.waitKey(20)

And I am writing the image out in my other program with: cv2.imwrite("image.pgm", image) And I am calling the script like this:

import subprocess
subprocess.Popen(["python3", "imshow.py"])

Although this is creating some dirty reads sometimes it is sufficient enough for me, a better solution would be to use pipes or queues between the two processes.

Community
  • 1
  • 1
ElDani
  • 31
  • 7
  • ..but once again you are dealing with a 20 ms loop aren't you? – user3085931 Sep 29 '16 at 11:41
  • Correctly, there's currently no way i know to get rid of that waitkey function. But what i will try next is to replace opencv imshow with another non opencv solution to show the images. Do you know anything in that direction? – ElDani Oct 01 '16 at 14:52
  • Then I don't get the information gain of the post. Have a look at `Tkinter` and `PIL` for Python – user3085931 Oct 01 '16 at 15:19
  • But why not? The extra process solves the problem of freezing and this is what this thread is about? But thanks anyway for the info. – ElDani Oct 04 '16 at 07:20
  • I achieve the same result when I solely increase the waiting time to 20 ms as well, which means creating an extra thread is unnecessary overhead that in a few months nobody will understand its purpose anymore (from my experience) – user3085931 Oct 04 '16 at 13:13
  • 1
    Well that didn't work for me. But the extra process did work so it's surely meaningful to leave this post where it is. – ElDani Oct 05 '16 at 11:56
2

So what I think is going on here is that the window,(an element of the highGUI) which is still active after the first call to imshow, is waiting for some sort of response from your waitKey function, but is becoming inactive since the program is stuck calculating in either the processImg of loadNextImg functions. If you don't care about a slight waste of efficiency (i.e. you're not running on an embedded system where every operation counts), you should just destroy the window after waitKey, and recreate before imshow. Since the window no longer exists during the time you are processing and loading images, the highGUI wont get stuck waiting for a call from waitKey, and it won't become unresponsive.

bstadt
  • 146
  • 11
  • I tried killing the window right **before** updating (or in this case creating a new window again). The result is instead of turning grey it just stays blank white. Another Problem with this solution: the window gets generated on a random place and if I want to move that, after the next update the new window is created at the old position again. Might get in the way of the remaining work. – user3085931 May 05 '16 at 19:53
  • To fix the issue with windows in random places, just call moveWindow right after you create the window and you can specify the x,y position of the window you want. Also, your window staying blank white shows that it is still active, just that you may be passing it a white image to display. I would check the algorithms themselves at this point. A good way to do this would be to write the image you are trying to display to a file and then view the file. If the file is all white, then it's an algorithmic issue. – bstadt May 07 '16 at 18:28
  • the algorithm is alright, I just increased the work load, before it was working just fine - I mean when a window turns grey in ubuntu means that this application is not responding. As it is a sequential program-routine, the new image is already finished when it comes to updating - and actually it first starts processing the next frame when the new image was shown. This is why I expect the error is on OpenCV side. In other words OpenCV seems to start some threading on its own, when it's returning but not even finished – user3085931 May 07 '16 at 19:44
1

If your window is going grey then it might be take more processing power. So try to resize image into smaller size image and execute. Sometimes times it freezes while running in ipython notebooks due to pressing any key while performing operation. I had personally executed your problem but I didn't get grey screen while doing it. I did executing directly using terminal. Code and steps are shown below.

import argparse
import cv2
import numpy as np 

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())

# load the image, grab its dimensions, and show it
image = cv2.imread(args["image"])
(h, w) = image.shape[:2]
cv2.imshow("Original", image)
cv2.waitKey(0)

for i in range(0,1000):
    image = cv2.imread(args["image"])
    cv2.imshow("The result",image);
    cv2.waitKey(0)

Run it in terminal:

  1. source activate env_name
  2. python Filename.py --image Imagename.png

This will get to your result in one window only(updating each time) without freezing and if you want seperate image in every new window then add .format(i) as given below. But Remember to run in terminal only not in jupyter notebooks.

You can check using terminal commands in this video link https://www.youtube.com/watch?v=8O-FW4Wm10s

for i in range(0,1000):
    image = cv2.imread(args["image"])
    cv2.imshow("The result{}".format(i),image);
    cv2.waitKey(0)

This may help to get you 1000 images separately.

1
try:
    import cv2
except:
    print("You need to install Opencv \n Run this command \n pip install python-opencv")
    exit()
print('Press q to quit frame')
def viewer(name,frame):
    while True:
        cv2.imshow(name,frame)
        if cv2.waitKey(10) & 0xff ==ord('q'):
            break
    return
cv2.destroyWindow(name)

Save this program and from now onwards, import this and use the function viewer to display any frame/image and your display windows will not hang or crash.

RAR
  • 83
  • 13
0

Add the following two lines of code after cv2.imshow() function,

cv2.waitKey()

cv2.destroyAllWindows()

Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
hafiz031
  • 2,236
  • 3
  • 26
  • 48
0

You can use while loop to take burst images without freezing. Here is an example for taking 10 images. You can also try to increase waitkey number and sleep time in while loop. This work for me.

key = cv2.waitKey(1)
webcam = cv2.VideoCapture(0)
sleep(1)

while True:

    try:
        check, frame = webcam.read()
        cv2.imshow("Capturing", frame)
        key = cv2.waitKey(1)

        img_counter = 0

        if key & 0xFF == ord('s'): #press s to take images
            while img_counter < 10:
                check, frame = webcam.read()
                cv2.imshow("Capturing", frame)
                key = cv2.waitKey(1)
                path = 'F:/Projects/' #folder path to save burst images
                img_name = "burst_{}.png".format(img_counter)
                cv2.imwrite(os.path.join(path, img_name), img=frame)
                print("Processing image...")
                img_ = cv2.imread(img_name, cv2.IMREAD_ANYCOLOR) #save as RGB color format
                print("{} written!".format(img_name))
                img_counter += 1
                sleep(0.2)
            webcam.release()
            cv2.destroyAllWindows()
            break

        elif key == ord('q'): #press q to quit without taking images
            webcam.release()
            cv2.destroyAllWindows()
            break

    except(KeyboardInterrupt):
        print("Turning off camera.")
        webcam.release()
        print("Camera off.")
        print("Program ended.")
        cv2.destroyAllWindows()
        break
0

This is an old thread but in case someone else encounters it, normally the issue happen when you update opencv/opencv-contrib versions with pip and still some of their dependencies are unmet (for example you might have numpy already installed so it wont reinstall it and this causes it to crash in the back).

Simply do

pip install opencv-python opencv-contrib-python --no-cache --force-reinstall

Version 4.5.2.52 is working fine on ubuntu 20.04 and 18.04 with python > 3.8

Abed
  • 1