PyQtGraph:GUI只在一个进程中无响应

时间:2014-06-25 22:27:45

标签: pyqt pyqtgraph

我正在为摄像机编写GUI,它基本上可以在两种模式下运行,我称之为liveview和recordview。唯一的区别是我在后者录制,只在前者录制。

在实时查看模式下,图像会正确更新。我设置了一个触发记录视图的按钮,但在此次采集过程中,GUI无法响应,图像也无法更新。让我向您展示代码的相关部分:

import numpy as np
from PyQt4 import QtGui, QtCore
import pyqtgraph as pg
from lantz.drivers.andor.ccd import CCD

app = QtGui.QApplication([])

def updateview():     # <-- this works OK
    global img, andor
    img.setImage(andor.most_recent_image16(andor.detector_shape),
                 autoLevels=False)

def liveview():
    """ Image live view when not recording
    """
    global andor, img, viewtimer

    andor.acquisition_mode = 'Run till abort'
    andor.start_acquisition()
    viewtimer.start(0)

def UpdateWhileRec():
    global stack, andor, img, n, ishape

    j = 0
    while j < n:
        if andor.n_images_acquired > j:

            # Data saving    <-- this part (and the whole while-loop) works OK
            i, j = andor.new_images_index
            stack[i - 1:j] = andor.images16(i, j, ishape, 1, n)

            # Image updating <-- this doesn't work
            img.setImage(stack[j - 1], autoLevels=False)

    liveview()   # After recording, it goes back to liveview mode

def record(n):
    """ Record an n-frames acquisition
    """
    global andor, ishape, viewtimer, img, stack, rectimer

    andor.acquisition_mode = 'Kinetics'
    andor.set_n_kinetics(n)
    andor.start_acquisition()

    # Stop the QTimer that updates the image with incoming data from the
    # 'Run till abort' acquisition mode.
    viewtimer.stop()
    QtCore.QTimer.singleShot(1, UpdateWhileRec)

if __name__ == '__main__':

    with CCD() as andor:

        win = QtGui.QWidget()
        rec = QtGui.QPushButton('REC')
        imagewidget = pg.GraphicsLayoutWidget()
        p1 = imagewidget.addPlot()
        img = pg.ImageItem()
        p1.addItem(img)

        layout = QtGui.QGridLayout()
        win.setLayout(layout)
        layout.addWidget(rec, 2, 0)
        layout.addWidget(imagewidget, 1, 2, 3, 1)

        win.show()

        viewtimer = QtCore.QTimer()
        viewtimer.timeout.connect(updateview)

        # Record routine
        n = 100
        newimage = np.zeros(ishape)
        stack = np.zeros((n, ishape[0], ishape[1]))
        rec.pressed.connect(lambda: record(n))

        liveview()

        app.exec_()
        viewtimer.stop()

如您所见,UpdateWhileRec每次获取时只运行一次updateview,直到调用viewtimer.stop()为止。

我是PyQt和PyQtGraph的新手,所以无论解决我目前问题的具体方式如何,都可能有更好的方法来做其他事情。如果是这样的话请告诉我!

先谢谢

1 个答案:

答案 0 :(得分:1)

你的问题源于你需要将控制权返回给Qt事件循环才能重绘图片。由于您在等待下一个图像获取时仍然处于UpdateWhileRec回调状态,因此Qt永远不会有机会绘制图像。退出函数UpdateWhileRec后,它才有机会。

我建议进行以下更改。

然后代替UpdateWhileRec中的while循环,有一个QTimer定期调用当前while循环的内容(我可能建议使用单一计时器)。这样可以确保控制权返回到Qt,这样它就可以在检查图像之前绘制图像。

类似于:

def UpdateWhileRec():
    # Note, j should be initialised to 0 in the record function now
    global stack, andor, img, n, j, ishape 


    if andor.n_images_acquired > j:    
        # Data saving    <-- this part (and the whole while-loop) works OK
        i, j = andor.new_images_index
        stack[i - 1:j] = andor.images16(i, j, ishape, 1, n)

        # Image updating <-- this should now work
        img.setImage(stack[j - 1], autoLevels=False)

    if j < n:
        QTimer.singleShot(0, UpdateWhileRec)
    else:
        liveview()   # After recording, it goes back to liveview mode

注意,您应该将函数和变量放在类中,并创建类的实例(对象)。这样你就不必在任何地方调用global,而且事情更加封装。

最后,您可能想要查看您的oror库是否支持在新图像可用时(回调)注册要调用的函数,这将节省您执行此常量轮询和/或获取线程中的图像和将它们发布回要绘制的GUI线程。但是一步一步!