Python 多线程中 OpenCV imshow 方法失效、不显示、不刷新、卡死的解决方法

文章目录

  • 问题
  • 解决方法与程序框架

问题

近日在做项目的时候,需要使用多线程来合成画面,然后一个子线程通过 OpenCV 中的 imshow() 模块显示在窗口上。

但是遇到一个问题:虽然程序能够正常运行,但是没有窗口,在 Dock 栏上只有一个白色的图标表明有这个程序在运行。翻阅了好多的博客,许多都说加入下面的代码就能够正常显示画面。

cv2.namedWindow("Flag Operating System")
cv2.imshow("Flag Operating System", image)
key = cv2.waitKey(1)

我加上了,但是依旧没有反应,这就奇怪了,按道理使用 imshow 就应该能创建窗口。我把 waitKey(1) 中的1 改成了 0 ,这时窗口是出现了,但是是黑屏,画面不刷新。

最终,在经历了近两天的查找与修改,终于发现问题出现在多线程上!!!

大概的意思是:OpenCV-Pythonimshow() 方法不能在子线程上使用,也就是说子线程里使用这个方法无法正确地创建、刷新画面。

解决方法与程序框架

为了解决这个问题,需要加入一个 Queue 将子线程里面的 frame 画面提取到主线程里,然后再在主线程里面显示。大体的程序框架见下面的程序所示。

import queue
import threading

# 处理画面的子线程
class RenderFrame(threading.Thread):
    def __init__(self, thread_name, render_queue):
        threading.Thread.__init__(self, name=thread_name)
        self.render_data = render_queue  # 完成合成的帧缓存列队
		...
        ...
        Your Code
        ...
		...

    def run(self) -> None:
		...
        ...
        Your Code
        ...
        ...
        while True:
            ...
            ...
			frame  # 这个是 OpenCV 处理完的画面,将这个画面存入缓存列队
            self.render_data.put(image)  # 将处理完的画面存入缓存列队

 def main():
    render_frame_queue = queue.Queue()  # 创建一个渲染完成的缓冲队列
    '''
    用于缓存 RenderFrame 合成出来的画面,用作缓存列队
    '''
    display_frame = RenderFrame("RenderFrame", render_frame_queue)
    display_frame.start()  # 开始线程

    # 在主线程处理渲染完成的画面
    '''
    由于 OpenCV 的限制,无法在子线程中使用 nameWindow 或者 imshow 等方法
    只能新建一个多线程列队将渲染完成的信息加入到列队,然后再在主线程中展示出来
    '''
    while True:
        frame = render_frame_queue.get()
        start_time = time.time()
        # 如果获取的帧不为空
        cv2.namedWindow('Window', cv2.WINDOW_KEEPRATIO)
        cv2.imshow('Window', frame)
        cv2.waitKey(1)
        end_time = time.time()
        print("FPS: ", 1 / (end_time - start_time))
        # break
    cv2.destroyAllWindows()
    display_frame.join()


if __name__ == '__main__':
    main()

你可能感兴趣的:(Python,折腾服务器系列,opencv,python,计算机视觉)