Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Program Crashes ERROR when converting a numpy array to Pixmap



  • Hello guys,
    I am working on an application wherein I load a binary (.bin) file and convert it to a 2D numpy array. I can read the binary file and I have also managed to convert it to a numpy array.
    The name of the variable is out and its shape is (512, 1536). As the shape of the array is 2D, it is a grayscale image. The variable contains:

    out = array([[  0, 107,  68, ...,   0,   2,   3],
           [ 47,  65,  66, ...,   0,   1,   0],
           [ 27,  24,  34, ...,   2,   0,   1],
           ...,
           [124, 127, 124, ..., 136, 140, 147],
           [125, 129, 125, ..., 130, 134, 132],
           [130, 126, 126, ..., 139, 134, 130]], dtype=uint8)
    

    I used opencv to show the image:

    import cv2
    cv2.imshow('out', out)
    

    This works and I can see the grayscale image in a new window.

    However, when I try to convert the numpy array to Pixmap using the following code the program crashes without outputting any error:

    qImg = QPixmap(QImage(out.data, out.shape[1], out.shape[0], QImage.Format_Grayscale8))
    print(qImg)
    

    The print(qImg) line should output a pixmap object but it doesn't and just crashes.

    What could the reason for this be?

    Appreciate your help.

    Thank You.



  • Okay, so it worked:
    I used the following function to create a QImage:

    def numpyQImage(image):
        qImg = QImage()
        if image.dtype == np.uint8:
            if len(image.shape) == 2:
                channels = 1
                height, width = image.shape
                bytesPerLine = channels * width
                qImg = QImage(
                    image.data, width, height, bytesPerLine, QImage.Format_Indexed8
                )
                qImg.setColorTable([qRgb(i, i, i) for i in range(256)])
            elif len(image.shape) == 3:
                if image.shape[2] == 3:
                    height, width, channels = image.shape
                    bytesPerLine = channels * width
                    qImg = QImage(
                        image.data, width, height, bytesPerLine, QImage.Format_RGB888
                    )
                elif image.shape[2] == 4:
                    height, width, channels = image.shape
                    bytesPerLine = channels * width
                    fmt = QImage.Format_ARGB32
                    qImg = QImage(
                        image.data, width, height, bytesPerLine, QImage.Format_ARGB32
                    )
        return qImg
    
    

    After this,

        new = out.copy()
        image = numpyQImage(new)
        pixmap = QPixmap.fromImage(image)
        label.setPixmap(pixmap)
    
        vbox = QVBoxLayout()
        vbox.addWidget(label)
        win.setLayout(vbox)
        win.show()
        sys.exit(app.exec_())
    

    @SGaist Thank you for your help!


  • Lifetime Qt Champion

    Hi,

    You should take a look at this stack overflow thread.

    It also links to a Python helper module that allows for numpy<->QImage conversion.



  • @SGaist
    I have tried this and it still doesnot work. The program still crashes.

    q = qimage2ndarray.array2qimage(out)
    pix = QPixmap(q)  # After this line the program crashes
    

  • Lifetime Qt Champion

    I just realized, at least in C++ there's no constructor taking a QImage. The method is QPixmap::fromImage



  • @SGaist
    I used:

    q = qimage2ndarray.array2qimage(out)
    pix = QPixmap.fromImage(q)
    

    But the error still persists as in the program crashes.
    Would it help if you have the complete numpy array(out) because what I have posted is a truncated version.


  • Lifetime Qt Champion

    A minimal test with a minimal numpy array would be nice indeed.

    By the way, which version of Python, Numpy and PySide/PyQt are you using ?



  • @SGaist
    Thanks for your reply. Morning.
    Using PyQt5, Python 3.7.9 (Conda environment), Numpy (1.19.4)

    Please use this link to download the text file which contains the numpy array.
    https://drive.google.com/file/d/1utNAS7srr4toCTBHIcRvm-mIGL3IPPB-/view?usp=sharing

    How i run the script:

    import numpy as np
    import sys
    from PyQt5.QtGui import QImage, QPixmap
    from PyQt5.QtWidgets import QApplication, QLabel
    import matplotlib.pyplot as plt
    import qimage2ndarray
    
    var = np.array(np.loadtxt('out.txt')).astype(np.uint8)
    new_var = var.copy()
    q = qimage2ndarray.array2qimage(new_var)
    pix = QPixmap.fromImage(q)  # Program crashes here
    
    app = QApplication(sys.argv)
    w = QLabel()
    w.setPixmap(pixmap)
    w.show()
    sys.exit(app.exec_())
    
    

    I have also tried following but still no luck.

    qImg = QPixmap.fromImage(QImage(new_var.data, new_var.shape[1], new_var.shape[0], new_var.strides[0], QImage.Format_Grayscale8))
    

    Please let me know if you cannot open the link.

    Edit 1:
    According to this link(https://stackoverflow.com/questions/58366734/converting-numpy-image-to-qpixmap) I also tried the following (extension of the script):

    from PyQt5.QtGui import qRgb
    
    GRAY_COLORTABLE = [qRgb(i, i, i) for i in range(256)]
    
    img_array = out.copy()
    # img_array.strides = (1536, 1)
    bytesPerLine = img_array.strides[1]  # Hence here indexed 1 for Grayscale image
    
    print(f'strides:{img_array.strides[1]}') # Channel = 1 For grayscale image
    
    height, width = img_array.shape
    
    image = QImage(img_array.data,
                       width, height,
                       bytesPerLine,
                       QImage.Format_Indexed8)
    image.setColorTable(GRAY_COLORTABLE)
    print('image: ', image)
    print('test')
    new = image.copy()
    pixmap = QPixmap.fromImage(new) # Program crashes here
    print(pixmap) # Cannot print this
    

    And still it doesn't work. I cannot print the Pixmap object let alone set it on a Label.

    I cannot get my head around this. Appreciate any help I can get.


  • Lifetime Qt Champion

    I have not run your script yet but one big issue you have is that you try to create your QPixmap before your QApplication object. Contrary to QImage, QPixmap requires a connection to the windowing system which is setup by QApplication.



  • So you were right. Even though I can print the pixmap object, the window (label) doesn't show the image.

        import numpy as np
        import sys
        from PyQt5.QtGui import QImage, QPixmap, QColor, qRgb
        from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout
    
        win = QWidget()
        label = QLabel()
    
        GRAY_COLORTABLE = [qRgb(i, i, i) for i in range(256)]
        out = np.array(np.loadtxt('out.txt')).astype(np.uint8)
        img_array = out.copy()
        bytesPerLine = img_array.strides[1]
    
        height, width = img_array.shape
    
        image = QImage(img_array.data,
                       width, height,
                       bytesPerLine,
                       QImage.Format_Indexed8)
    
        image.setColorTable(GRAY_COLORTABLE)
    
        print('image: ', image)
        # new = image.copy()
        pixmap = QPixmap.fromImage(image)
        print(pixmap)  # I can see the pixmap object now
        label.setPixmap(pixmap)
    
        vbox = QVBoxLayout()
        vbox.addWidget(label)
        win.setLayout(vbox)
        win.show()
        sys.exit(app.exec_())
    


  • Okay, so it worked:
    I used the following function to create a QImage:

    def numpyQImage(image):
        qImg = QImage()
        if image.dtype == np.uint8:
            if len(image.shape) == 2:
                channels = 1
                height, width = image.shape
                bytesPerLine = channels * width
                qImg = QImage(
                    image.data, width, height, bytesPerLine, QImage.Format_Indexed8
                )
                qImg.setColorTable([qRgb(i, i, i) for i in range(256)])
            elif len(image.shape) == 3:
                if image.shape[2] == 3:
                    height, width, channels = image.shape
                    bytesPerLine = channels * width
                    qImg = QImage(
                        image.data, width, height, bytesPerLine, QImage.Format_RGB888
                    )
                elif image.shape[2] == 4:
                    height, width, channels = image.shape
                    bytesPerLine = channels * width
                    fmt = QImage.Format_ARGB32
                    qImg = QImage(
                        image.data, width, height, bytesPerLine, QImage.Format_ARGB32
                    )
        return qImg
    
    

    After this,

        new = out.copy()
        image = numpyQImage(new)
        pixmap = QPixmap.fromImage(image)
        label.setPixmap(pixmap)
    
        vbox = QVBoxLayout()
        vbox.addWidget(label)
        win.setLayout(vbox)
        win.show()
        sys.exit(app.exec_())
    

    @SGaist Thank you for your help!


Log in to reply