PyQt5 display image of pixel array

119 Views Asked by At

He||o,

What I want to do :

I have an array of 22x22 pixel of value between 0 and 255 (8 bit grayscale).

What I have done :

I was able to display it using matplotlib but now I want to plot it inside a PyQt5 interface. When I create a pixmap and set the values everything seems fine but when it displays, either there is black space between the rows and cols or the row seems to be shifted.

Here are the 2 codes I have tried:

For this one you will have to pip install folium, matplotlib, numpy and PySide6.

import sys
import io
import folium
import matplotlib.pyplot as plt
import numpy as np

from PySide6.QtWidgets import QApplication, QDialog, QDialogButtonBox, QGroupBox, QHBoxLayout, QLabel, QVBoxLayout
from PySide6.QtGui import QPixmap, QImage
from PySide6 import QtWebEngineWidgets
from PySide6 import QtCore


class Dialog(QDialog):

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

        self.create_horizontal_group_box()

        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)

        main_layout = QVBoxLayout()
        main_layout.addWidget(self._horizontal_group_box)
        main_layout.addWidget(button_box)
        self.setLayout(main_layout)

        self.setWindowTitle("Basic Layouts")

    def create_horizontal_group_box(self):
        self._horizontal_group_box = QGroupBox("Horizontal layout")
        layout = QHBoxLayout()

        #map data
        data = np.array([[65535, 65535, 65535, 65535, 30, 32, 33, 31, 30, 28, 29, 29, 30, 31, 31, 32, 31, 31, 30, 30, 29, 29],
                        [65535, 65535, 65535, 65535, 32, 35, 37, 34, 31, 28, 29, 30, 32, 34, 36, 38, 35, 33, 30, 30, 29, 28],
                        [28, 29, 30, 31, 34, 38, 41, 36, 33, 28, 30, 32, 33, 37, 40, 44, 40, 35, 31, 30, 28, 28],
                        [29, 30, 31, 32, 36, 41, 45, 39, 34, 28, 30, 33, 35, 40, 45, 50, 44, 37, 31, 30, 28, 27],
                        [28, 30, 31, 33, 38, 43, 48, 41, 36, 29, 32, 35, 38, 43, 48, 53, 47, 40, 34, 32, 30, 28],
                        [28, 30, 32, 34, 39, 46, 51, 44, 37, 30, 33, 37, 40, 45, 50, 55, 49, 42, 36, 34, 32, 30],
                        [27, 30, 32, 35, 41, 48, 54, 46, 39, 31, 35, 39, 43, 48, 53, 58, 52, 45, 39, 36, 34, 31],
                        [28, 31, 33, 36, 42, 49, 55, 48, 41, 34, 38, 42, 46, 50, 55, 59, 52, 45, 39, 36, 33, 30],
                        [28, 31, 35, 38, 44, 50, 56, 49, 43, 36, 40, 45, 49, 53, 56, 60, 53, 46, 38, 35, 33, 30],
                        [29, 32, 36, 39, 45, 51, 57, 51, 45, 39, 43, 48, 52, 55, 58, 61, 53, 46, 38, 35, 32, 29],
                        [29, 32, 35, 38, 44, 51, 57, 52, 48, 43, 46, 51, 54, 56, 58, 61, 54, 47, 40, 37, 34, 30],
                        [29, 32, 35, 38, 44, 50, 56, 53, 50, 47, 50, 53, 56, 58, 59, 60, 54, 48, 42, 38, 35, 32],
                        [255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
                        [255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
                        [255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
                        [255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
                        [255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
                        #[29, 32, 34, 37, 43, 50, 56, 54, 53, 51, 53, 56, 58, 59, 59, 60, 55, 49, 44, 40, 37, 33],
                        #[29, 32, 34, 36, 43, 50, 57, 56, 56, 55, 57, 59, 60, 61, 61, 61, 57, 51, 47, 42, 38, 33],
                        #[30, 31, 33, 35, 42, 51, 58, 58, 59, 59, 60, 61, 63, 62, 62, 62, 58, 54, 50, 45, 39, 34],
                        #[30, 31, 33, 34, 42, 51, 59, 60, 62, 63, 64, 64, 65, 64, 64, 63, 60, 56, 53, 47, 40, 34],
                        #[28, 30, 32, 33, 41, 50, 58, 60, 62, 63, 64, 64, 65, 65, 65, 64, 61, 56, 53, 47, 40, 34],
                        [27, 28, 31, 33, 41, 50, 58, 59, 62, 64, 65, 65, 66, 65, 65, 65, 61, 57, 53, 47, 41, 35],
                        [25, 27, 30, 32, 40, 49, 57, 59, 62, 64, 65, 65, 66, 66, 66, 66, 62, 57, 53, 47, 41, 35],
                        [25, 27, 30, 32, 40, 50, 58, 60, 62, 64, 65, 64, 65, 65, 65, 65, 61, 56, 51, 46, 40, 35],
                        [26, 28, 30, 32, 41, 50, 59, 60, 63, 64, 64, 64, 64, 64, 65, 65, 60, 54, 50, 45, 40, 35],
                        [26, 28, 30, 32, 41, 51, 60, 61, 63, 64, 64, 63, 63, 63, 64, 64, 59, 53, 48, 44, 39, 35]])                 

        im = QImage(data, 22, 22, QImage.Format_Grayscale16)
        pixmap = QPixmap(im)
        pixmap = pixmap.scaled(440, 440, QtCore.Qt.KeepAspectRatio)
        myLabel = QLabel()
        myLabel.setPixmap(pixmap)
        layout.addWidget(myLabel)
        
        #create map
        m = folium.Map(location=[45.5236, -122.6750], tiles="Stamen Toner", zoom_start=13)
        data = io.BytesIO()
        m.save(data, close_file=False)
        w = QtWebEngineWidgets.QWebEngineView()
        w.setHtml(data.getvalue().decode())
        layout.addWidget(w)

        self._horizontal_group_box.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = Dialog()
    sys.exit(dialog.exec())

We should be able to see white pixels next to each others but they are split appart. I also tried with Format_Grayscale8.

Here is the result with greyscale16:

greyscale16

Here is the result with greyscale8 (changing max values to 255): greyscale8

For this one you will need to pip install PyQt5 and numpy.

import sys
import numpy as np

from PyQt5.QtWidgets import QWidget, QApplication, QDialog, QDialogButtonBox, QGroupBox, QHBoxLayout, QLabel, QVBoxLayout
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import Qt, QByteArray


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = QWidget()
    layout = QVBoxLayout()
    window.setLayout(layout)

    img_width = 22
    img_height = 22

    img = np.full((img_height, img_width, 3), 254, dtype=np.uint8)
    for i in range (22):
        for j in range (22):
            #img[i][j]=(i*5)+(j*5)
            if i == j :
                img[i][j]=100

    print(type(img))
    print(type(img.data))

    qtImage = QImage(img.data, img_width, img_height, QImage.Format_Grayscale8)
    pixmap = QPixmap.fromImage(qtImage)
    pixmap = pixmap.scaled(440, 440, Qt.KeepAspectRatio)
    image_label = QLabel()
    image_label.setPixmap(pixmap)
    layout.addWidget(image_label)

    window.show()
    app.exec_()

Here you can clearly see what I mean by "rows are shifted" Here is the result:

SimpleResult

Edit :

New help is still appreciated. I have been able to make something work from the second exemple (the first exemple is still a mystery). I changed from 3D numpy matrix to 2D numpy matrix and added the parameter bytesPerLines to width*bitsPerPixel/8 (bitsPerPixel is just a value that I know : 8 bits) as musicamante suggested.

Here is the code :

import sys

import numpy as np

from PyQt5.QtWidgets import QWidget, QApplication, QDialog, QDialogButtonBox, QGroupBox, QHBoxLayout, QLabel, QVBoxLayout
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import Qt, QByteArray


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = QWidget()
    layout = QVBoxLayout()
    window.setLayout(layout)

    img_width = 22
    img_height = 22

    img = np.full((img_height, img_width, 1), 254, dtype=np.uint8)
    for i in range (22):
        for j in range (22):
            img[i][j]=(i*5)+(j*5)

    print(type(img))
    print(type(img.data))

    qtImage = QImage(img.data, img_width, img_height, img_width, QImage.Format_Grayscale8)
    pixmap = QPixmap.fromImage(qtImage)
    pixmap = pixmap.scaled(440, 440, Qt.KeepAspectRatio)
    image_label = QLabel()
    image_label.setPixmap(pixmap)
    layout.addWidget(image_label)

    window.show()
    app.exec_()

And here is the result : workingExemple

0

There are 0 best solutions below