37 votes

Comment convertir une figure Matplotlib en objet PIL Image (sans sauvegarder l'image) ?

Comme le titre l'indique, j'essaie de convertir un fichier fig à un PIL.Image . Je suis actuellement en mesure de le faire en sauvegardant d'abord le fichier fig sur le disque, puis d'ouvrir ce fichier à l'aide de Image.open() mais le processus prend plus de temps que prévu et j'espère qu'en sautant l'étape de l'enregistrement local, il sera un peu plus rapide.

Voici ce que j'ai pour l'instant :

# build fig
figsize, dpi = self._calc_fig_size_res(img_height)
fig = plt.Figure(figsize=figsize)
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
ax.imshow(torch.from_numpy(S).flip(0), cmap = cmap)
fig.subplots_adjust(left = 0, right = 1, bottom = 0, top = 1)
ax.axis('tight'); ax.axis('off')

# export
fig.savefig(export_path, dpi = dpi)

# open image as PIL object
img = Image.open(export_path)

J'ai essayé de le faire après avoir construit la figurine (juste avant l'étape d'exportation) :

pil_img = Image.frombytes('RGB', canvas.get_width_height(), canvas.tostring_rgb())

Mais l'image n'est pas affichée dans son intégralité. On dirait qu'il s'agit d'un recadrage du coin supérieur gauche, mais il pourrait s'agir d'une représentation bizarre des données - je travaille avec des spectrogrammes, de sorte que les images sont assez abstraites.

28voto

Lewis Morris Points 47

EDIT # 2

PIL.Image.frombytes('RGB', 
fig.canvas.get_width_height(),fig.canvas.tostring_rgb())

prend environ 2 ms par rapport aux 35/40 ms de l'exemple ci-dessous.

C'est le moyen le plus rapide que j'ai trouvé jusqu'à présent.


Je me suis également penché sur cette question aujourd'hui.

Dans la documentation de matplotlib, la fonction savefig avait ceci.

pil_kwargsdict, optionnel Arguments de mots-clés supplémentaires qui sont transmis à PIL.Image.save lors de l'enregistrement de la figure. Ne s'applique qu'aux formats qui sont sauvegardés à l'aide de Pillow, c'est-à-dire qui sont enregistrés à l'aide de Pillow, c'est-à-dire JPEG, TIFF et (si le mot-clé a une valeur à une valeur non nulle) PNG.

Cela doit signifier qu'il s'agit déjà d'une image pilote avant l'enregistrement, mais je ne la vois pas.

Vous pouvez suivre cette procédure

Matplotlib : sauvegarde du tracé dans un tableau numpy

Pour le mettre dans un tableau numpy et ensuite faire

PIL.Image.fromarray(array)

Vous devrez peut-être inverser les canaux de BGR à RGB avec le tableau [ :, :, ::-1].

EDITAR:

J'ai testé tous les moyens que j'ai trouvés jusqu'à présent.

import io

def save_plot_and_get():
    fig.savefig("test.jpg")
    img = cv2.imread("test.jpg")
    return PIL.Image.fromarray(img)

def buffer_plot_and_get():
    buf = io.BytesIO()
    fig.savefig(buf)
    buf.seek(0)
    return PIL.Image.open(buf)

def from_canvas():
    lst = list(fig.canvas.get_width_height())
    lst.append(3)
    return PIL.Image.fromarray(np.fromstring(fig.canvas.tostring_rgb(),dtype=np.uint8).reshape(lst))

Résultats

%timeit save_plot_and_get()

35,5 ms ± 148 µs par boucle (moyenne ± écart-type de 7 passages, 10 boucles chacun)

%timeit save_plot_and_get()

35,5 ms ± 142 µs par boucle (moyenne ± écart-type de 7 passages, 10 boucles chacun)

%timeit buffer_plot_and_get()

40,4 ms ± 152 µs par boucle (moyenne ± écart-type de 7 passages, 10 boucles chacun)

23voto

kotchwane Points 968

J'utilise la fonction suivante :

def fig2img(fig):
    """Convert a Matplotlib figure to a PIL Image and return it"""
    import io
    buf = io.BytesIO()
    fig.savefig(buf)
    buf.seek(0)
    img = Image.open(buf)
    return img

Exemple d'utilisation :

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

x = np.arange(-3,3)
plt.plot(x)
fig = plt.gcf()

img = fig2img(fig)

img.show()

3voto

Josh Sharkey Points 564

Je l'ai signalé comme un doublon et je l'ai fermé parce que j'ai utilisé le mauvais lien.

Quoi qu'il en soit, la réponse se trouve peut-être ici :

Comment sauvegarder une figure pylab dans un fichier en mémoire qui peut être lu dans une image PIL ?

0voto

Zach Points 141

Malheureusement, cela n'a pas permis d'augmenter la vitesse, mais je vais tout de même publier ma solution spécifique ci-dessous au cas où quelqu'un aurait un problème similaire :

# build fig
figsize, dpi = self._calc_fig_size_res(img_height)
fig = plt.Figure(figsize = figsize)
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
ax.imshow(torch.from_numpy(S).flip(0), cmap = camp)
fig.subplots_adjust(left = 0, right = 1, bottom = 0, top = 1)
ax.axis('tight'); ax.axis('off')

# convert to PIL Image object
buf = io.BytesIO()
fig.savefig(buf, format='png', dpi = dpi)
buf.seek(0)
pil_img = deepcopy(Image.open(buf))
buf.close()

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