web-dev-qa-db-fra.com

Spécifier et enregistrer une figure avec une taille exacte en pixels

Disons que j'ai une image de taille 3841 x 7195 pixels. Je souhaite enregistrer le contenu de la figure sur le disque, ce qui donne une image de la taille exacte que je spécifie en pixels.

Pas d'axe, pas de titre. Juste l'image. Personnellement, je ne me soucie pas des DPI, je veux seulement spécifier la taille de l'image sur l'écran du disque en pixels .

J'ai lu autrediscussions , et ils semblent tous effectuer des conversions en pouces, puis spécifier les dimensions de la figure en pouces et ajuster les ppp d'une manière ou d'une autre. J'aimerais éviter de composer avec la perte de précision potentielle pouvant résulter des conversions de pixels en pouces.

J'ai essayé avec:

w = 7195
h = 3841
fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(im_np, aspect='normal')
fig.savefig(some_path, dpi=1)

sans chance (Python se plaint que la largeur et la hauteur doivent être inférieures à 32768 (?))

D'après tout ce que j'ai vu, matplotlib nécessite que la taille du chiffre soit spécifiée dans inches et dpi, mais je ne m'intéresse qu'à les pixels La figure prend dans le disque. Comment puis-je faire ceci?

Pour clarifier: je cherche un moyen de faire cela avec matplotlib, et non avec d’autres bibliothèques de sauvegarde d’images.

121

Matplotlib ne fonctionne pas directement avec les pixels, mais plutôt avec les tailles physiques et le DPI. Si vous souhaitez afficher un chiffre avec une certaine taille en pixels, vous devez connaître le DPI de votre moniteur. Par exemple, ce lien le détectera pour vous.

Si vous avez une image de 3841x7195 pixels, il est peu probable que votre moniteur soit aussi grand, vous ne pourrez donc pas afficher un personnage de cette taille (matplotlib exige que le personnage s'adapte à l'écran, si vous demandez trop grand, il sera réduit à la taille de l’écran). Imaginons que vous vouliez une image de 800 x 800 pixels, par exemple. Voici comment afficher une image de 800 x 800 pixels sur mon moniteur (my_dpi=96):

plt.figure(figsize=(800/my_dpi, 800/my_dpi), dpi=my_dpi)

Donc, vous divisez simplement les dimensions en pouces par votre DPI.

Si vous souhaitez enregistrer un chiffre d'une taille spécifique, il en va tout autrement. Les DPI d'écran ne sont plus si importants (à moins que vous ne demandiez un chiffre qui ne rentre pas dans l'écran). En utilisant le même exemple de 800 x 800 pixels, nous pouvons l’enregistrer dans différentes résolutions à l’aide du mot clé dpi de savefig. Pour l'enregistrer dans la même résolution que l'écran, utilisez simplement le même dpi:

plt.savefig('my_fig.png', dpi=my_dpi)

Pour l'enregistrer en tant qu'image 8000x8000 pixels, utilisez un dpi supérieur à 10 fois supérieur:

plt.savefig('my_fig.png', dpi=my_dpi * 10)

Notez que le réglage du DPI n'est pas pris en charge par tous les backends. Ici, le backend PNG est utilisé, mais les backends pdf et ps implémenteront la taille différemment. En outre, la modification de la résolution et de la taille aura également une incidence sur la taille de la police. Une résolution plus grande conservera les mêmes tailles relatives de polices et d’éléments, mais si vous souhaitez des polices plus petites pour une taille plus grande, vous devez augmenter la taille physique au lieu de la résolution.

Pour revenir à votre exemple, si vous souhaitez enregistrer une image de 3841 x 7195 pixels, vous pouvez procéder comme suit:

plt.figure(figsize=(3.841, 7.195), dpi=100)
( your code ...)
plt.savefig('myfig.png', dpi=1000)

Notez que j'ai utilisé le chiffre de 100 pour s'adapter à la plupart des écrans, mais enregistré avec dpi=1000 pour obtenir la résolution requise. Dans mon système, cela produit un png avec 3840x7190 pixels - il semble que le DPI enregistré soit toujours inférieur de 0,02 pixels/pouce à la valeur sélectionnée, ce qui aura un effet (faible) sur les grandes images. Un peu plus de discussion à ce sujet ici .

137
tiago

Cela a fonctionné pour moi, en fonction de votre code, générant une image png de 93 Mo avec bruit de couleur et les dimensions souhaitées:

import matplotlib.pyplot as plt
import numpy

w = 7195
h = 3841

im_np = numpy.random.Rand(h, w)

fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(im_np, aspect='normal')
fig.savefig('figure.png', dpi=1)

J'utilise les dernières versions PIP des bibliothèques Python 2.7 dans Linux Mint 13.

J'espère que ça t'as aidé!

15
heltonbiker

Sur la base de la réponse acceptée par tiago, voici une petite fonction générique qui exporte un tableau numpy vers une image ayant la même résolution que le tableau:

import matplotlib.pyplot as plt
import numpy as np

def export_figure_matplotlib(arr, f_name, dpi=200, resize_fact=1, plt_show=False):
    """
    Export array as figure in original resolution
    :param arr: array of image to save in original resolution
    :param f_name: name of file where to save figure
    :param resize_fact: resize facter wrt shape of arr, in (0, np.infty)
    :param dpi: dpi of your screen
    :param plt_show: show plot or not
    """
    fig = plt.figure(frameon=False)
    fig.set_size_inches(arr.shape[1]/dpi, arr.shape[0]/dpi)
    ax = plt.Axes(fig, [0., 0., 1., 1.])
    ax.set_axis_off()
    fig.add_axes(ax)
    ax.imshow(arr)
    plt.savefig(f_name, dpi=(dpi * resize_fact))
    if plt_show:
        plt.show()
    else:
        plt.close()

Comme indiqué dans la réponse précédente de tiago, il faut d'abord trouver l'écran DPI, ce qui peut être fait ici, par exemple: http://dpi.lv

J'ai ajouté un argument supplémentaire resize_fact dans la fonction permettant d'exporter l'image à 50% (0,5) de la résolution d'origine, par exemple.

4
Cyril