Convert Python Opencv Image (numpy array) to PyQt QPixmap image
Asked Answered
N

9

28

I am trying to convert python opencv image to QPixmap.

I follow the instruction shows Page Link and my code is attached below

img = cv2.imread('test.png')[:,:,::1]/255. 
imgDown = cv2.pyrDown(img)
imgDown = np.float32(imgDown)        
cvRGBImg = cv2.cvtColor(imgDown, cv2.cv.CV_BGR2RGB)
qimg = QtGui.QImage(cvRGBImg.data,cvRGBImg.shape[1], cvRGBImg.shape[0], QtGui.QImage.Format_RGB888)
pixmap01 = QtGui.QPixmap.fromImage(qimg)
self.image01TopTxt = QtGui.QLabel('window',self)
self.imageLable01 = QtGui.QLabel(self)
self.imageLable01.setPixmap(pixmap01)

The code has no compile and runtime error but the conversion is wrong and I just get some noise image. I am not sure what the problem is. Could anyone help?

Northman answered 11/12, 2015 at 21:11 Comment(0)
M
49

Use this to convert cvImage to Qimage, here cvImage is the original image.

height, width, channel = cvImg.shape
bytesPerLine = 3 * width
qImg = QImage(cvImg.data, width, height, bytesPerLine, QImage.Format_RGB888)

and set this Qimage to Label.setPixmap parameter from Qimage. It works!!!

Madrigalist answered 8/3, 2016 at 2:32 Comment(8)
I had to create QPixmap explicitly: self.imageLable01.setPixmap(QPixmap(qImg)) and pass bytesPerLine + 1Acetous
Any documentation that mentions numpy format is always RGB888 ?Phlogistic
Doesn't always have to be RGB888, from teh qt5 docs, doc.qt.io/qt-5/qimage.html#image-formats a list of supported formats. Of course, you'll have to make sure your numpy array has the right data.Festinate
@MarkCarpenterJr Is there any way to determine which image format I need? Tried several from your link but none works.Shrink
@Shrink You could try converting to a specific format first then creating the QImage(). You could also look at a tuple in the array, and guess at determining the format, RGB888, for example, is 8 bits per pixel and is considered a 24-bit format, a pixel would look like 3 8bit values; (255,255,255). All depends on what you're doing though.Festinate
With OpenCV you want to use QImage.Format_BGR888 as OpenCV uses BGR, not RGB.Rhetorical
@Rhetorical When i try to use Format_BGR888 i have an error type object 'QImage' has no attribute 'Format_BGR888'. Otherwise with Format_RGB888 it works. Why?Catwalk
@Catwalk QImage.Format_BGR888 was added in Qt 5.14, upgradeRhetorical
B
23

Just complementing the answer of AdityaIntwala, if the image appears to be red or blue, it is because the format is not RGB, but BGR (the inverse). In this case, use the QImage.rgbSwapped method to correct:

height, width, channel = cvImg.shape
bytesPerLine = 3 * width
qImg = QImage(cvImg.data, width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped()
Bedmate answered 11/6, 2018 at 15:1 Comment(0)
M
8
#image is the numpy array that you got from cv2.imread(example_image.jpg)

image = QtGui.QImage(image, image.shape[1],\
                            image.shape[0], image.shape[1] * 3,QtGui.QImage.Format_RGB888)
pix = QtGui.QPixmap(image)

self.scene.addPixmap(pix)
Margetmargette answered 8/3, 2016 at 0:38 Comment(0)
B
6

Hate to add to the large number of answers, but as this was the only thing that worked for me I will, in case others run into the same issue.

As mentioned here on GitHub

Wrap the numpy array/ndarry in a np.require(array, np.uint8, 'C') call first, such as:

arr2 = np.require(arr, np.uint8, 'C')
qImg = QtGui.QImage(arr2, width, height, QtGui.QImage.Format_RGB888)
Bathyscaphe answered 30/5, 2019 at 20:51 Comment(0)
L
3

There is the easiest way:

from PIL.ImageQt import ImageQt 
from PIL import Image
from PySide2.QtGui import QPixmap
import cv2


# Convert an opencv image to QPixmap
def convertCvImage2QtImage(cv_img):
    rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
    PIL_image = Image.fromarray(rgb_image).convert('RGB')
    return QPixmap.fromImage(ImageQt(PIL_image))
Lusk answered 24/12, 2020 at 8:3 Comment(0)
D
2

Here's my take on this:

def convert_nparray_to_QPixmap(self,img):
    h,w,ch = img.shape
    # Convert resulting image to pixmap
    if img.ndim == 1:
        img =  cv2.cvtColor(img,cv2.COLOR_GRAY2RGB)

    qimg = QImage(img.data, w, h, w*ch, QImage.Format_RGB888) 
    qpixmap = QPixmap(qimg)

    return qpixmap
Dentation answered 4/12, 2020 at 4:0 Comment(1)
This is incorrect. img.shape is [h, w, (channels)] and bytesPerLine = channels * width. Also note QImage(data, width, height, (bytesPerLine), QImage.Format)Gahl
D
1

AdityaIntwala's answer was close but it didnt work for me. the cvImg.data gave an error like 'argument 1 has unexpected type 'memoryview'. So I have removed the 'cvImg.data' and passed the cvImg.tobytes() as bytes, and it worked

height, width, channel = cvImg.shape
bytesPerLine = 3 * width
qImg = QImage(cvImg.tobytes(), width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped()

then I have set the pixmap as shown below

self.imageLabel.setPixmap(QPixmap(qImg))
Dorsey answered 4/10, 2022 at 14:5 Comment(0)
R
0
  image=cv2.imread("your_image.png")
  image = QtGui.QImage(image, image.shape[1],image.shape[0], image.shape[1] * 3, QtGui.QImage.Format_BGR888)
  pix = QtGui.QPixmap(image)
  self.image.setPixmap(QtGui.QPixmap(pix))
Roderickroderigo answered 14/4, 2022 at 12:49 Comment(1)
Hi and welcome to stack overflow, posting an answer with only a code block is not recommended, its better to have some text around it explaining how and why this worksAlaniz
S
0

When using OpenCV to read an image, the output is in BGR format. However, before running QImage, you need to convert BGR to RGB.

Please convert using cv2.cvtColor(img,cv2.COLOR_BGR2RGB). If you convert BGR to RGB using other solutions, such as img = img[:,:,(2,1,0)], it may not be complete.

Softshoe answered 22/3, 2023 at 10:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.