【问题标题】:Opencv imshow() freezes when updatingOpencv imshow() 更新时冻结
【发布时间】:2016-08-30 12:48:18
【问题描述】:

对于我的图像处理算法,我使用的是 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) 行在第一个实例中创建窗口(即没有前面的调用)

【问题讨论】:

  • 实际上是 cv2.waitKey 为 GUI 工作提供消息。它需要足够频繁地调用,以便 UI 真正响应所有必要的事件(如重绘等)。如果处理需要这么长时间,并且您希望同时拥有响应式 UI,则需要在单独的线程中进行处理。
  • @DanMašek 在一个按顺序工作的单线程程序中,我希望在当前任务完成后首先执行另一个命令(在这种情况下更新图像)。感谢您提供有关线程的提示,但老实说,这使得它变得不必要的复杂
  • 如果你不想处理线程(虽然这不是我认为复杂的,但我理解 YMMV),另一种可能性是提供某种方式来泵送消息(调用waitKey)在您进行处理时(在各个步骤之间)。它会很笨拙,但至少这样窗口会保持相当响应。

标签: python opencv image-processing freeze imshow


【解决方案1】:

我的建议是使用 Matplotlib pyplot 来显示图像。我按照以下方式进行。

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 的问题,但它解决了我们的问题。

【讨论】:

  • cv2 的版本4.1.2(通过opencv-python 包含)中,您传递给cvtColor 的标志似乎已从cv2.BGR2RGB 更改为cv2.COLOR_BGR2RGB
  • 这是一个解决方法建议,而不是解决方案。我的首选解决方案由@MohanavelT 在其他answer 中给出 - 目前在下面。
【解决方案2】:

增加等待时间可以解决这个问题。但是在我看来,这是不必要的睡眠时间(20 毫秒 / 帧),即使它并不多。

变化

cv2.waitKey(1)

cv2.waitKey(20)

在我的情况下防止窗口冻结。所需等待时间的持续时间可能因机器而异。

【讨论】:

    【解决方案3】:

    只需在cv2.waitKey() 之后添加cv2.destroyAllWindows()

    【讨论】:

    • 我建议将imshow相关代码包装到try-except-finally语句中,并将cv2.destoryAllWindows()放入finally子句中,这样即使出现异常,窗口也会被销毁。
    【解决方案4】:

    我有同样的问题,我注意到更新窗口的 fps 越来越慢,直到它完全冻结。 将 waitKey(x) 增加到更高的值只会延长图像更新的持续时间,但是当 cv2.imshow() 需要计算的时间超过 wait(Key) 的时间时,它就会停止更新。

    (跳过此投诉:) 我认为 cv2.imshow() 与 waitKey() 组合是一个完整的设计错误,为什么 imshow() 在 UI 更新之前不阻塞?这将使生活变得更加轻松,而不必每次都调用 waitKey()...

    P.S.:有可能在 opencv 内部为 opencv 窗口启动一个自己的线程:

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

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

    这对我不起作用,因为我在运行它时总是会收到此错误:

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

    虽然这有时会造成一些脏读,但这对我来说已经足够了,更好的解决方案是在两个进程之间使用管道或队列。

    【讨论】:

    • ..但是你又要处理一个 20 毫秒的循环,不是吗?
    • 正确,目前我不知道如何摆脱该 waitkey 功能。但我接下来要尝试的是用另一种非 opencv 解决方案替换 opencv imshow 来显示图像。你知道这方面的事情吗?
    • 那我没有得到帖子的信息增益。看看TkinterPIL for Python
    • 但为什么不呢?额外的过程解决了冻结问题,这就是这个线程的内容?不过还是谢谢你的信息。
    • 那对我不起作用。但是额外的过程确实有效,因此将这篇文章留在原处肯定是有意义的。
    【解决方案5】:

    所以我认为这里发生的情况是,在第一次调用 imshow 后仍处于活动状态的窗口(highGUI 的一个元素)正在等待来自您的 waitKey 函数的某种响应,但正在变为非活动状态因为程序被困在 loadNextImg 函数的 processImg 中。如果您不关心效率的轻微浪费(即您没有在每个操作都很重要的嵌入式系统上运行),您应该在 waitKey 之后销毁窗口,并在 imshow 之前重新创建。由于在处理和加载图像期间窗口不再存在,因此 highGUI 不会卡住等待来自 waitKey 的调用,也不会无响应。

    【讨论】:

    • 我尝试在 更新之前杀死窗口(或者在这种情况下再次创建一个新窗口)。结果不是变成灰色,而是保持空白。此解决方案的另一个问题:窗口是在随机位置生成的,如果我想移动它,在下一次更新后,新窗口会再次在旧位置创建。可能会妨碍剩余的工作。
    • 要解决随机位置的窗口问题,只需在创建窗口后立即调用 moveWindow 即可指定所需窗口的 x,y 位置。此外,您的窗口保持空白显示它仍然处于活动状态,只是您可能正在传递一个白色图像来显示。此时我会检查算法本身。一个很好的方法是将您尝试显示的图像写入文件,然后查看该文件。如果文件全是白色的,那就是算法问题。
    • 算法没问题,我只是增加了工作量,在它工作正常之前 - 我的意思是当一个窗口在 ubuntu 中变成灰色时意味着这个应用程序没有响应。由于它是一个顺序程序例程,因此新图像在更新时已经完成 - 实际上它首先在显示新图像时开始处理下一帧。这就是为什么我希望错误出现在 OpenCV 方面。换句话说,OpenCV 似乎会在它返回但尚未完成时自行启动一些线程
    【解决方案6】:

    如果您的窗口变灰,则可能需要更多的处理能力。所以尝试将图像调整为更小尺寸的图像并执行。有时,由于在执行操作时按任意键,它在 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. 源激活环境名称
    2. python Filename.py --image Imagename.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 张图像。

    【讨论】:

      【解决方案7】:
      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)
      

      保存此程序,从现在开始,导入此程序并使用功能查看器显示任何帧/图像,您的显示窗口不会挂起或崩溃。

      【讨论】:

        【解决方案8】:

        cv2.imshow()函数后添加如下两行代码,

        cv2.waitKey()

        cv2.destroyAllWindows()

        【讨论】:

        • @Mohanavel 的副本
        【解决方案9】:

        您可以使用 while 循环来拍摄连拍图像而不会冻结。这是拍摄 10 张图像的示例。您也可以尝试在 while 循环中增加 waitkey 数字和 sleep 时间。这对我有用。

        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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-06-13
          • 2015-07-15
          • 1970-01-01
          • 2015-01-22
          • 2013-01-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多