将numpy数组绘制到QWidg中时出现问题

2024-09-30 08:16:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试编写一个预览小部件,它能够显示2dnumpy数组图像。 这个小部件有一个固定的大小(正方形),但是图像可以有任何形状。在

它似乎适用于某些图像形状,但对于其他形状,它显示无意义;对于其他一些形状,它崩溃时没有任何错误消息。在

你看到我的代码有明显的错误吗?在

from silx.gui import qt
import numpy


GRAY_COLORTABLE = []
for i in range(256):
    GRAY_COLORTABLE.append(qt.qRgb(i, i, i))


class PreviewImageWidget(qt.QWidget):
    """Preview image"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.pixmap = qt.QPixmap()
        self.setFixedSize(350, 350)

    def paintEvent(self, event):
        painter = qt.QPainter(self)
        painter.drawPixmap(self.rect(), self.pixmap)

    def setImage(self, img_array):
        # TODO : adjust colortable to actual dtype (autoscale to min - max ??)
        if img_array is None:
            self.pixmap = qt.QPixmap()
        else:
            if img_array.dtype != numpy.uint8:
                max_value = img_array.max()
                img_array = 256. / max_value * img_array
                img_array = img_array.astype(numpy.uint8)

            # binary images are of dtype uint8
            if img_array.max() == 1:
                img_array = img_array * 255
            image = qt.QImage(img_array,
                              img_array.shape[1], img_array.shape[0],
                              qt.QImage.Format_Indexed8)
            image.setColorTable(GRAY_COLORTABLE)
            self.pixmap = qt.QPixmap.fromImage(image)

        self.update()

if __name__ == '__main__':

    app = qt.QApplication([])
    allPreviewWidgets = []

    for sh in [(610, 500), (450, 700), (550, 600),
               (500, 500), (510, 500), (500, 520)]:
        img_array = numpy.zeros(sh, dtype=numpy.uint8)
        img_array[200:350, 250:300] = 1

        previewWidget = PreviewImageWidget()
        previewWidget.setWindowTitle(str(img_array.shape))
        previewWidget.show()
        previewWidget.setImage(img_array)
        allPreviewWidgets.append(previewWidget)

    app.exec_()

enter image description here 几乎是正方形的形状不起作用。长方形的很好用。 在QPainter的文档中,它说:

Note: The image is scaled to fit the rectangle, if both the image and rectangle size disagree.

使程序崩溃的形状示例:(2000500)

编辑:这是另一个例子,显示了同样的问题,没有qpaint,也没有调整pixmap的大小。我认为这将缩小到QImage如何解码numpy数组的问题。在

^{pr2}$

Tags: 图像imageselfnumpyimgifqtarray
2条回答

如果有人在我的第一个例子中遇到同样的问题,这就是我必须要做的事情。在

import numpy
from silx.gui import qt

GRAY_COLORTABLE = [qt.qRgb(i, i, i) for i in range(256)]


class PreviewImageWidget(qt.QLabel):
    """Image preview widget. Displays the image in
    a 2D numpy array with a grayscale colortable.
    """
    def __init__(self, parent=None):
        super().__init__(parent)

        self.size = qt.QSize(150, 150)
        self.setSize(self.size)
        self.pixmap = qt.QPixmap()

    def setSize(self, size):
        self.size = size
        self.setFixedSize(self.size)

    def setImage(self, img_array):
        if img_array is None:
            # null pixmap
            self.pixmap = qt.QPixmap()
        else:
            img_array = img_array.copy()
            bytesPerLine = img_array.strides[0]
            if img_array.dtype != numpy.uint8:
                max_value = img_array.max()
                img_array = 256. / max_value * img_array
                img_array = img_array.astype(numpy.uint8)

            height, width = img_array.shape
            image = qt.QImage(img_array,
                              width, height,
                              bytesPerLine,
                              qt.QImage.Format_Indexed8)
            image.setColorTable(GRAY_COLORTABLE)

            pixmap = qt.QPixmap.fromImage(image)
            self.pixmap = pixmap.scaled(self.size,
                                        qt.Qt.KeepAspectRatio)
        self.setPixmap(self.pixmap)


if __name__ == '__main__':

    app = qt.QApplication([])
    allPreviewWidgets = []

    for sh in [(610, 500), (450, 700), (550, 600),
               (500, 500), (510, 500), (500, 520)]:
        img_array = numpy.zeros(sh, dtype=numpy.uint8)
        img_array[200:350, 250:300] = 255

        previewWidget = PreviewImageWidget()
        previewWidget.setSize(qt.QSize(300, 300))
        previewWidget.setWindowTitle(str(img_array.shape))
        previewWidget.show()
        previewWidget.setImage(img_array)
        allPreviewWidgets.append(previewWidget)

    app.exec_()

在这种情况下,复制数组以确保它在内存中是连续的似乎有帮助,而复制QImage似乎没有必要。在

在我的应用程序PyQt5.13之前,由于一个未知的原因,我的应用程序甚至失败了。我希望这些都是与当前版本的Qt相关的bug,并且它将在下一个版本中得到修复。在

我只能在第二种情况下重现问题,我发现问题在于内存,因为在所有转换中都使用同一个对象,在某些情况下,内存会被消除,所以解决方案是复制数据:

from PySide2 import QtCore, QtGui, QtWidgets
import numpy

GRAY_COLORTABLE = []
for i in range(256):
    GRAY_COLORTABLE.append(QtGui.qRgb(i, i, i))


def array2qpixmap(img_array):
    height, width = img_array.shape
    bytesPerLine, _ = img_array.strides
    image = QtGui.QImage(
        img_array.data.tobytes(),
        width,
        height,
        bytesPerLine,
        QtGui.QImage.Format_Indexed8,
    )
    image.setColorTable(GRAY_COLORTABLE)
    return QtGui.QPixmap.fromImage(image.copy())


if __name__ == "__main__":

    app = QtWidgets.QApplication([])
    labels = []

    for sh in [
        (610, 500),
        (450, 700),
        (550, 600),
        (500, 500),
        (510, 500),
        (200, 520),
    ]:
        img_array = numpy.zeros(sh, dtype=numpy.uint8)
        img_array[200:350, 250:300] = 255
        lab = QtWidgets.QLabel()
        lab.resize(700, 700)
        lab.setWindowTitle(str(sh))
        lab.show()
        lab.setPixmap(array2qpixmap(img_array.copy()))
        labels.append(lab)

    app.exec_()

相关问题 更多 >

    热门问题