14

Considering the following code

from PyQt5.QtWidgets import QMainWindow, QLabel, QSizePolicy, QApplication 
from PyQt5.QtGui import QPixmap, QImage                                
from PyQt5.QtCore import Qt                                                                                              
import numpy as np                                                     
import sys



class Test(QMainWindow):                                                                                                                                                                                       

 def __init__(self):                                                                                                                                                                                        
     super().__init__()                                                                                                                                                                                     
     self.initUI()                                                                                                                                                                                          

 def initUI(self):                                                                                                                                                                                          
     self.setGeometry(10,10,640, 400)                                                                                                                                                                       

     pixmap_label = QLabel()                                                                                                                                                                                
     pixmap_label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)                                                                                                                                   
     pixmap_label.resize(640,400)                                                                                                                                                                           
     pixmap_label.setAlignment(Qt.AlignCenter)                                                                                                                                                              

     im_np = np.ones((1800,2880,3),dtype=uint8)                                                                                                                                                                                  
     im_np = np.transpose(im_np, (1,0,2))                                                                                                                                                                              
     qimage = QImage(im_np, im_np.shape[1], im_np.shape[0],                                                                                                                                                 
                     QImage.Format_RGB888)                                                                                                                                                                 
     pixmap = QPixmap(qimage)                                                                                                                                                                               
     pixmap = pixmap.scaled(640,400, Qt.KeepAspectRatio)                                                                                                                                                    
     pixmap_label.setPixmap(pixmap)                                                                                                                                                                         

     self.setCentralWidget(pixmap_label)                                                                                                                                                                    
     self.show()                                                                                                                                                                                            



def main():                                                                                                                                                                                                    
  app = QApplication(sys.argv)                                                                                                                                                                               
  win = Test()                                                                                                                                                                                               
  sys.exit(app.exec_())                                                                                                                                                                                      



if __name__=="__main__":                                                                                                                                                                                       
  main()  

I get the following error

TypeError: arguments did not match any overloaded call: QImage(): too many arguments QImage(QSize, QImage.Format): argument 1 has unexpected type 'numpy.ndarray' QImage(int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray' QImage(bytes, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(sip.voidptr, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray' QImage(bytes, int, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray'
QImage(sip.voidptr, int, int, int, QImage.Format): argument 1 has unexpected type 'numpy.ndarray' QImage(List[str]): argument 1 has unexpected type 'numpy.ndarray' QImage(str, format: str = None): argument 1 has unexpected type 'numpy.ndarray' QImage(QImage): argument 1 has unexpected type 'numpy.ndarray' QImage(Any): too many arguments

According to this post this can be caused by numpy creating a view. Modifying the lines

 im_np = np.array(img)                                                                                                                                                                                  
 im_np = np.transpose(im_np, (1,0,2))                                                                                                                                                                              

To

im_np = np.array(img)                                                                                                                                                                                  
im_np = np.transpose(im_np, (1,0,2))                                                                                                                                                                              
im_np_cpy = np.copy(im_np)     

Produces the same error. To test that I am not passing a view I print the result of the test

im_np_cpy.base is im_np

and it's False. The image is visualised correctly with cv2. I am clearly missing something, any idea what?

Cheers!

MagoNick
  • 331
  • 1
  • 4
  • 17

7 Answers7

15

I added a copy after the transpose like this:

im_np = np.transpose(im_np,(1,0,2)).copy()

and that worked for me.

Johan van Breda
  • 583
  • 8
  • 13
  • Ok... that seems to solve it... but why? What is wrong with doing im_np_cpy = np.copy(im_np)? And what was wrong with doing the transpose in the first place? The memory view? – MagoNick Feb 06 '18 at 10:46
  • I do not know what a = np.copy(matrix) is. I know that a = matrix.copy() works, for instance to take a part from the data like in data[row:stride,column:stride].copy() – Johan van Breda Feb 06 '18 at 10:58
  • 1
    According to the documentation of [numpy.copy](https://docs.scipy.org/doc/numpy/reference/generated/numpy.copy.html) and [numpy.ndarray.copy](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.copy.html#numpy.ndarray.copy) the only difference is in the `order` that controls the memory layout. In your solution the default is C-order. While in mine is K, that means that it tries to match the layout of the original matrix. Now I do not know what does this imply, but apparently is messing up with Qt. – MagoNick Feb 06 '18 at 11:12
  • Thanks, that works for me. Making a copy unfortunately considerably slows down my process though. – 101 Jul 09 '21 at 02:02
  • I think the root cause is some key `attr` of a `"view"` actually returns [base object](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.base.html) attrs. Like `view.strides` actually gives `view.base.strides`, but `view.shape` good (compare to `view.copy().strides`). I think `img` for `QImage(img.data, ...)` constr must have `.base.` or `.base.base.flags['OWNDATA']` → `True`, which unfortunately cannot happen unless you `copy` it `¯\_(ツ)_/¯`. Took me awhile to figure this out. Use `bytesPerLine` of the [Qimage constructor](https://doc.qt.io/qt-5/qimage.html) respek @eyllanesc... – Kardo Paska Aug 09 '21 at 08:35
8

Ivan's answer is short and elegant, however while numpy uses (H, W) order, Qt uses (W, H) order. Therefore, to make it work, I have to exchange w and h in the second line:

h, w, _ = img.shape
qimage = QImage(img.data, w, h, 3 * w, QImage.Format_RGB888)

(I would have preferred to comment on the above answer but I don't have enough reputation.)

Woffl
  • 106
  • 1
  • 3
7

Check if the module qimage2ndarray suits your needs, with just one line of code https://pypi.org/project/qimage2ndarray/

yourQImage=qimage2ndarray.array2qimage(yournumpyarray)
Dio Nik
  • 71
  • 1
  • 3
4

Just do this:

h,w = img.shape
qimage = QImage(img.data, w, h, 3*w, QImage.Format_RGB888)
Ivan
  • 311
  • 3
  • 7
3

Axis transposing, reordering (BGR to RGB) or any transition that doesn't require a copy, a new image container, representing the same image buffer will be created. the problems starts to appear at the interface point to another module. usually an image buffer is represented as a continues stream of bytes along a defined order of axis. it could be solved using:

im_np = np.array(img)                                                                                                                                                                               
im_np = np.transpose(im_np, (1,0,2))
im_np = np.ascontiguousarray(im_np)
qimage = QImage(im_np.data, im_np.shape[1], im_np.shape[0],                                                                                                                                                 
                 QImage.Format_RGB888)

or alternatively (faster) by:

im_np = np.array(img)    
qimage = QImage(im_np.data, im_np.shape[1], im_np.shape[0],                                                                                                                                                 
                 QImage.Format_BGR888)
Assaf-ge
  • 464
  • 4
  • 6
1

If we use opencv module in pyqt Qimage, use the below command for image.

 qimage = QImage(img, img.shape[1], img.shape[0], QImage.Format_BGR888)

And if we use images, then directly use this:

 qimage = QImage(img, img.shape[1], img.shape[0], QImage.Format_RGB888)
1
import copy

im_np = np.array(img)                                                                                                                                                                                  
im_np = np.transpose(im_np, (1,0,2))                                                                                                                                                                              
im_np_cpy = copy.deepcopy(im_np) 

Use above command for getting the im_np data to im_np_cpy

Elikill58
  • 4,050
  • 24
  • 23
  • 45