How to display a byte array image on a QLabel? - python

I read a byte array of size: height*width*3 (3=RGB) that represents an image. This is raw data that I receive from a USB camera.
I was able to display and save it using PIL on this thread. Now I'm trying to display it on a PyQt5 window.
I have tried using QLabel.setPixmap() but it seems I can not create a valid pixel map.
Failed attempt reading the byte array:
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QByteArray
from PyQt5.QtWidgets import QLabel
self.camLabel = QLabel()
pixmap = QPixmap()
loaded = pixmap.loadFromData(QByteArray(img)) # img is a byte array of size: h*w*3
self.imgLabel.setPixmap(pixmap)
in this example loaded returns False so I know imgLabel.setPixmap will not work, but I don't know how to debug further to find out why the loading has failed.
A second failed attempt trying to use PIL library:
import PIL.Image
import PIL.ImageQt
pImage = PIL.Image.fromarray(RGB) # RGB is a numpy array of the data in img
qtImage = PIL.ImageQt.ImageQt(pImage)
pixmap = QPixmap.fromImage(qtImage)
self.imgLabel.setPixmap(pixmap)
In this example the application crashes when I'm running: self.imgLabel.setPixmap(pixmap), so again, I'm not sure how to debug further.
Any help will be appreciated!

To get a QPixmap from the numpy array you could create an QImage first and use that to create the QPixmap. For example:
from PyQt5 import QtCore, QtWidgets, QtGui
import numpy as np
# generate np array of (r, g, b) triplets with dtype uint8
height = width = 255
RGBarray = np.array([[r % 256, c % 256, -c % 256] for r in range(height) for c in range(width)], dtype=np.uint8)
app = QtWidgets.QApplication([])
label = QtWidgets.QLabel()
# create QImage from numpy array
image = QtGui.QImage(bytes(RGBarray), width, height, 3*width, QtGui.QImage.Format_RGB888)
pixmap = QtGui.QPixmap(image)
label.setPixmap(pixmap)
label.show()
app.exec()

Related

How do I adjust the image size in the QTableWidget?

I want to adjust the image size in the QTableWidget.
But it is size comes out small. (The part that looks like an "이미지")
Below is the original image.
Please help me by referring to the code below.
Thanks.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
imgPath = "D:\Image\Image1.png"
self.tableWidget1 = QTableWidget(self.tab1)
self.tableWidget1.setRowCount(30)
self.tableWidget1.setColumnCount(3)
self.tableWidget1.setHorizontalHeaderLabels(setNameList)
self.tableWidget1.resize(1824, 760)
self.tableWidget1.move(0, 0)
self.tableWidget1.setItem(0, 0, QTableWidgetItem(QIcon(QPixmap(imgPath).scaled(QSize(1280, 640), Qt.KeepAspectRatio)), ''))

Show skimage output in qt application

I am using skimage to do some image manipulations via their numpy manipulations. I am able to do the math on my pixels and then show the result using
def image_manip():
# do manipulations
return final_image
viewer = ImageViewer(image_manip())
viewer.show()
In parallel, in a different application, I'm able to show an image in QT using:
self.pixmap = QtGui.QPixmap('ImagePath.jpg')
So ideally, I'd like to combine the two into something like this:
def image_manip():
# do manipulations
return final_image
self.pixmap = QtGui.QPixmap(image_manip())
Obviously this doesn't work. I get an error TypeError: QPixmap(): argument 1 has unexpected type 'numpy.ndarray'
My guess is that viewer = ImageViewer(image_manip()) and viewer.show() has some magic to allow it to read the skimage/numpy objects directly. In my use case, I don't want to save a file out of skimage (I want to just keep it in memory), so I would imagine it needs to be 'baked out' so Qt can read it as a common format.
How do I go about doing this?
You can convert a uint8 numpy array (shape M, N, 3 RGB image) to QPixmap as follows:
from skimage import img_as_ubyte
arr = img_as_ubyte(arr)
img = QImage(arr.data, arr.shape[1], arr.shape[0],
arr.strides[0], QImage.Format_RGB888)
pixmap = QPixmap.fromImage(img)

How to copy sections of pyQT QPixmaps without copying the whole pixmap?

I have an image that contains tiles. I want to make a QPixmap of each tile within the QPixmap. I thought QPixmap's copy(x,y,width,height) method would do this for me, but must be copying the entire image, not just the rectangle defined by the arguments, and thus consuming WAY too much memory.
An example below illustrates the problem. My png happens to be 3400x3078 pixels, dividing by the 57 rows, 50 columns, the minipixmaps should each be 68x54 pixels, but are obviously using much more memory than that.
What am I missing?
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication
import os, sys
app = QApplication(sys.argv)
file = r"/path/to/image/grid-of-tiles.png"
# image I'm using has these many rows and columns of tiles
r = 57
c = 50
pixmap = QPixmap(file)
# the tiles are known to divide evenly
width = pixmap.width() / c
height = pixmap.height() / r
# after executing the below, mem use climbs north of 9GB!
# I was expecting on the order of twice the original image's size
minipixmaps = [pixmap.copy(row*height, col*width, width, height) for row in range(r) for col in range(c)]
Thanks to eyllanesc's comment. QImage does seem better behaved:
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtWidgets import QApplication
import os, sys
app = QApplication(sys.argv)
file = r"/path/to/image/grid-of-tiles.png"
# image I'm using has these many rows and columns of tiles
r = 57
c = 50
mosaic = QImage(file) # QImage instead of QPixmap
# the tiles are known to divide evenly
width = mosaic.width() / c
height = mosaic.height() / r
# much less memory!
minipixmaps = [QPixmap.fromImage(mosaic.copy(row*height, col*width, width, height)) for row in range(r) for col in range(c)]

Read dicom file in python by simple ITK

I use simple ITK for read dicom file but I do not know how to show it into a QLabel.
reader = SimpleITK.ImageFileReader()
reader.SetFileName("M:\\CT-RT DICOM\ct\\CT111253009007.dcm")
image1 = reader.Execute()
How can I show image1 in QLabel?
Maybe something like this? It should generate a QImage which you can then pass into the QLabel.
A few catch-me's will be the 16 bit image data (I assume) from the DICOM which needs passed into the RGB image. Further the scaling of the image. But this should be enough to get you started
from PySide import QtGui
width,height = img.GetSize()
img = QtGui.QImage(width, height, QtGui.QImage.Format_RGB16)
for x in xrange(width):
for y in xrange(height):
img.setPixel(x, y, QtGui.QColor(data[x,y],data[x,y],data[x,y]))
pix = QtGui.QPixmap.fromImage(img)
QtGui.QLabel label;
label.setPixmap(pix);
label.setMask(pix.mask());
label.show();

How to display clickable RGB image similar to pyqtgraph ImageView?

Despite not being a proficient GUI programmer, I figured out how to use the pyqtgraph module's ImageView function to display an image that I can pan/zoom and click on to get precise pixel coordinates. The complete code is given below. The only problem is that ImageView can apparently only display a single-channel (monochrome) image.
My question: How do I do EXACTLY the same thing as this program (ignoring histogram, norm, and ROI features, which I don't really need), but with the option to display a true color image (e.g., the original JPEG photo)?
import numpy as np
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import matplotlib.image as mpimg
# Load image from disk and reorient it for viewing
fname = 'R0000187.JPG' # This can be any photo image file
photo=np.array(mpimg.imread(fname))
photo = photo.transpose()
# select for red color and extract as monochrome image
img = photo[0,:,:] # WHAT IF I WANT TO DISPLAY THE ORIGINAL RGB IMAGE?
# Create app
app = QtGui.QApplication([])
## Create window with ImageView widget
win = QtGui.QMainWindow()
win.resize(1200,800)
imv = pg.ImageView()
win.setCentralWidget(imv)
win.show()
win.setWindowTitle(fname)
## Display the data
imv.setImage(img)
def click(event):
event.accept()
pos = event.pos()
print (int(pos.x()),int(pos.y()))
imv.getImageItem().mouseClickEvent = click
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
pyqtgraph.ImageView does support rgb / rgba images. For example:
import numpy as np
import pyqtgraph as pg
data = np.random.randint(255, size=(100, 100, 3))
pg.image(data)
..and if you want to display the exact image data without automatic level adjustment:
pg.image(data, levels=(0, 255))
As pointed out by Luke, ImageView() does display RGB, provided the correct array shape is passed. In my sample program, I should have used photo.transpose([1,0,2]) to keep the RGB in the last dimension rather than just photo.transpose(). When ImageView is confronted with an array of dimension (3, W, H), it treats the array as a video consisting of 3 monochrome images, with a slider at the bottom to select the frame.
(Corrected to incorporate followup comment by Luke, below)

Categories

Resources