问题
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