27

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?

SimaGuanxing
  • 673
  • 2
  • 10
  • 29

9 Answers9

47

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!!!

vwvw
  • 372
  • 4
  • 16
AdityaIntwala
  • 2,536
  • 1
  • 17
  • 17
  • 1
    I had to create `QPixmap` explicitly: `self.imageLable01.setPixmap(QPixmap(qImg))` and pass `bytesPerLine + 1` – jfs Jun 05 '18 at 10:31
  • Any documentation that mentions numpy format is always RGB888 ? – Overdrivr Oct 09 '18 at 12:50
  • 1
    Doesn't always have to be RGB888, from teh qt5 docs, https://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. – Mark Carpenter Jr Jan 02 '20 at 13:48
  • @MarkCarpenterJr Is there any way to determine which image format I need? Tried several from your link but none works. – Matthias May 12 '20 at 15:58
  • @Matthias 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. – Mark Carpenter Jr May 12 '20 at 17:08
  • 2
    With OpenCV you want to use `QImage.Format_BGR888` as OpenCV uses BGR, not RGB. – fferri Apr 04 '22 at 19:05
  • @fferri 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? – s.paszko Jul 01 '22 at 10:26
  • @s.paszko `QImage.Format_BGR888` [was added in Qt 5.14](https://doc.qt.io/qtforpython-5/PySide2/QtGui/QImage.html#PySide2.QtGui.PySide2.QtGui.QImage.Format), upgrade – fferri Jul 02 '22 at 11:13
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()
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)
SkyCityRuler
  • 81
  • 1
  • 2
4

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)
JTIM
  • 2,774
  • 1
  • 34
  • 74
so860
  • 408
  • 3
  • 12
3

Here's my take on this:

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

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

    return qpixmap
Ivan
  • 311
  • 3
  • 7
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))
Sajjad Aemmi
  • 2,120
  • 3
  • 13
  • 25
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))
smoothumut
  • 3,423
  • 1
  • 25
  • 35
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))
jack chyna
  • 83
  • 4
  • 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 works – Luke_ Apr 19 '22 at 12:40
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.

Andreas Violaris
  • 2,465
  • 5
  • 13
  • 26