Opencv imshow() freezes when updating
Asked Answered
T

10

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)

Technicality answered 4/5, 2016 at 21:45 Comment(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.Mccreary
@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 complicatedTechnicality
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.Mccreary
M
20

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.

Mackle answered 28/9, 2017 at 4:12 Comment(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.Stigmatize
This is a workaround suggestion, not solution. My preferred solution is given by @MohanavelT in other answer -currently below.Lamanna
T
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.

Technicality answered 5/5, 2016 at 20:36 Comment(0)
E
4

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

Eckel answered 22/1, 2019 at 8:0 Comment(1)
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.Lamanna
P
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.

Pond answered 22/9, 2016 at 11:31 Comment(6)
..but once again you are dealing with a 20 ms loop aren't you?Technicality
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?Pond
Then I don't get the information gain of the post. Have a look at Tkinter and PIL for PythonTechnicality
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.Pond
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)Technicality
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.Pond
V
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.

Virgel answered 5/5, 2016 at 2:43 Comment(3)
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.Technicality
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.Virgel
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 finishedTechnicality
T
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.

Twain answered 6/12, 2017 at 14:1 Comment(0)
H
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.

Hodgkin answered 2/7, 2019 at 5:42 Comment(0)
R
1

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

Raynold answered 6/6, 2022 at 22:20 Comment(0)
I
0

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

cv2.waitKey()

cv2.destroyAllWindows()

Incandescence answered 15/2, 2019 at 15:34 Comment(1)
duplicate of @MohanavelTechnicality
S
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
Schmuck answered 5/5, 2020 at 17:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.