pyqtgraph ImageView Freezes when multithreaded

为君一笑 提交于 2021-01-28 04:09:45

问题


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.

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.

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.

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.

These are my imports

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

import pyqtgraph as pg
from PyQt5.QtCore import QThread

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

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.

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


回答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 Thread and Worker Thread



来源:https://stackoverflow.com/questions/57012643/pyqtgraph-imageview-freezes-when-multithreaded

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!