Matplotlib, обновите изображение с imshow быстрее

Я работаю над проектом, в котором мне нужно нанести изображение размером 320*250 пикселей и, если возможно, 60 раз в секунду в окне графического интерфейса пользователя. Поэтому я пытаюсь сделать это с помощью matplotlib 2.0.2, Python 3.6 и PyQt5 (потому что я начинаю знать эти инструменты и работаю над этим с другим проектом) следующим образом:

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

Я оптимизировал так, как могу отключить интерполяцию и рисовать только один раз фигуру, но с помощью этого кода программа обновляет фигуру только 20 раз в секунду, тогда как таймер правильно установлен на 16 мс (1/60 Гц).

Я надеюсь, что кто-то может помочь мне дать некоторые подсказки, чтобы улучшить мой код. Заранее большое спасибо!

1 ответ

Решение

Matplotlib производит графики качества публикации, но, к сожалению, она не совсем подходит для печати в реальном времени и видео.

Если это не строгое требование, рассмотрите возможность использования pyqtgraph модуль. Он хорошо работает с pyqt5 и предназначен для покрытия недостатков matplotlibособенно в области реального времени:

Если вы делаете что-либо, требующее быстрых обновлений сюжета, видео или интерактивности в реальном времени, matplotlib - не лучший выбор. Это (на мой взгляд) самая большая слабость Matplotlib

(from pyqtgraph site)

Он также получил дополнительные (дополнительные) функции, такие как область интересов, нормализация и построение гистограммы.

Этот код может выдавать ~160 FPS (с отключенной гистограммой) на моем ноутбуке:

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_())
Другие вопросы по тегам