Matplotlib, refresh image with imshow faster

2019-07-15 07:25发布

I am working on a project on which I have to plot an image of 320*250 pixels and this 60 times per second if possible, on a window of a GUI. So I try to do this with matplotlib 2.0.2, Python 3.6 and PyQt5 (because I begin to know these tools and work on another project with this), in the following way :

import sys, random, matplotlib
from PyQt5 import QtCore, QtGui, QtWidgets

matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt

class SecondWindow(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(SecondWindow, self).__init__(parent)
        self.setupUi(self)

    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(800, 600)

        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)
        self.axes = self.figure.add_subplot(111)

        self.setLayout(QtWidgets.QVBoxLayout())
        self.layout().addWidget(self.canvas)

        self.initialisationFigure()

        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self.majFigure)
        self.timer.start(16)

        self.timer2 = QtCore.QTimer(self)
        self.timer2.timeout.connect(self.NumberRefreshPerSecond)
        self.timer2.start(1000)

    def NumberRefreshPerSecond(self):
        print(self.count)
        self.count = 0

    def majFigure(self):
        self.count = self.count + 1
        self.plot.set_data([[random.random() for x in range(1, 320)] for y in range(1, 250)])
        # self.canvas.draw()
        self.axes.draw_artist(self.axes.patch)
        self.axes.draw_artist(self.plot)
        self.canvas.update()
        self.canvas.flush_events()

    def initialisationFigure(self):
        self.plot = self.axes.imshow([[random.random() for x in range(1,320)] for y in range(1,250)], interpolation='none')
        self.count = 0
        self.canvas.draw()

    def closeEvent(self, event):
        self.timer.stop()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    form = SecondWindow()
    form.show()
    sys.exit(app.exec_())

I optimized like I can turning off the interpolation, and drawing only once the figure, but with this code the program refresh the figure only 20 times per second whereas the timer is correctly set to 16ms (1/60Hz).

I hope someone can help me giving me some clues to improve my code. I thank you in advance a lot !

1条回答
家丑人穷心不美
2楼-- · 2019-07-15 08:04

Matplotlib produces publication quality plots but unfortunately it's not quite suitable for real-time plotting and videos.

If it's not a strict requirement, consider using pyqtgraph module. It plays well with pyqt5 and designed to cover shortcomings of matplotlib, especially in real-time area:

If you are doing anything requiring rapid plot updates, video, or realtime interactivity, matplotlib is not the best choice. This is (in my opinion) matplotlib's greatest weakness

(from pyqtgraph site)

It also got additional (optional) features like Region-of-Interest, normalization and histogram plotting.

This code can produce ~160 FPS (with histogram disabled) on my laptop:

import sys, random, matplotlib
from PyQt5 import QtCore, QtGui, QtWidgets

import pyqtgraph as pg
import numpy as np


class SecondWindow(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(SecondWindow, self).__init__(parent)
        self.setupUi(self)

    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(800, 600)

        self.im_widget = pg.ImageView(self)
        # uncomment to hide histogram
        # self.im_widget.ui.histogram.hide()

        self.setLayout(QtWidgets.QVBoxLayout())
        self.layout().addWidget(self.im_widget)

        self.initialisationFigure()

        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self.majFigure)
        self.timer.start(16)

        self.timer2 = QtCore.QTimer(self)
        self.timer2.timeout.connect(self.NumberRefreshPerSecond)
        self.timer2.start(1000)

    def NumberRefreshPerSecond(self):
        print(self.count)
        self.count = 0

    def majFigure(self):
        self.count = self.count + 1
        # numpy random.rand also much faster than list comprehension
        data = np.random.rand(320, 250)
        self.im_widget.setImage(data)

    def initialisationFigure(self):
        self.count = 0
        self.im_widget.show()

    def closeEvent(self, event):
        self.timer.stop()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    form = SecondWindow()
    form.show()
    sys.exit(app.exec_())
查看更多
登录 后发表回答