Python 将numpy数组转换为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

我在PyQt4中有一个简单的查看器,当从numpy数组(8位灰度)转换为QImage以显示时,我有一些奇怪的行为。在我看来,当我试图从一个转置的数组构造一个QImage时,似乎有些事情正在失控,即使内存顺序应该已经更新(也就是说,它不仅仅是一个步幅不同的视图)

以下是该查看器的大幅精简版本:

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位对齐的”。仔细阅读文档的课程。。。