18

I want to convert an image into a NumPy array to a PySide QPixmap, so I can display it (EDIT: in my PySide UI). I already found this tool: qimage2ndarray, but it only works for PyQt4. I tried to change it to get it working with PySide, but I would have to change the C part of the tool and I have no experience with C. How can I do this or are there any alternatives?

4 Answers 4

11

One alternative is to just use PIL library.

>>> import numpy as np
>>> import Image
>>> im = Image.fromarray(np.random.randint(0,256,size=(100,100,3)).astype(np.uint8))
>>> im.show()

You can look at the QPixmap constructor at http://www.pyside.org/docs/pyside/PySide/QtGui/QImage.html.

It looks like you should be able to use a numpy array directly in the constructor:

class PySide.QtGui.QImage(data, width, height, format)

where the format argument is one of these: http://www.pyside.org/docs/pyside/PySide/QtGui/QImage.html#PySide.QtGui.PySide.QtGui.QImage.Format.

So, for example you could do something like:

>>> a = np.random.randint(0,256,size=(100,100,3)).astype(np.uint32)
>>> b = (255 << 24 | a[:,:,0] << 16 | a[:,:,1] << 8 | a[:,:,2]).flatten() # pack RGB values
>>> im = PySide.QtGui.QImage(b, 100, 100, PySide.QtGui.QImage.Format_RGB32)

I don't have PySide installed so I haven't tested this. Chances are it won't work as is, but it might guide you in the right direction.

Sign up to request clarification or add additional context in comments.

6 Comments

Sorry, I forgot to mention that. I want to display the image in my PySide UI, so unfortunately I cant do it that way.
I changed the 2nd line to b = (255 << 24 | a[:,:,0] << 16 | a[:,:,1] << 8 | a[:,:,2]) and it worked. Thank you very much!
Great solution! To make it work for me, I needed to make a small change and use PySide.QtGui.QImage.Format_ARGB32. The rest is the same.
care to explain the b=... line, I don't get it at all... :s why 255, 24, 16, 8 ? I'm guessing it's related to 2^8, 2^4, 2^3 but what about 24? Also an explanation would be nice, thank you!
posted a separate question here and got a very good explanation. Thanks though! stackoverflow.com/questions/27872239/…
|
11

If you create the data yourself, using numpy for example, I think the fastest method is to directly access a QImage. You can create a ndarray from the buffer object QImage.bits(), do some work using the numpy methods and create a QPixmap from QImage when you are done. You can also read or modify existing QImages that way.

import numpy as np
from PySide.QtGui import QImage

img = QImage(30, 30, QImage.Format_RGB32)
imgarr = np.ndarray(shape=(30,30), dtype=np.uint32, buffer=img.bits())

# qt write, numpy read
img.setPixel(0, 0, 5)
print "%x" % imgarr[0,0]

# numpy write, qt read
imgarr[0,1] = 0xff000006
print "%x" % img.pixel(1,0)

Be sure that the array does not outlive the image object. If you want, you can use a more sophisticated dtype, like a record array for individual access to the alpha, red, green and blue bits (beware of endianess though).

In case there is no efficient way to calculate the pixel values using numpy, you can also use scipy.weave to inline some C/C++ code that operates on the array img.bits() points to.

If you already have an image in ARGB format, creating the QImage from data as suggested before is probably easier.

Comments

2

In addition to @user545424 answer about using PIL, if you didn't want to depend on PIL, you could manually construct your Image directly from your np array:

width = 100
height = 100
data = np.random.randint(0,256,size=(width,height,3)).astype(np.uint8)

img = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32)
for x in xrange(width):
    for y in xrange(height):
        img.setPixel(x, y, QtGui.QColor(*data[x][y]).rgb())

pix = QtGui.QPixmap.fromImage(img)

I'm sure, using PIL, there is a way to read the actual image data into a QImage, but I will let @user545424 address that part since its from his answer. PIL comes with the ImageQt module which is convenient for directly converting an Image -> QPixmap, but unfortunately thats a PyQt4 QPixmap, which doesn't help you.

6 Comments

Thanks, this works. But it takes about 3 seconds, which is way too slow for my application.
@AntonS It's also possible to use ImageQt with PySide. You can write sys.modules['PyQt4'] = PySide before import ImageQt. Example code: pastebin.com/DX2pbdpV. But I don't know what is faster.
Thank you very much! This worked, but user545425s code is a little bit faster and doesn't depend on PIL
@AntonS: user545424's answer DOES depend on PIL though. Did you mean that mine doesn't need PIL?
I meant the second part, where the rgb values are bitshifted and then given to QImage()
|
0

If the answer of user545424 does not work as expected: you see artifacts in the image, then I would suggest you change the parameter to

PySide.QtGui.QImage.Format_ARGB32

a = np.random.randint(0,256,size=(100,100,3)).astype(np.uint32)
b = (255 << 24 | a[:,:,0] << 16 | a[:,:,1] << 8 | a[:,:,2]).flatten() # pack RGB values
im = PySide.QtGui.QImage(b, 100, 100, PySide.QtGui.QImage.Format_ARGB32)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.