показать вывод matplotlib imshow в Qt - PullRequest
2 голосов
/ 23 февраля 2020

У меня есть массив 2D numpy типа np.float64, и я хочу показать его как изображение в QLabel (или любым другим допустимым способом):

self.img = np.rot90(get_my_data()) # this line returns a 2D numpy array of type np.float64
self.qimg = QtGui.QImage(self.img, self.img.shape[0], self.img.shape[1], QtGui.QImage.Format_Grayscale8)
self.myLabel.setPixmap(QtGui.QPixmap(self.qimg))

Мой код выше возврата следующая ошибка:

TypeError: arguments did not match any overloaded call:
QImage(): too many arguments
QImage(QSize, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(bytes, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(sip.voidptr, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(bytes, int, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(sip.voidptr, int, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(List[str]): argument 1 has unexpected type 'numpy.ndarray'
QImage(str, format: str = None): argument 1 has unexpected type 'numpy.ndarray'
QImage(QImage): argument 1 has unexpected type 'numpy.ndarray'
QImage(Any): too many arguments

Но, если я добавлю .copy() в конце первой строки, то это сработает! но данные отображаются неправильно.

self.img = np.rot90(get_my_data()).copy()
self.qimg = QtGui.QImage(self.img, self.img.shape[0], self.img.shape[1], QtGui.QImage.Format_Grayscale8)
self.myLabel.setPixmap(QtGui.QPixmap(self.qimg))

Вот что отображает метка по сравнению с pyplot.imshow():

self.img = 20 * np.log10(np.rot90(get_my_data()).copy())
self.qimg = QtGui.QImage(self.img, self.img.shape[0], self.img.shape[1], QtGui.QImage.Format_Grayscale8)
self.myLabel.setPixmap(QtGui.QPixmap(self.qimg))
pyplot.imshow(self.img)
pyplot.show()

Результат pyplot.imshow():

enter image description here

В то время как myLabel отображает следующий результат:

enter image description here

Итак, что не так с моим кодом?

Есть ли более элегантный способ отображения массива 2D numpy в виде изображения?

1 Ответ

2 голосов
/ 23 февраля 2020

Из того, что я прочитал, у OP есть проблема XY , то есть его цель - показать вывод imshow () в окне Qt, но спросить о попытке отобразить данные в QImage.

Метод imshow () не показывает необработанные данные, но обрабатывает информацию на основе параметров, указанных в документах:

matplotlib.pyplot .imshow (X, cmap = Нет, норма = Нет, аспект = Нет, интерполяция = Нет, альфа = Нет, vmin = Нет, vmax = Нет, источник = Нет, экстент = Нет, форма =, filternorm = 1, filterrad = 4.0, imlim =, resample = Нет, url = Нет, *, data = None, ** kwargs)

Поэтому, если вы хотите получить изображение с этими данными, вы должны реализовать этот алгоритм (вы можете проверить исходный код matplotlib или аналогичного ПО для анализа логи c)

Если мы сосредоточимся на реальной цели, то самое простое решение - использовать Qt-интерфейс matplotlib для получения соответствующего холста, как показано ниже:

import numpy as np

from PyQt5 import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.figure = Figure(figsize=(5, 3))
        self.canvas = FigureCanvas(self.figure)
        self.ax = self.figure.subplots()

        delta = 0.025
        x = y = np.arange(-3.0, 3.0, delta)
        X, Y = np.meshgrid(x, y)
        Z1 = np.exp(-(X ** 2) - Y ** 2)
        Z2 = np.exp(-((X - 1) ** 2) - (Y - 1) ** 2)
        Z = (Z1 - Z2) * 2

        self.ax.imshow(Z)
        self.ax.set_axis_off()

        self.setCentralWidget(self.canvas)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()

    sys.exit(app.exec_())

enter image description here

Обновление:

Если вы хотите отображать данные время от времени, вы можете использовать QTimer, который обновляет информацию, как показано ниже:

import random
import numpy as np

from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.figure = Figure(figsize=(5, 3))
        self.canvas = FigureCanvas(self.figure)
        self.ax = self.figure.subplots()
        self.ax.set_axis_off()

        self.setCentralWidget(self.canvas)

        timer = QtCore.QTimer(self)
        timer.timeout.connect(self.on_timeout)
        timer.start(100)

    def on_timeout(self):
        x0, y0 = random.uniform(-2, 2), random.uniform(-2, 2)
        delta = 0.025
        x = y = np.arange(-3.0, 3.0, delta)
        X, Y = np.meshgrid(x, y)
        Z1 = np.exp(-(X ** 2) - Y ** 2)
        Z2 = np.exp(-((X - x0) ** 2) - (Y - y0) ** 2)
        Z = (Z1 - Z2) * 2
        self.ax.imshow(Z)
        self.canvas.draw()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()

    sys.exit(app.exec_())

С другой стороны Если вы хотите иметь ПО в режиме реального времени, то GUI ограничит эту цель. Желательно показывать данные каждые N выборок, чтобы GUI не блокировался, и пользователь мог просматривать и анализировать информацию. Человеческий глаз очень медленный, поэтому, даже если существует технология для отображения изображений каждую микросекунду, наше зрение не оценило бы это, нашему зрению требуется 60 мс для обработки изображения, поэтому устройства рассчитаны на работу с частотой 30 Гц, поскольку, если бы частота была выше улучшения не будет наблюдаться.

...