【问题标题】:How do I output a colormap in a scene using pyqt?如何使用 pyqt 在场景中输出颜色图?
【发布时间】:2016-05-28 12:01:26
【问题描述】:

TL;DR:您只需要阅读“更新”部分。

如何将numpy.random.random((256, 256)) 作为颜色图输出到 qt 场景?

这是摘要的摘要。

更新:

以下内容为我提供了我想要保存到文件的颜色图。

scaled_image = Image.fromarray(np.uint8(self.image*255))
plt.savefig("/home/test.png")

self.image 是 256x256 的 numpy 数组,它的所有值都在 -1 和 1 之间。

如何在 Qt 中将此图像输出到场景中?你可以使用self.image = numpy.random.random((256, 256)) 有一个和我类似的起点。如何将 2D numpy 随机值数组作为颜色图放到 pyqt 场景中?


24/02/1016 更新

如此接近。这似乎有效,但规模已经倒转。蓝色现在很热,红色很冷。如何切换它以使其看起来像上图?

    scene = QGraphicsScene(self)
    scaled_image = Image.fromarray(np.uint8(self.image*255))
    gcf().canvas.draw() # IMPORTANT!
    stringBuffer = gcf().canvas.buffer_rgba() # IMPORTANT!
    l, b, w, h = gcf().bbox.bounds
    qImage = QtGui.QImage(stringBuffer,
                  w,
                  h,
                  QtGui.QImage.Format_ARGB32)
    pixmap = QtGui.QPixmap.fromImage(qImage)
    pixmapItem = QtGui.QGraphicsPixmapItem(pixmap)
    scene.addItem(pixmapItem)
    self.graphicsView.setScene(scene)

我在 2016 年 2 月 23 日尝试了什么

下面给了我一个空白屏幕

    scene = QGraphicsScene(self)
    scaled_image = Image.fromarray(np.uint8(self.image*255))
    pixMap = QPixmap(scaled_image)
    scene.addPixmap(pixMap)
    self.graphicsView.setScene(scene)

下面给我一个灰度输出到 Qt 场景。为什么不是彩色的?

scene = QGraphicsScene(self)
scaled_image = Image.fromarray(np.uint8(self.image*255))
imgQ = ImageQt(scaled_image)
pixMap = QtGui.QPixmap.fromImage(imgQ)
scene.addPixmap(pixMap)
self.graphicsView.setScene(scene)

我从颜色图问题here 的解决方案进行逆向工程并显示图像here

使用已发布解决方案的建议,我尝试先创建一个QGraphicsPixmapItem,然后将该项目添加到场景中。官方文档有点混乱,所以我终于从更清晰的pyside docs 中得到了我需要的东西。可悲的是,我得到了与上面相同的灰度。代码如下:

    scene = QGraphicsScene(self)
    scaled_image = Image.fromarray(np.uint8(self.image*255))
    imgQ = ImageQt(scaled_image)
    pixMap = QtGui.QPixmap.fromImage(imgQ)
    pixMapItem = QtGui.QGraphicsPixmapItem(pixMap)
    scene.addItem(pixMapItem)
    self.graphicsView.setScene(scene)

我尝试过的其他事情(旧):

self.image 是 numpy 二维数组,它的所有值都在 -1 和 1 之间。

我按如下缩放并得到灰度图像。但是,我想要一个颜色图:

    scene = QGraphicsScene(self)
    scaled_image = (self.image + 1) * (255 / 2)    
    scene.addPixmap(QPixmap.fromImage(qimage2ndarray.array2qimage(scaled_image)))
    self.graphicsView.setScene(scene)

#min(self.image) = -0.64462
#max(self.image) = 1.0

如果我改为执行以下操作,我会得到我想要的颜色图,例如我之前开发的 Web 应用程序的下图中

>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> imgplot = ax.imshow(self.image)

如何将颜色图添加到 qt 场景,而不仅仅是灰度?

【问题讨论】:

    标签: python qt matplotlib pyqt4


    【解决方案1】:

    QPixmap 支持大于 255 和multiple image formats 的颜色值。如果不是这样,Qt 中的所有图标都会被灰度化(显然不是这样;))。

    你可以用任何你想做的方式生成你的颜色图(之前(使用 OpenCV 和 numpy)或在将其转换为 QImage(使用 Qt)之后),将其转换为 QPixmap 和使用QGraphicsPixmapItem(不要直接使用QPixmap作为QGraphicScene的一部分)将其附加到您的QGraphicsScene

    编辑: 我误读了文档。您实际上可以通过使用addPixmap() 在QGraphicScene 中直接使用QPixmap。对于那个很抱歉。作为道歉,这里有一些代码给你。 :P

    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    
    class ImageView(QGraphicsView):
      def __init__(self, pixmap=None, parent=None):
        '''
        QGraphicsView shows the image
        '''
        super(ImageView, self).__init__(parent)
        self.pixmap = pixmap
    
    
    class Widget(QWidget):
      def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        layout = QVBoxLayout(self)
        pic = QPixmap('/home/-----/Pictures/7 Cat Sins - Wrath.jpg')
        grview = ImageView(pic, self)
        layout.addWidget(grview)
        self.setFixedSize(pic.size())
    
        scene = QGraphicsScene(self)
        scene.addPixmap(pic)
    
        grview.setScene(scene)
        self.show()
    
    def main():
      app = QApplication(sys.argv)
      w = Widget()
    
      return sys.exit(app.exec_())
    
    if __name__ == '__main__':
      main()
    

    它产生以下结果:

    图片来源:在 Google 上寻找 7 Cat Sins - Wrath ;)

    基本上,您创建一个图像查看器,创建场景图,将像素图添加到场景图中,将图像查看器的场景设置为该图并使用该查看器在屏幕上显示像素图。

    EDIT2: 好的,看来您在matplotlib 的实际集成方面遇到了问题。以下是你的做法(取自here,对gcf().canvas.buffer_rgba()稍作改动):

    import numpy as np
    from matplotlib import use
    use('AGG')
    from matplotlib.pylab import *
    from PySide import QtCore,QtGui
    # Following are used for the generation of the image but you have your own imports so you don't need them
    from matplotlib.transforms import Bbox
    from matplotlib.path import Path
    from matplotlib.patches import Rectangle    
    
    # Generation of the figure (you can skip all that and use your stuff)
    rect = Rectangle((-1, -1), 2, 2, facecolor="#aaaaaa")
    gca().add_patch(rect)
    bbox = Bbox.from_bounds(-1, -1, 2, 2)
    
    for i in range(12):
        vertices = (np.random.random((4, 2)) - 0.5) * 6.0
        vertices = np.ma.masked_array(vertices, [[False, False], [True, True], [False, False], [False, False]])
        path = Path(vertices)
        if path.intersects_bbox(bbox):
            color = 'r'
        else:
            color = 'b'
        plot(vertices[:,0], vertices[:,1], color=color)
    
    # The conversion and display of the plot
    app = QtGui.QApplication(sys.argv)
    gcf().canvas.draw() # IMPORTANT!
    
    stringBuffer = gcf().canvas.buffer_rgba() # IMPORTANT!
    l, b, w, h = gcf().bbox.bounds
    
    qImage = QtGui.QImage(stringBuffer, 
                          w,
                          h,
                          QtGui.QImage.Format_ARGB32)
    
    scene = QtGui.QGraphicsScene()
    view = QtGui.QGraphicsView(scene)
    pixmap = QtGui.QPixmap.fromImage(qImage)
    pixmapItem = QtGui.QGraphicsPixmapItem(pixmap)
    scene.addItem(pixmapItem)
    view.show()
    
    app.exec_()
    

    编辑 3: 对于您的反转颜色图问题,请参阅 here (documentation)here (SO)

    PS:我建议您自己做,而不是使用 qimage2ndarray 之类的额外库将 OpenCV 图像转换为 QImages,以查看究竟需要做什么。如果您对材料有丰富的经验并且您只需要节省一些时间,那么这样的库就很整洁。除此之外 - 远离他们。

    【讨论】:

    • 查看我的编辑。我想你很快就会看到我不知道如何使用 QGraphicsPixmapItem 将颜色图直接附加到 QGraphicsScene,thanx。显然,我们非常接近解决方案。
    • 如你所见,我采纳了你关于 qimage2ndarray 的建议
    • 查看我的第二次更新。我创建了一个 QGraphicsPixmapItem 对象并使用 addItem 添加到场景中无济于事:(
    • 很抱歉。我误读了文档。检查我的编辑。这应该可以帮助您继续前进。
    • 查看我的更新。天哪……简直不敢相信这个问题——我认为这是一个简单明了的问题——现在有 6 个赞!我看到的唯一解决方案是将颜色图实际保存为 png 文件,然后将其加载为 QPixmap ......但必须有一种方法可以在不保存任何内容的情况下执行此操作。这会造成瓶颈,不是吗?
    【解决方案2】:

    您已经拥有几乎可以运行的代码。您使用以下方式获取图像:

    scaled_image = Image.fromarray(np.uint8(self.image*255))
    

    要反转,您只需从 255 中减去当前数据。

    scaled_image = Image.fromarray(255-np.uint8(self.image*255))
    

    在这里,我假设您当前的代码工作正常,并且只有反转值。但是,如果您的数据确实是从 -1 到 1,那么当前代码会将结果的一半限制为零(因为 uint8 的最小值为零)。从 -1 到 1 的值的正确代码应该稍作修改:

    scaled_image = Image.fromarray(255 - (self.image + 1)*127.5)
    

    附:您可以通过使用不同的颜色图(例如'jet_r')来反转颜色而无需任何数学运算。但请确保您的值正确缩放

    【讨论】:

    • +1 用于解决反向问题的单行答案,谢谢!我确实最终在最终解决方案中使用了您的代码(请参阅我发布的答案中的更新)
    【解决方案3】:

    所以这行得通......但我觉得这样做很肮脏:

        scene = QGraphicsScene(self)
        scaled_image = Image.fromarray(np.uint8(self.image*255))
        plt.savefig(".../Downloads/itworks.png")
        pixMap = QPixmap(".../Downloads/itworks.png")
        scene.addPixmap(pixMap)
        self.graphicsView.setScene(scene)
    

    真的必须依赖于将图像保存到文件,然后将其作为 QPixmap 重新加载才能工作...?对于我认为对 pyqt 的一个非常标准的需求,这不是一个非常不合常规的胶带答案吗?我担心每次都必须将图像保存到文件中,这会在我扩大规模时产生瓶颈,而且,因为我必须管理文件系统的东西,所以会很烦人。

    我将向任何可以提供将numpy.random.random((256, 256)) 输出到 qt 场景而无需保存到文件的中间步骤的人开放。

    与此同时,这种胶带解决方案有效:

    更新:作为参考,这就是我最终使用rbaleksandarimposeren 中的代码完美运行的操作。谢谢大家!

        scene = self.QScene(self)
        scaled_image = Image.fromarray(255-np.uint8(self.image*255))
        plt.imshow(scaled_image, interpolation = "nearest")
        gcf().canvas.draw() # IMPORTANT!
        stringBuffer = gcf().canvas.buffer_rgba() # IMPORTANT!
        l, b, w, h = gcf().bbox.bounds
        qImage = QtGui.QImage(stringBuffer,
                      w,
                      h,
                      QtGui.QImage.Format_ARGB32)
        pixmap = QtGui.QPixmap.fromImage(qImage)
        pixmapItem = QtGui.QGraphicsPixmapItem(pixmap)
        scene.addItem(pixmapItem)
        self.graphicsView.setScene(scene)
    

    【讨论】:

    • 我不明白。你知道你可以在 PyQt 中无缝集成 matplotlib。我会更新我的答案。
    • 我不知道,谢谢(两周前才开始使用pyqt)。最后一个问题,或者我希望,在我的问题中看到我的更新。冷是热的,热是冷的。我应该可以切换两个参数来修改这个?
    • 那里,见EDIT 3
    【解决方案4】:

    您应该使用matplotlib's PyQt4 backend 继续沿Matplotlib's imshow 路线(可能还与colormap customisation 一起)。

    我以前使用过这个 mpl-PyQt4 工具,虽然一开始可能看起来很麻烦,但它正是您正在寻找的(使用原生工具,没有技术翻译/桥接)和 大多数强>可扩展。这些属性在示例中通过制作动画以及 QLayout 的绘图排列来显示

    【讨论】:

      猜你喜欢
      • 2014-01-07
      • 1970-01-01
      • 2022-10-07
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多