在 Qt 中显示 matplotlib imshow 输出
show matplotlib imshow output in Qt
我有一个 np.float64 类型的二维 numpy 数组,我想在 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()
的结果是:
而 myLabel
显示以下结果:
那么,我的代码有什么问题?
是否有更优雅的方式将我的 2D numpy 数组显示为图像?
据我所知,OP 有一个 XY problem,也就是说,它的 objective 是在 Qt window 中显示 imshow() 的输出,但询问尝试在 QImage 中显示数据。
imshow()方法不显示原始数据,而是根据文档指示的参数处理信息:
matplotlib.pyplot.imshow(X, cmap=None, norm=None, aspect=None,
interpolation=None, alpha=None, vmin=None, vmax=None, origin=None,
extent=None, shape=, filternorm=1,
filterrad=4.0, imlim=, resample=None, url=None,
*, data=None, **kwargs)
所以如果你想用那个数据得到一个图像你必须实现那个算法(你可以查看matplotlib或类似软件的源代码来分析逻辑)
如果我们关注真正的objective那么最简单的解决方案是使用matplotlib的Qt后端来获取合适的canvas如下所示:
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_())
更新:
如果您想不时显示数据,那么您可以使用 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_())
另一方面,如果您想实时使用 SW,那么 GUI 会限制 objective。建议每 N 个样本显示一次数据,这样 GUI 就不会被阻塞,用户可以查看和分析信息。人眼非常慢,所以即使存在每微秒显示图像的技术,我们的视觉也不会欣赏它,我们的视觉需要 60 毫秒来处理图像,因此设备设计为工作在 30Hz,因为如果频率更高不会观察到改善。
我有一个 np.float64 类型的二维 numpy 数组,我想在 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()
的结果是:
而 myLabel
显示以下结果:
那么,我的代码有什么问题?
是否有更优雅的方式将我的 2D numpy 数组显示为图像?
据我所知,OP 有一个 XY problem,也就是说,它的 objective 是在 Qt window 中显示 imshow() 的输出,但询问尝试在 QImage 中显示数据。
imshow()方法不显示原始数据,而是根据文档指示的参数处理信息:
matplotlib.pyplot.imshow(X, cmap=None, norm=None, aspect=None, interpolation=None, alpha=None, vmin=None, vmax=None, origin=None, extent=None, shape=, filternorm=1, filterrad=4.0, imlim=, resample=None, url=None, *, data=None, **kwargs)
所以如果你想用那个数据得到一个图像你必须实现那个算法(你可以查看matplotlib或类似软件的源代码来分析逻辑)
如果我们关注真正的objective那么最简单的解决方案是使用matplotlib的Qt后端来获取合适的canvas如下所示:
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_())
更新:
如果您想不时显示数据,那么您可以使用 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_())
另一方面,如果您想实时使用 SW,那么 GUI 会限制 objective。建议每 N 个样本显示一次数据,这样 GUI 就不会被阻塞,用户可以查看和分析信息。人眼非常慢,所以即使存在每微秒显示图像的技术,我们的视觉也不会欣赏它,我们的视觉需要 60 毫秒来处理图像,因此设备设计为工作在 30Hz,因为如果频率更高不会观察到改善。