2 votes

QImage déforme certaines images mais pas d'autres

Je travaille avec des piles de tif et QImage semble déformer certaines images à un angle de 45 degrés. Matplotlib est capable d'afficher les images sans problème dans les deux cas de test (les liens vers les deux piles tif sont fournis ci-dessous), donc je ne pense pas que je me sois trompé de tableau quelque part.

Voici un exemple de travail : (NOTE : cet exemple ne montre que la première image de la pile tif pour plus de simplicité)

import matplotlib.pyplot as plt
import sys
from PIL import Image
from PyQt5.QtGui import QPixmap, QImage 
from PyQt5.QtWidgets import (QMainWindow, QApplication, QVBoxLayout, 
                             QWidget, QFileDialog, QGraphicsPixmapItem, QGraphicsView,
                             QGraphicsScene)

import numpy as np

class Example(QMainWindow):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        # set up a widget to hold a pixmap
        wid = QWidget(self)
        self.setCentralWidget(wid)
        self.local_grview = QGraphicsView()
        self.local_scene = QGraphicsScene()
        vbox = QVBoxLayout()                
        self.local_grview.setScene( self.local_scene )
        vbox.addWidget(self.local_grview)
        wid.setLayout(vbox)

        # load and display the image
        self.loadImage()

        # display the widget
        self.show()

        # also use matplotlib to display the data as it should appear
        plt.imshow(self.dataUint8[0], cmap='gray')
        plt.show()

    def loadImage(self):
        fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')[0]

        # use the tif reader to read in the tif stack
        self.data = self.readTif(fname)

        # convert to uint8 for display
        self.dataUint8 = self.uint8Convert(self.data)

        ###############################################################################################################################
        # I suspect this is where something goes wrong
        ###############################################################################################################################
        # create a QImage object
        self.im = QImage(self.dataUint8[0], self.dataUint8[0].shape[1], self.dataUint8[0].shape[0], QImage.Format_Grayscale8)
        # if we save using self.im.save() we also have a skewed image
        ###############################################################################################################################

        # send the QImage object to the pixmap generator
        self.pixmap = QPixmap(self.im)

        self.pixMapItem = QGraphicsPixmapItem(self.pixmap, None)
        self.local_scene.addItem(self.pixMapItem)

    def readTif(self, filename): # use this function to read in a tif stack and return a 3D numpy array
        # read in the file
        stack = Image.open(filename)    

        # extract each frame from the file and store in the frames variable
        frames = []
        i = 0
        while True:
            try:
                stack.seek(i) # move to the ith position in the stack
                frames.append(np.array(stack) )
                i += 1
            except EOFError:
                # end of stack
                break
        del stack # probably unnecessary but this presumably saves a bit of memory

        return frames 

    def uint8Convert(self, frames): # use this function to scale a 3D numpy array of floats to 0-255 so it plays well with Qt methods

        # convert float array to uint8 array
        if np.min(frames)<0:
            frames_uint8 = [np.uint8((np.array(frames[i]) - np.min(frames[i]))/np.max(frames[i])*255) for i in range(np.shape(frames)[0])]
        else:
            frames_uint8 = [np.uint8(np.array(frames[i])/np.max(frames[i])*255) for i in range(np.shape(frames)[0])]

        return frames_uint8

if __name__=='__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

Voici une capture d'écran de la sortie :

Qimage vs matplotlib

enter image description here

Voici un lien vers une pile tif qui s'affiche correctement :

https://drive.google.com/uc?export=download&id=0B9EG5AHWC9qzX3NrNTJRb2toV2c

Et voici un lien vers une pile tif qui devient oblique lorsqu'elle est affichée :

https://drive.google.com/uc?export=download&id=0B9EG5AHWC9qzbFB4TDU4c2x1OE0

Une aide pour comprendre pourquoi QImage fausse cette image serait très appréciée. La seule différence majeure entre les deux piles tif est que celle qui s'affiche de travers a une zone noire (zéros) autour de l'image, ce qui rend le tableau plus grand.

MISE À JOUR : J'ai découvert que si je recadre l'image en question à 1024x1024 ou 512x512 ou 1023x1024 QImage s'affiche correctement mais le recadrage en 1024x1023 s'affiche de manière biaisée. Il apparaît donc que la longueur x (horizontale) doit être une puissance de 2 afin que QImage pour le traiter comme prévu. C'est une limitation ridicule ! Il doit y avoir quelque chose que je ne comprends pas. Il y a sûrement un moyen de gérer des tableaux de forme arbitraire.

...Je suppose qu'en principe, on pourrait d'abord appliquer une inclinaison à l'image et simplement laisser QImage le redresser... (<== pas fan de cette solution)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X