What is the difference between an opencv BGR image and its reverse version RGB image[:,:,::-1]?

As you have noticed opencv reads the image in BGR format but QImage in RGB, in your first method you convert to QImage without doing the conversion and then you use rgbSwapped() method to do the conversion.

By testing the first method I get:

1000 loops, best of 5: 291 usec per loop

In the second method you try to do it before converting it to QImage but when I execute it I get the following error presuming that you also get it.

Traceback (most recent call last):
  File "xxxx.py", line 18, in <module>
    qImg = QtGui.QImage(src.data, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
TypeError: arguments did not match any overloaded call:
  QImage(): too many arguments
  QImage(QSize, QImage.Format): argument 1 has unexpected type 'memoryview'
  QImage(int, int, QImage.Format): argument 1 has unexpected type 'memoryview'
  QImage(bytes, int, int, QImage.Format): argument 1 has unexpected type 'memoryview'
  QImage(sip.voidptr, int, int, QImage.Format): argument 1 has unexpected type 'memoryview'
  QImage(bytes, int, int, int, QImage.Format): argument 1 has unexpected type 'memoryview'
  QImage(sip.voidptr, int, int, int, QImage.Format): argument 1 has unexpected type 'memoryview'
  QImage(List[str]): argument 1 has unexpected type 'memoryview'
  QImage(str, format: str = None): argument 1 has unexpected type 'memoryview'
  QImage(QImage): argument 1 has unexpected type 'memoryview'
  QImage(Any): too many arguments

And this is because numpy uses memoryview to optimize certain tasks. And in this case when doing src[:,:,::-1] one way to optimize is not to modify the data but the way to access the data, this is done through the Buffer Protocol.

And in this case QImage does not support this type of data, so the solution is to access the bytes using the tobytes() or bytes():

import cv2
from PyQt5 import QtGui, QtWidgets

if __name__ == '__main__':
    import sys
    src = cv2.imread('image.jpg')
    src = src[:,:,::-1]
    h, w, ch = src.shape
    bytesPerLine = ch * w
    qImg = QtGui.QImage(src.data.tobytes(), w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
    # Or
    # qImg = QtGui.QImage(bytes(src.data), w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QLabel()
    w.setPixmap(QtGui.QPixmap.fromImage(qImg))
    w.show()
    sys.exit(app.exec_())

Time:

500 loops, best of 5: 523 usec per loop

Another solution is to use the cvtColor() function of opencv that if you modify the data:

import cv2
from PyQt5 import QtGui, QtWidgets

if __name__ == '__main__':
    import sys
    src = cv2.imread('image.jpg')
    src = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
    h, w, ch = src.shape
    bytesPerLine = ch * w
    qImg = QtGui.QImage(src.data, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QLabel()
    w.setPixmap(QtGui.QPixmap.fromImage(qImg))
    w.show()
    sys.exit(app.exec_())

Time:

1000 loops, best of 5: 263 usec per loop

Leave a Comment