相关文章推荐
沉稳的木瓜  ·  Python_PyCharm_Turtle- ...·  2 天前    · 
有腹肌的伤痕  ·  javascript ...·  11 小时前    · 
飘逸的饭卡  ·  python移动文件问题 - ...·  3 小时前    · 
威武的罐头  ·  Logging Architecture ...·  4 月前    · 
会搭讪的饭盒  ·  C# ...·  8 月前    · 
腼腆的围巾  ·  r - Raster to points ...·  12 月前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I've been struggling with this challenge for the best of today, I've managed to get a good point using previous posts and other resources.

I'm trying to convert a PIL.Image to a QPixmap so that I can display using a QgraphicsScene on my PyQT GUI. However when the picture is displayed the colours have changed?? Has anyone ever experienced this issue?

The code I use for this is as below.

self.graphicsScene.clear()
im = Image.open('Penguins.jpg')
im = im.convert("RGBA")
data = im.tobytes("raw","RGBA")
qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_ARGB32)
pix = QtGui.QPixmap.fromImage(qim)
self.graphicsScene.addPixmap(pix)
self.graphicsView.fitInView(QtCore.QRectF(0,0,im.size[0], im.size[1]), QtCore.Qt.KeepAspectRatio)
self.graphicsScene.update()

Im on windows 7 64bit, using python 3.4 with PyQt4 and pillow 3.1.0. The results im getting can be seen below.

Original picture

Picture displayed in GUI

Thanks in advance :).

In your PIL image the last band is the alpha channel, whereas in the Qt image the alpha channel is the first (RGBA vs. ARGB). There may be other ways of permuting the bands but the easiest way seems to use the ImageQt class.

from PIL.ImageQt import ImageQt
qim = ImageQt(im)
pix = QtGui.QPixmap.fromImage(qim)
                as @Michael is mentioning in his answer, this crashes e.g. with Win10/Python3.7.4/PyQt5, Any ideas why and how to maybe easily fix it instead of using Michael's lengthy workaround?
– theozh
                Oct 21, 2020 at 8:46
                Hi @theozh. I don't know but I am not involved in the Pillow project so I am not the one to ask. I recommend making a bug report in the Pillow issue list on GitHub. Make sure to include a copy error message and complete stack trace.
– titusjan
                Oct 21, 2020 at 9:14

I dont know why, but ImageQt crashed in my system Win10, Python3, Qt5. So i went to an other direction and tried a solution found on github. This code doesnt crash, but gives a effect shown in first post.

My solution for this is, to separate the RGB pic to each color and assemble it as BGR or BGRA before converting it to a Pixmap

    def pil2pixmap(self, im):
    if im.mode == "RGB":
        r, g, b = im.split()
        im = Image.merge("RGB", (b, g, r))
    elif  im.mode == "RGBA":
        r, g, b, a = im.split()
        im = Image.merge("RGBA", (b, g, r, a))
    elif im.mode == "L":
        im = im.convert("RGBA")
    # Bild in RGBA konvertieren, falls nicht bereits passiert
    im2 = im.convert("RGBA")
    data = im2.tobytes("raw", "RGBA")
    qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_ARGB32)
    pixmap = QtGui.QPixmap.fromImage(qim)
    return pixmap

I've tested RGB, and PIL saves data with the qt format Format_RGB888:

im = im.convert("RGB")
data = im.tobytes("raw","RGB")
qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_RGB888)

I haven't tested it, but I assume for that RGBA it will be the equivalent format Format_RGBA8888:

im = im.convert("RGBA")
data = im.tobytes("raw","RGBA")
qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_RGBA8888)
                Can you please try my answer (stackoverflow.com/a/75498151/1091935) and see if that fixes your RGB problem?
– DirkR
                Feb 19 at 5:20

@titusjan's answer didn't work for me. Both @Michael and @Jordan have solutions that worked. A simpler version of @Michael's is just to redefine how the bytes are written for the image. So this works for me:

im2 = im.convert("RGBA")
data = im2.tobytes("raw", "BGRA")
qim = QtGui.QImage(data, im.width, im.height, QtGui.QImage.Format_ARGB32)
pixmap = QtGui.QPixmap.fromImage(qim)

The only difference is that I swapped the order for the encoding, e.g. to 'BGRA' instead of 'RGBA'.

This maybe usefull

Creates an ImageQt object from a PIL Image object. This class is a subclass of QtGui.QImage, which means that you can pass the resulting objects directly to PyQt4/5 API functions and methods. This operation is currently supported for mode 1, L, P, RGB, and RGBA images. To handle other modes, you need to convert the image first.

https://pillow.readthedocs.io/en/stable/reference/ImageQt.html

One problems that many of the existing answers run into is that Qt seems to have an undocumented implicit assumption that by default image lines need to start on a 32 bit boundary. For images with alpha channel that is automatically the case, but for RGB images that have sizes that are not divisible by 4 it is not, and the resulting QImage typically looks grey and skewed, or it could crash.

The easiest solution is to use the bytesPerLine parameter of the QImage constructor to explicitly tell it to start the next line at the right position and RGB works fine (no clue why it doesn't do that automatically):

    im = im.convert("RGB")
    data = im.tobytes("raw", "RGB") 
    qi = QImage(data, im.size[0], im.size[1], im.size[0]*3, QImage.Format.Format_RGB888)
    pix = QPixmap.fromImage(qi)

Another possible reason for crashes is the data retention. QImage does not make a copy of or add a reference to the data, it assumes the data is valid until the QImage is destroyed. For this specific answer which immediately transforms the QImage into a QPixmap it shouldn't matter, as the QPixmap keeps a copy of the data, but if for whatever reason you hang on to the QImage, you also need to keep a reference to the data around.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.