Opencv imshow() зависает при обновлении

Для моего алгоритма обработки изображений я использую python/OpenCV. Вывод моего алгоритма будет обновляться в одном и том же окне снова и снова.

Однако иногда окно зависает и вообще не обновляется, но алгоритм все еще работает и тем временем обновляет изображение несколько раз. На этом компьютере с Ubuntu окно становится темно-серым.

Вот отрывок задействованного кода:

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

Примечание: процесс processImg() занимает около 1-2 секунд для своих процедур. Строка cv2.imshow(procImg) создает окно в первом экземпляре (т.е. нет предшествующего вызова)


person user3085931    schedule 04.05.2016    source источник
comment
Это cv2.waitKey, который на самом деле перекачивает сообщения для работы графического интерфейса. Его нужно вызывать достаточно часто, чтобы пользовательский интерфейс действительно реагировал на все необходимые события (например, перерисовку и т. д.). Если обработка занимает так много времени, и вы хотите одновременно иметь отзывчивый пользовательский интерфейс, вам нужно выполнить обработку в отдельном потоке.   -  person Dan Mašek    schedule 05.05.2016
comment
@DanMašek В однопоточной программе, работающей последовательно, я ожидал, что сначала выполнит другую команду после завершения текущей задачи (в данном случае обновите изображение). Спасибо за подсказку с резьбой, но, честно говоря, это излишне усложняет   -  person user3085931    schedule 05.05.2016
comment
Если вы не хотите иметь дело с потоками (хотя это не то, что я считаю сложным, но я понимаю, что YMMV), другая возможность - предоставить какой-то способ перекачки сообщений (вызов waitKey), пока вы делаете обработка (между отдельными этапами). Это будет неуклюже, но, по крайней мере, таким образом окно останется достаточно отзывчивым.   -  person Dan Mašek    schedule 05.05.2016


Ответы (9)


Я предлагаю использовать pyplot Matplotlib для отображения изображения. Я делаю следующим образом.

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

Я знаю, что это не решает проблему cv2.imshow, но решает нашу проблему.

person Dharma    schedule 28.09.2017
comment
В версии 4.1.2 из cv2 (включенной через opencv-python) кажется, что флаг, который вы передали в cvtColor, изменился с cv2.BGR2RGB на cv2.COLOR_BGR2RGB. - person blthayer; 24.01.2020
comment
Это предложение обходного пути, а не решение. Мое предпочтительное решение дано @MohanavelT в другом ответе - в настоящее время ниже. - person MaciekS; 13.01.2021

Увеличение времени ожидания решает эту проблему. Однако, на мой взгляд, это лишнее время, затрачиваемое на сон (20 мс/кадр), хотя это и немного.

изменение

cv2.waitKey(1)

to

cv2.waitKey(20)

предотвращает замерзание окна в моем случае. Продолжительность этого требуемого времени ожидания может различаться на разных машинах.

person user3085931    schedule 05.05.2016

Просто добавьте cv2.destroyAllWindows() сразу после cv2.waitKey()

person Mohanavel T    schedule 22.01.2019
comment
Я бы предложил обернуть код, связанный с imshow, в оператор try-except-finally и поместить cv2.destoryAllWindows() в предложение finally, чтобы окно было уничтожено даже в случае исключения. - person MaciekS; 13.01.2021

У меня такая же проблема, и я заметил, что частота кадров в секунду при обновлении окна становится все медленнее и медленнее, пока полностью не зависает. Увеличение значения waitKey(x) до чего-то более высокого просто увеличивает продолжительность обновления изображений, но когда время, которое необходимо вычислить cv2.imshow(), превышает время от ожидания (Key), оно просто перестает обновляться.

(Пропустите эту жалобу :) Я думаю, что комбинация cv2.imshow() с waitKey() является полной ошибкой дизайна, почему imshow() просто не блокируется до тех пор, пока пользовательский интерфейс не будет обновлен? Это сделало бы жизнь намного проще без необходимости каждый раз вызывать waitKey()...

P.S.: Есть возможность запустить собственный поток для окон opencv внутри opencv:

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

источник: команда cv2.imshow не работает должным образом в opencv- питон

Ну, это не работает для меня, потому что я всегда получаю эти ошибки при запуске:

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

Может быть, вы могли бы попробовать и сообщить, если это работает для вас?

Редактировать: Хорошо, я решил проблему для себя, создав отдельный скрипт 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)

И я пишу изображение в своей другой программе с помощью: cv2.imwrite("image.pgm", image) И я вызываю скрипт следующим образом:

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

Хотя это создает некоторые грязные чтения, иногда этого достаточно для меня, лучшим решением было бы использование каналов или очередей между двумя процессами.

person ElDani    schedule 22.09.2016
comment
... но вы снова имеете дело с циклом 20 мс, не так ли? - person user3085931; 29.09.2016
comment
Правильно, в настоящее время я не знаю, как избавиться от этой функции ожидания. Но что я попробую дальше, так это заменить opencv imshow другим решением, отличным от opencv, для отображения изображений. Вы знаете что-нибудь в этом направлении? - person ElDani; 01.10.2016
comment
Тогда я не получаю информационный прирост поста. Взгляните на Tkinter и PIL для Python - person user3085931; 01.10.2016
comment
Но почему нет? Дополнительный процесс решает проблему зависания и об этом эта ветка? Но все равно спасибо за информацию. - person ElDani; 04.10.2016
comment
Я достигаю того же результата, когда просто увеличиваю время ожидания до 20 мс, а это означает, что создание дополнительного потока является ненужным накладным расходом, который через несколько месяцев никто больше не поймет его цели (из моего опыта) - person user3085931; 04.10.2016
comment
Ну, это не сработало для меня. Но дополнительный процесс сработал, поэтому, безусловно, имеет смысл оставить этот пост там, где он есть. - person ElDani; 05.10.2016

Итак, я думаю, что здесь происходит то, что окно (элемент highGUI), которое все еще активно после первого вызова imshow, ожидает какого-то ответа от вашей функции waitKey, но становится неактивным, так как программа застревает в вычислениях либо в функциях processImg, либо в loadNextImg. Если вас не волнует небольшая потеря эффективности (т. е. вы не работаете во встроенной системе, где учитывается каждая операция), вам следует просто уничтожить окно после waitKey и воссоздать его перед imshow. Поскольку окно больше не существует во время обработки и загрузки изображений, highGUI не застрянет в ожидании вызова от waitKey и не перестанет отвечать на запросы.

person bstadt    schedule 05.05.2016
comment
Я попытался закрыть окно прямо перед обновлением (или в этом случае снова создать новое окно). В результате вместо того, чтобы стать серым, он просто остается белым. Еще одна проблема с этим решением: окно создается в случайном месте, и если я хочу его переместить, после следующего обновления новое окно снова создается в старой позиции. Может помешать оставшейся работе. - person user3085931; 05.05.2016
comment
Чтобы решить проблему с окнами в случайных местах, просто вызовите moveWindow сразу после создания окна, и вы можете указать x, y положение окна, которое вы хотите. Кроме того, ваше окно, остающееся пустым белым, показывает, что оно все еще активно, просто вы можете передавать ему белое изображение для отображения. Я бы проверил сами алгоритмы на этом этапе. Хорошим способом сделать это было бы записать изображение, которое вы пытаетесь отобразить, в файл, а затем просмотреть файл. Если файл весь белый, то это алгоритмическая проблема. - person bstadt; 07.05.2016
comment
с алгоритмом все в порядке, я просто увеличил нагрузку, раньше все работало нормально - я имею в виду, что когда окно становится серым в ubuntu, это означает, что это приложение не отвечает. Поскольку это последовательная программа-подпрограмма, новое изображение уже готово, когда дело доходит до обновления - и фактически оно сначала начинает обработку следующего кадра, когда новое изображение было показано. Вот почему я ожидаю, что ошибка на стороне OpenCV. Другими словами, OpenCV, кажется, запускает потоки самостоятельно, когда он возвращается, но даже не завершен. - person user3085931; 07.05.2016

Если ваше окно становится серым, возможно, требуется больше вычислительной мощности. Поэтому попробуйте изменить размер изображения на изображение меньшего размера и выполнить. Иногда он зависает во время работы в ноутбуках ipython из-за нажатия любой клавиши во время выполнения операции. Я лично выполнил вашу проблему, но при этом у меня не было серого экрана. Я выполнял напрямую с помощью терминала. Код и шаги показаны ниже.

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)

Запустите его в терминале:

  1. источник активировать env_name
  2. python Имя файла.py --image Имя изображения.png

Это приведет к вашему результату только в одном окне (обновление каждый раз) без зависания, и если вы хотите, чтобы в каждом новом окне было отдельное изображение, добавьте .format(i), как указано ниже. Но не забывайте запускать только в терминале, а не в блокнотах Jupyter.

Вы можете проверить с помощью команд терминала в этом видео по ссылке 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)

Это может помочь вам получить 1000 изображений отдельно.

person R K Bhalodia    schedule 06.12.2017

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)

Сохраните эту программу и с этого момента импортируйте ее и используйте средство просмотра функций для отображения любого кадра / изображения, и ваши окна дисплея не будут зависать или падать.

person Harsh Vijay    schedule 02.07.2019

Добавьте следующие две строки кода после функции cv2.imshow(),

cv2.waitKey()

cv2.destroyAllWindows()

person hafiz031    schedule 15.02.2019
comment
дубликат @Mohanavel - person user3085931; 18.02.2019

Вы можете использовать цикл while для получения серийных изображений без зависания. Вот пример получения 10 изображений. Вы также можете попробовать увеличить waitkey число и sleep время в цикле while. Эта работа для меня.

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
person Savin Perera    schedule 05.05.2020