11

I am currently switching from PyQt to PySide.

With PyQt I converted QImage to a Numpy.Array using this code that I found on SO:

def convertQImageToMat(incomingImage):
    '''  Converts a QImage into an opencv MAT format  '''

    incomingImage = incomingImage.convertToFormat(4)

    width = incomingImage.width()
    height = incomingImage.height()

    ptr = incomingImage.bits()
    ptr.setsize(incomingImage.byteCount())
    arr = np.array(ptr).reshape(height, width, 4)  #  Copies the data
    return arr

However ptr.setsize(incomingImage.byteCount()) does not work with PySide as this is part of the void* support of PyQt.

My Question is: How can I convert a QImage to a Numpy.Array using PySide.

EDIT:

Version Info
> Windows 7 (64Bit)
> Python 2.7
> PySide Version 1.2.1
> Qt Version 4.8.5
Community
  • 1
  • 1
Mailerdaimon
  • 6,003
  • 3
  • 35
  • 46
  • 1
    PySide doesn't seem to offer a `bits` method. Is this also part of PyQt? How about using [`constBits`](http://srinikom.github.io/pyside-docs/PySide/QtGui/QImage.html#PySide.QtGui.PySide.QtGui.QImage.constBits)? – Henry Gomersall Nov 11 '13 at 12:35
  • m( can´t believe I didn´t see that! Thanks a lot. If you repost your comment as a Answer I will accept it. Thanks again! – Mailerdaimon Nov 11 '13 at 13:05
  • Done, but is that adequate to answer the question? – Henry Gomersall Nov 11 '13 at 13:15
  • Yes, as it was the only thing missing to get it working. I edit my Question to add the working code in a sec. – Mailerdaimon Nov 11 '13 at 13:18

3 Answers3

6

For me the solution with constBits() did not work, but the following worked:

def QImageToCvMat(incomingImage):
    '''  Converts a QImage into an opencv MAT format  '''

    incomingImage = incomingImage.convertToFormat(QtGui.QImage.Format.Format_RGBA8888)

    width = incomingImage.width()
    height = incomingImage.height()

    ptr = incomingImage.bits()
    ptr.setsize(height * width * 4)
    arr = np.frombuffer(ptr, np.uint8).reshape((height, width, 4))
    return arr
JTIM
  • 2,774
  • 1
  • 34
  • 74
  • 3
    Be aware that using `bits()` instead of `constBits()` creates a deep copy. This may or may not be what you intend. – Mailerdaimon Nov 21 '18 at 06:45
  • @Mailerdaimon I need the deep copy because I want to manipulate the data. At least I get an access violation if I do not use `bits()` – JTIM Nov 21 '18 at 07:24
3

The trick is to use QImage.constBits() as suggested by @Henry Gomersall. The code I use now is:

def QImageToCvMat(self,incomingImage):
    '''  Converts a QImage into an opencv MAT format  '''

    incomingImage = incomingImage.convertToFormat(QtGui.QImage.Format.Format_RGB32)

    width = incomingImage.width()
    height = incomingImage.height()

    ptr = incomingImage.constBits()
    arr = np.array(ptr).reshape(height, width, 4)  #  Copies the data
    return arr
Mailerdaimon
  • 6,003
  • 3
  • 35
  • 46
  • Wonderful!Do you know the inverse of it ? – Maham Oct 06 '17 at 13:38
  • @Maham That would best be asked in a seperate question – Mailerdaimon Oct 06 '17 at 13:47
  • @Silencer: You may want to ask that as a question showing us what exactly is not working. I am using PyQt5 and it is working for me. – Mailerdaimon Nov 16 '17 at 07:24
  • Sorry about this. I find the reason: I display using `cv2.imshow` and `QLabel` at the same, then they confllict for some reason of `gtkXXX`. But when I comment off the `cv2.imshow`, it works. Sorry again. – Kinght 金 Nov 16 '17 at 10:40
2

PySide doesn't seem to offer a bits method. How about using constBits to get the pointer to the array?

Henry Gomersall
  • 8,434
  • 3
  • 31
  • 54