'Convert QImage BGR888 to Mat (OpenCV) in Python

I'm trying to convert a QImage into Mat format (to save a video from a sequence of QImage) in Python.

I've been trying the different solutions proposed online, such as the ones described here:

PyQt/PySide: How do I convert QImage into OpenCV's MAT format

https://code-examples.net/en/q/12faee7

One of this solution is the following one:

def convertQImageToMat(incomingImage):
        incomingImage = incomingImage.convertToFormat(4)
        width = incomingImage.width()
        height = incomingImage.height()
        ptr = incomingImage.bits()
        ptr.setsize(incomingImage.byteCount())
        arr = np.array(ptr).reshape(height, width, 4)  #  Copies the data
        return arr

But when trying this solution, I end up with a black video of 105KB containing no frame (whatever the number of frames that I write to my cv2.VideoWriter).

If I try this other solution:

def convertQImageToMat(incomingImage):
        incomingImage = incomingImage.convertToFormat(QImage.Format.Format_BGR888)
        width = incomingImage.width()
        height = incomingImage.height()
        ptr = incomingImage.constBits()
        arr = np.array(ptr).reshape(height, width, 4) 
        return arr

I then end up with this error:

ValueError: cannot reshape array of size 1 into shape (3060,5440,4)

And no video is then produced (because the above error occurs during frame format conversion, before the cv2.VideoWrite function)

I believe these erros may be due to the non-standard initial format of my QImage, which is as follow:

img = QImage(self.buf, self.width, self.height, (self.width * 24 + 31) // 32 * 4, QImage.Format_BGR888)

I've seen here a solution to convert a BGR888 QImage into Mat format (Error when converting Qimage to Mat opencv), but this solution is in C++, which I don't master.

Anyone here have already tried to convert such a BGR888 QImage into Mat in Python, or knows how to convert the c++ code provided in the above link into Python?

Many thanks in advance for your help

EDIT 27/04/2022 13:08

I found a way using a solution I found here (https://devdreamz.com/question/158707-in-pyqt-how-do-i-convert-qimage-to-a-list-of-pixels). Here is the edited function:

def convertQImageToMat(incomingImage):
        incomingImage = incomingImage.convertToFormat(QImage.Format_RGBX8888)
        ptr = incomingImage.constBits()
        ptr.setsize(incomingImage.byteCount())
        cv_im_in = np.array(ptr, copy=True).reshape(incomingImage.height(), incomingImage.width(), 4)
        cv_im_in = cv2.cvtColor(cv_im_in, cv2.COLOR_BGRA2RGB)
        return cv_im_in

This works fine, however, I am now wondering whether convertToFormat(QImage.Format_RGBX8888) alters or not my image (since its initial format is BGR888). If someone can confirm that this does not change anything, then I could call this a solved issue.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source