Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I output a colormap in a scene using pyqt?

TL;DR: You only need to read the "Update" section.

How do you output numpy.random.random((256, 256)) as a colormap to a qt scene?

That's the summary of the summary.

Update:

The following gets me the colormap I want saved to file.

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

self.image is 256x256 numpy array, all its values range between -1 and 1. enter image description here

How do I get this image to output onto a scene in Qt? You can use self.image = numpy.random.random((256, 256)) to have a starting point similar to me. How do you get your 2D numpy array of random values onto the pyqt scene as a colormap?


Update 24/02/1016

So close. This seems to work, but the scale has been inversed. Blue is now hot and red is cold. How do I switch this around so that it looks like the image above?

    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)

enter image description here

What I've tried 23/02/2016

The following gves me a blank screen

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

enter image description here

The following get me a grayscale outputted to the Qt scene. Why isn't it in colour?

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)

enter image description here

I reverse engineered from solutions to colormap problems here and displaying an image here.

Using advice from a solution posted I tried creating a QGraphicsPixmapItem first and then adding the item to the scene. The official docs were a bit confusing so I finally got what I needed from the much crispier pyside docs. Sadly I get the same grayscale as above. Code below:

    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)

Other things I've tried (older):

self.image is numpy 2D array, all its values range between -1 and 1.

I scale as follows and get a grayscale image. However, I want a colourmap:

    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

enter image description here

If I had instead done the following I would have gotten the colormap I want such as in the image below of a web app I have previously developed

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

enter image description here

How do I add a colormap to the qt scene, instead of just having a grayscale?

like image 919
Frikster Avatar asked Feb 17 '16 00:02

Frikster


1 Answers

QPixmap supports colour values larger than 255 and multiple image formats. If that wasn't true all icons in Qt would have been grayscaled (obviously not the case ;)).

You can generate your colormap in whatever way you want to do that (before (using OpenCV and numpy) or after converting it to a QImage (using Qt)), convert it to a QPixmap and using QGraphicsPixmapItem (don't use QPixmap as a part of QGraphicScene directly) attach it to your QGraphicsScene.

EDIT: I have misread the documentation. You can actually use QPixmap directly in a QGraphicScene by using addPixmap(). Sorry about that. As an apology here is some code for you. :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()

It produces the following result:

enter image description here

Image source: look for 7 Cat Sins - Wrath on Google ;)

Basically you create an image viewer, create the scene graph, add a pixmap to the scene graph, set the image viewer's scene to that graph and display the pixmap on the screen using that viewer.

EDIT2: Okay, so it seems you had problems with the actual integration of matplotlib. Here is how you do it (taken from here with a small change for 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_()

EDIT 3: For your reversed colourmap problem see here (documentation) and here (SO).

PS: Instead of using extra library such as qimage2ndarray to convert OpenCV images to QImages I advise you to do that on your own to see what exactly needs to be done. Such libraries are neat if you have plenty of experience with the material and you just need to save some time. Beside that reason - stay away from them.

like image 170
rbaleksandar Avatar answered Oct 12 '22 02:10

rbaleksandar