簡體   English   中英

在Python 3中重現Python 2 PyQt4 QImage構造函數的行為

[英]Reproduce Python 2 PyQt4 QImage constructor behavior in Python 3

我使用PyQt4編寫了一個小的GUI,該GUI顯示圖像並獲取用戶單擊的點坐標。 我需要將2D numpy數組顯示為灰度,因此我要從該數組創建一個QImage,然后從該數組創建一個QPixmap。 在Python 2中,它工作正常。

但是,當我轉向Python 3時,它無法決定QImage的構造函數-它給了我以下錯誤:

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(str, 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(str, 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-of-str): argument 1 has unexpected type 'numpy.ndarray'
  QImage(str, str format=None): argument 1 has unexpected type 'numpy.ndarray'
  QImage(QImage): argument 1 has unexpected type 'numpy.ndarray'
  QImage(object): too many arguments

據我所知,我之前調用的QImage構造函數就是其中之一:

  • QImage(str, int, int, QImage.Format)
  • QImage(sip.voidptr, int, int, QImage.Format)

我假設一個numpy數組適合其中之一所需的協議之一。 我在想它可能與數組而不是視圖有關,但是我嘗試過的所有變化都會產生上述錯誤,或者只是使GUI退出而無所事事。 如何在Python 3中重現Python 2的行為?

以下是一個小示例,其中相同的確切代碼在Python 2下可以正常工作,但在Python 3下卻不能正常工作:

from __future__ import (print_function, division)

from PyQt4 import QtGui, QtCore
import numpy as np

class MouseView(QtGui.QGraphicsView):

    mouseclick = QtCore.pyqtSignal(tuple)

    def __init__(self, scene, parent=None):
        super(MouseView, self).__init__(scene, parent=parent)

    def mousePressEvent(self, event):
        self.mouseclick.emit((event.x(),
                              self.scene().sceneRect().height() - event.y()))


class SimplePicker(QtGui.QDialog):

    def __init__(self, data, parent=None):
        super(SimplePicker, self).__init__(parent)

        mind = data.min()
        maxd = data.max()
        bdata = ((data - mind) / (maxd - mind) * 255.).astype(np.uint8)

        wdims = data.shape
        wid = wdims[0]
        hgt = wdims[1]

        # This is the line of interest - it works fine under Python 2, but not Python 3
        img = QtGui.QImage(bdata.T, wid, hgt,
                           QtGui.QImage.Format_Indexed8)

        self.scene = QtGui.QGraphicsScene(0, 0, wid, hgt)
        self.px = self.scene.addPixmap(QtGui.QPixmap.fromImage(img))

        view = MouseView(self.scene)
        view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        view.setSizePolicy(QtGui.QSizePolicy.Fixed,
                           QtGui.QSizePolicy.Fixed)
        view.setMinimumSize(wid, hgt)
        view.mouseclick.connect(self.click_point)

        quitb = QtGui.QPushButton("Done")
        quitb.clicked.connect(self.quit)

        lay = QtGui.QVBoxLayout()
        lay.addWidget(view)
        lay.addWidget(quitb)

        self.setLayout(lay)

        self.points = []

    def click_point(self, xy):
        self.points.append(xy)

    def quit(self):
        self.accept()


def test_picker():

    x, y = np.mgrid[0:100, 0:100]
    img = x * y

    app = QtGui.QApplication.instance()
    if app is None:
        app = QtGui.QApplication(['python'])

    picker = SimplePicker(img)
    picker.show()
    app.exec_()

    print(picker.points)

if __name__ == "__main__":
    test_picker()

我在Windows 7 64位,Qt 4.8.7,PyQt 4.10.4,numpy 1.9.2上使用Anaconda安裝。

在上面的PyQt構造函數中,從名為bdata的Numpy數組中觀察到以下行為:

  • bdata對於Python 2和Python 3均正常工作
  • bdata.T適用於2,而不適用於3(構造函數錯誤)
  • bdata.T.copy()對兩個都適用
  • bdata[::-1,:]不適用於2或3(相同的錯誤)
  • bdata[::-1,:].copy()都適用
  • bdata[::-1,:].base兩者均可使用,但會丟失反向操作的結果

正如@ekhumoro在評論中提到的那樣,您需要一些支持Python 緩沖區協議的東西。 這里感興趣的實際Qt構造函數是 QImage構造函數或它的const版本:

QImage(uchar * data, int width, int height, Format format)

根據此處保存的PyQt 4.10.4文檔,PyQt對unsigned char *期望在Python 2和3中有所不同:

Python 2:

如果Qt期望使用char * ,有signed char *unsigned char * (或const版本),則PyQt4將接受unicode或QString,其中僅包含ASCII字符,str,QByteArray或實現緩沖協議Python對象

Python 3:

如果Qt期望帶signed char *unsigned char * (或const版本),則PyQt4將接受一個bytes

Numpy 數組滿足這兩個條件,但顯然Numpy 視圖都不滿足。 實際上令人困惑的是bdata.T在Python 2中bdata.T工作,因為它據稱返回了一個視圖:

>>> a = np.ones((2,3))
>>> b = a.T
>>> b.base is a
True

最終答案:如果需要進行轉換以生成視圖,則可以通過將結果的copy()到新數組以傳遞到構造函數中來避免錯誤。 這可能不是最佳答案,但它會起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM