问题
近日在做项目的时候,需要使用多线程来合成画面,然后一个子线程通过 OpenCV
中的 imshow()
模块显示在窗口上。
但是遇到一个问题:虽然程序能够正常运行,但是没有窗口,在 Dock 栏上只有一个白色的图标表明有这个程序在运行。翻阅了好多的博客,许多都说加入下面的代码就能够正常显示画面。
cv2.namedWindow("Flag Operating System")
cv2.imshow("Flag Operating System", image)
key = cv2.waitKey(1)
我加上了,但是依旧没有反应,这就奇怪了,按道理使用 imshow
就应该能创建窗口。我把 waitKey(1)
中的1
改成了 0
,这时窗口是出现了,但是是黑屏,画面不刷新。
最终,在经历了近两天的查找与修改,终于发现问题出现在多线程上!!!
大概的意思是:OpenCV-Python
的 imshow()
方法不能在子线程上使用,也就是说子线程里使用这个方法无法正确地创建、刷新画面。文章来源:https://www.toymoban.com/news/detail-557671.html
解决方法与程序框架
为了解决这个问题,需要加入一个 Queue
将子线程里面的 frame
画面提取到主线程里,然后再在主线程里面显示。大体的程序框架见下面的程序所示。文章来源地址https://www.toymoban.com/news/detail-557671.html
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 imshow 方法失效、不显示、不刷新、卡死的解决方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!