pyqtgraph ImageView 在多线程时冻结 [英] pyqtgraph ImageView Freezes when multithreaded

查看:118
本文介绍了pyqtgraph ImageView 在多线程时冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有多个通过 wifi 无线连接的摄像头,我正在尝试将数据流式传输到客户端,该客户端在 GUI 上显示流.

I have multiple cameras that are hooked up wirelessly via wifi and I'm trying to stream the data to a client, which displays the streams on a GUI.

我的问题是 pyqtgraph ImageItems 似乎在大约 30 秒后停止重新绘制,或者如果我单击窗口外,或者如果我调整其中一个图像的控件.之后,我可以通过调整窗口大小来设法重新绘制图像,但这有点乏味.

My issue is that the pyqtgraph ImageItems seem to stop repainting after about 30 seconds, or if I click out of the window, or if I adjust the controls on one of the images. After that, I can manage to get the images to repaint by resizing the window, but that's kind of tedious.

我想也许 pyqtgraph 不是线程安全的,但我什至不知道我是否在使用真正的线程,因为我必须让所有东西都通过 Qt (QThread) 来运行.

I thought maybe pyqtgraph wasn't threadsafe, but I don't even know if I'm using real threads, since I have to have everything run through Qt (QThread) to get things working.

我发现一些论坛帖子显示了与此类似的问题.第一个 重定向到here 解释说您可以使用名为 NSAppSleepDisabled 的东西,但这似乎只适用于 OSX,而​​我运行 Windows 10.第二个解释说他们的整个 GUI 冻结,我没有遇到这个问题,只有 ImageItem 冻结,GUI 的其余部分都是响应式的.

I have found a few forum posts that show similar problems to this. The first one which redirected to here explains that you can use something called NSAppSleepDisabled but that appears to be only on OSX and I'm running Windows 10. The second one explains that their entire GUI freezes, and I'm not having that problem, only the ImageItem freezes, the entire rest of the GUI is responsive.

这些是我的进口

import time
from multiprocessing import Queue
from threading import Lock
from queue import Empty

import pyqtgraph as pg
from PyQt5.QtCore import QThread

为了保持我的软件可扩展,我使用了工作线程来管理传入的图像数据,为了保持 ImageView 的线程安全,我添加了一个锁:

In order to keep my software expandable, I've used worker threads to manage incoming image data, in an attempt to keep the ImageView's threadsafe, I added a lock:

graph_lock = Lock()

class WindowUpdater(QThread):

    stop_q = Queue()

    def __init__(self, cam_q: Queue, img_control: pg.ImageView, **kwargs):
        super().__init__(**kwargs)
        self.q = cam_q
        self.c = img_control

    def run(self) -> None:
        while self.stop_q.empty():
            try:
                timg = self.q.get_nowait()
                graph_lock.acquire(True)
                self.c.setImage(timg.frame)
                self.c.invalidate()
                graph_lock.release()
            except Empty:
                time.sleep(0.1)

然后主应用程序处理将这些线程链接到传入数据

Then the main application handles linking these threads to the incoming data

app = QApplication(sys.argv)
window = QMainWindow()

grid = QGridLayout()
grid.setSpacing(10)
widg = QWidget()
widg.setLayout(grid)
window.setCentralWidget(widg)
window.show()

window.setGeometry(300, 300, 500, 400)
window.show()

threads = []

for i, h in enumerate(hosts):
    img = pg.ImageView(window)
    grid.addWidget(img, i, 0)

    img_item = pg.ImageItem()
    img.addItem(img_item)

    threads.append(WindowUpdater(img_queue, img)

for t in threads:
    t.start()

sys.exit(app.exec_())

其中 hosts 是用于连接的主机名列表,img_queue 是特定于该主机的相机流的多处理队列.

where hosts is a list of hostnames used to connect to, and img_queue is a multiprocessing Queue specific to that host's camera stream.

有人知道为什么同时运行多个 pyqtgraph ImageView 或 ImageItem 实例会导致问题吗?

Does anybody know why having multiple instances of pyqtgraph ImageView or ImageItem s running simultaneously causes problems here?

推荐答案

你不应该从另一个线程更新 GUI,因为 Qt 禁止它(1).所以你必须使用信号来传递信息.

You should not update the GUI from another thread since Qt forbids it (1). So you must use signals to transmit the information.

class WindowUpdater(QThread):
    imageChanged = pyqtSignal(np.ndarray)
    stop_q = Queue()

    def __init__(self, cam_q: Queue, **kwargs):
        super().__init__(**kwargs)
        self.q = cam_q

    def run(self) -> None:
        while self.stop_q.empty():
            try:
                timg = self.q.get_nowait()
                graph_lock.acquire(True)
                self.imageChanged.emit(timg.frame)
                graph_lock.release()
            except Empty:
                time.sleep(0.1)

# ...
for i, h in enumerate(hosts):
    img = pg.ImageView(window)
    grid.addWidget(img, i, 0)

    img_item = pg.ImageItem()
    img.addItem(img_item)
    thread = WindowUpdater(img_queue)
    thread.imageChanged.connect(img.setImage)
    threads.append(thread)
# ...

<小时>

(1) GUI 线程和工作线程

这篇关于pyqtgraph ImageView 在多线程时冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆