15

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!

7 Answers 7

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.

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

5 Comments

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?
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()
According to the documentation of numpy.copy and 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.
Thanks, that works for me. Making a copy unfortunately considerably slows down my process though.
I think the root cause is some key attr of a "view" actually returns base object 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 respek @eyllanesc...
9

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.)

Comments

8

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

yourQImage=qimage2ndarray.array2qimage(yournumpyarray)

1 Comment

just for reference, the module doesn't support PyQt6 (Feb 2022)
5

Just do this:

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

Comments

5

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)

Comments

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

Comments

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)

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.