Python 将numpy数组转换为QImage时内存顺序行为问题
我在PyQt4中有一个简单的查看器,当从numpy数组(8位灰度)转换为QImage以显示时,我有一些奇怪的行为。在我看来,当我试图从一个转置的数组构造一个QImage时,似乎有些事情正在失控,即使内存顺序应该已经更新(也就是说,它不仅仅是一个步幅不同的视图) 以下是该查看器的大幅精简版本:Python 将numpy数组转换为QImage时内存顺序行为问题,python,numpy,pyqt4,Python,Numpy,Pyqt4,我在PyQt4中有一个简单的查看器,当从numpy数组(8位灰度)转换为QImage以显示时,我有一些奇怪的行为。在我看来,当我试图从一个转置的数组构造一个QImage时,似乎有些事情正在失控,即使内存顺序应该已经更新(也就是说,它不仅仅是一个步幅不同的视图) 以下是该查看器的大幅精简版本: import numpy as np from PyQt4 import QtGui class SimpleViewer(QtGui.QMainWindow): def __init__(se
import numpy as np
from PyQt4 import QtGui
class SimpleViewer(QtGui.QMainWindow):
def __init__(self, data, parent=None):
super(SimpleViewer, self).__init__(parent=parent)
hgt, wid = data.shape
dmin = data.min()
dmax = data.max()
bdata = ((data - dmin)/(dmax - dmin)*255).astype(np.uint8)
img = QtGui.QImage(bdata, wid, hgt, QtGui.QImage.Format_Indexed8)
self.scene = QtGui.QGraphicsScene(0, 0, wid, hgt)
self.px = self.scene.addPixmap(QtGui.QPixmap.fromImage(img))
self.view = QtGui.QGraphicsView(self.scene)
self.setCentralWidget(self.view)
if __name__ == "__main__":
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication(['python'])
xx, yy = np.meshgrid(np.arange(-100,100), np.arange(350))
zz = xx * np.cos(yy/350.*6*np.pi)
viewer = SimpleViewer(zz)
viewer.show()
app.exec_()
现在,这产生了类似这样的东西,这很好:
但是,我需要查看真实图像,第一个维度为“x”,第二个维度为“y”,因此需要进行转置(加上y翻转,使原点位于左下方,但这超出了本文的范围)
如果我将hgt,wid=data.shape
更改为wid,hgt=data.shape
并且不做任何其他事情(这是错误的),我会得到以下结果。这是有道理的,因为QImage只是读取内存
但是,如果我也传入bdata.T.copy()
而不是bdata
,我希望数组将被转置,内存将通过复制操作重新排序。但我得到的是:
它离得很近,但由于某种原因只差一根头发。此外,我注意到,如果维度恰好是彼此的整数倍(例如200x100),那么结果就可以了。发生了什么事我是不是错过了一些非常愚蠢的事情?
我不知道这是PyQt问题还是numpy问题。。。使用matplotlib可以很好地绘制转置数组,但matplotlib可以处理跨距,因此这可能没有任何意义
我在Python2.7和Python3.5中得到了相同的行为。PyQt4版本是4.11.4,使用Qt版本4.8.7。Numpy版本是1.10.1。这个问题源于
QImage
的创建
img = QtGui.QImage(bdata, wid, hgt, QtGui.QImage.Format_Indexed8)
您正在使用的构造函数的签名的
。。。数据必须是32位对齐的,并且图像中的每个数据扫描线也必须是32位对齐的
如果更改数组的尺寸使其32位对齐(例如使用xx,yy=np.meshgrid(np.arange(-128128),np.arange(384))
,则代码工作正常
要更正此问题,而不需要每行32字节的倍数,您需要对QImage
使用一个稍微小的:
QImage(data, width, height, bytesPerLine, format)
在您的情况下,这很简单:
img = QtGui.QImage(bdata, wid, hgt, wid, QtGui.QImage.Format_Indexed8)
因为每个像素包含1字节的信息。Whoa。出于某种原因,我必须停止读取“数据必须是32位对齐的”,并且完全错过了“并且每个扫描线也必须是32位对齐的”。仔细阅读文档的课程。。。