Enregistrement d'un tableau Numpy en tant qu'image

261

J'ai une matrice dans le type d'un tableau Numpy. Comment pourrais-je l'écrire sur le disque en tant qu'image? Tout format fonctionne (png, jpeg, bmp ...). Une contrainte importante est que le PIL n'est pas présent.

M456
la source
12
Je voudrais juste noter que certaines des réponses ci-dessous, et sûrement certaines des personnes venant et trouvant cette question, ne rencontrent pas la contrainte listée ci-dessus d'être sans PIL . Étant donné que certains demandeurs et certaines réponses évitent tous deux cette contrainte, j'encourage tous ceux qui sont ici et cela ne me dérange pas d'avoir PIL à regarder ci-dessous, et toutes les réponses non-PIL (nouvelles ou anciennes) à mentionner qu'elles sont un PIL-est utilisé type de réponse, pour se distinguer des réponses répondant à la contrainte d'origine.
lindes

Réponses:

54

Vous pouvez utiliser PyPNG . Il s'agit d'un pur encodeur / décodeur PNG open source Python (sans dépendances) et il prend en charge l' écriture de tableaux NumPy sous forme d'images.

dF.
la source
4
N'oubliez pas de mettre à l'échelle les valeurs dans la bonne plage pour PNG, généralement 0..255. Les plages de valeurs dans les réseaux de neurones sont souvent de 0..1 ou -1..1.
Tomáš Gavenčiak
8
PyPNG est pur Python, ce qui réduit ses dépendances externes, mais le rend beaucoup plus lent que PIL et ses classes dérivées. Par exemple, enregistrer une image 3000x4000 sur ma machine a pris 4,05 secondes avec PyPNG mais seulement 0,59 secondes avec scipy.misc.imsave (6x plus rapide).
Zvika
@ TomášGavenčiak - scipy.misc.imsave est désormais déconseillé dans les nouvelles versions de Scipy. Une alternative quelques commentaires ci-dessous est d'utiliser imageio.imwrite ('image_file.jpg', array)
Psi-Ed
259

Cela utilise PIL, mais certains pourraient le trouver utile:

import scipy.misc
scipy.misc.imsave('outfile.jpg', image_array)

EDIT : La scipyversion actuelle a commencé à normaliser toutes les images afin que min (données) deviennent noires et max (données) deviennent blanches. Ceci n'est pas souhaité si les données doivent être des niveaux de gris exacts ou des canaux RVB exacts. La solution:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
Steve Tjoa
la source
19
imsave vit dans ... / scipy / misc / pilutil.py qui utilise PIL
denis
5
Soyez prudent lors de la conversion en jpg car il est avec perte et vous risquez donc de ne pas pouvoir récupérer les données exactes utilisées pour générer l'image.
Feanil
8
Ceci est désormais obsolète dans l'utilisation de scipy 0.19 - scipy.io.imwrite
g.stevo
6
"imsave est déconseillé dans SciPy 1.0.0 et sera supprimé dans 1.2.0" ( doc Scipy 1.1.0 )
noobar
15
scipy.misc.imsave est obsolète. utiliser import imageio; imageio.imwrite ('file_name.jpg', nmupy_array)
ChaosPredictor
228

Une réponse en utilisant PIL (juste au cas où cela serait utile).

étant donné un tableau numpy "A":

from PIL import Image
im = Image.fromarray(A)
im.save("your_file.jpeg")

vous pouvez remplacer "jpeg" par presque n'importe quel format souhaité. Plus de détails sur les formats ici

migas
la source
5
L'image est un module de PIL. Faire "imprimer l'image .__ fichier__"
Juh_
10
Très utile pour ceux d'entre nous qui se sont promenés ici et ont PIL - Je pense que je vais utiliser from PIL import Imagepour être clair ...
sage
4
Si vous avez une image RVB, vous pouvez obtenir l'image en utilisant im = Image.fromarray (A) .convert ('RGB') Plus d'infos: stackoverflow.com/questions/4711880/…
Roger Veciana
L'utilisation du troisième axe d'un tableau de uint8 pour coder RVB fonctionne avec cette méthode. Le module PIL peut être installé à l'aide d'un "oreiller d'installation de pip".
bli
1
@Ludovico Verniani Il ne déforme pas les images, mais il utilise un codage couleur quelque peu inhabituel dans lequel l'ordre des couleurs est BGR plutôt que RVB.
Zvika
88

Avec matplotlib:

import matplotlib

matplotlib.image.imsave('name.png', array)

Fonctionne avec matplotlib 1.3.1, je ne connais pas la version inférieure. De la docstring:

Arguments:
  *fname*:
    A string containing a path to a filename, or a Python file-like object.
    If *format* is *None* and *fname* is a string, the output
    format is deduced from the extension of the filename.
  *arr*:
    An MxN (luminance), MxNx3 (RGB) or MxNx4 (RGBA) array.

entrez la description de l'image ici

christianbrodbeck
la source
En utilisant cela. Mais souffrant d'une fuite de mémoire
SolessChong
matplotlib.imsave () dans les versions plus récentes
Vinay Lodha
6
C'est matplotlib.pyplot.imsavedans matplotlib 2+
Aleksei Petrenko
1
@HughPerkins essaie Pillow en remplacement de PIL dans Python 3
christianbrodbeck
10
import matplotlib.pyplot as pltpuisplt.imsave('name.png', array)
Alessandro Jacopson
62

Pure Python (2 & 3), un extrait sans dépendances tierces.

Cette fonction écrit des fichiers RGBAPNG compressés en couleurs vraies (4 octets par pixel) .

def write_png(buf, width, height):
    """ buf: must be bytes or a bytearray in Python3.x,
        a regular string in Python2.x.
    """
    import zlib, struct

    # reverse the vertical line order and add null bytes at the start
    width_byte_4 = width * 4
    raw_data = b''.join(
        b'\x00' + buf[span:span + width_byte_4]
        for span in range((height - 1) * width_byte_4, -1, - width_byte_4)
    )

    def png_pack(png_tag, data):
        chunk_head = png_tag + data
        return (struct.pack("!I", len(data)) +
                chunk_head +
                struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head)))

    return b''.join([
        b'\x89PNG\r\n\x1a\n',
        png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
        png_pack(b'IDAT', zlib.compress(raw_data, 9)),
        png_pack(b'IEND', b'')])

... Les données doivent être écrites directement dans un fichier ouvert en binaire, comme dans:

data = write_png(buf, 64, 64)
with open("my_image.png", 'wb') as fh:
    fh.write(data)

ideasman42
la source
2
Cela semble être exactement ce que je recherche, mais pourriez-vous ajouter quelques commentaires? Je ne vois pas comment cela écrit dans un fichier. Devez-vous écrire la sortie dans un fichier précédemment ouvert? Merci!
PhilMacKay
1
@PhilMacKay, les données doivent juste être écrites dans un fichier binaire. commentaire ajouté.
ideasman42
1
Quelqu'un peut-il spécifier dans quel format l'image ( buf) est censée être? Il ne semble pas être un tableau engourdi ...
christianbrodbeck
1
@christianmbrodbeck, un bytearray (RGBARGBA ...)
ideasman42
1
Merci @ ideasman42. J'ai porté ce code pour l'utiliser dans Blender .
emackey
57

Il y a opencvpour python ( documentation ici ).

import cv2
import numpy as np

cv2.imwrite("filename.png", np.zeros((10,10)))

utile si vous devez faire plus de traitement que l'enregistrement.

Xocoatzin
la source
1
Pourquoi un tableau de taille 10? Qu'est-ce qui a conduit au choix de 10 dans cette solution?
Gathide
3
@Gathide Juste comme un exemple d'écriture d'une matrice numpy arbitraire dans un fichier. Dans la vraie vie, remplacez np.zeros((10,10))par votre image.
Xocoatzin
5
Comment puis-je ajouter quelque chose comme cmap="gray"lorsque j'enregistre l'image à l'aide de cv2?
Mona Jalal
@Xocoatzin Lien brisé?
jtlz2
1
@ jtlz2 Lien mis à jour.
Xocoatzin
30

Si vous avez matplotlib, vous pouvez faire:

import matplotlib.pyplot as plt
plt.imshow(matrix) #Needs to be in row,col order
plt.savefig(filename)

Cela sauvera l'intrigue (pas les images elles-mêmes). entrez la description de l'image ici

Doppler
la source
10
Non, pour l'interface pyplot, le plt.figure () est superflu. De plus, vous n'avez besoin de plt.show () que si vous souhaitez également voir une fenêtre de figure - dans ce cas, seule la sauvegarde d'un fichier image était souhaitée, il n'était donc pas nécessaire d'appeler show ().
DopplerShift
7
Notez que le fichier d'image résultant contiendra les axes et la zone grise de la figure matlplotlib - pas seulement les données de pixels.
Dave
1
ne fonctionnera pas si vous exécutez votre script sur un hôte distant, en y accédant sans prise en charge de l'interface graphique.
Temak
Si vous souhaitez afficher l'image dans un bloc-notes, vous pouvez ajouter ce qui suit: >> "depuis IPython.display import Image" puis >> "Image (filename = filename)"
Robert
Pour retirer l'axe:plt.axis('off')
yakout
15

Vous pouvez utiliser la bibliothèque 'skimage' en Python

Exemple:

from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)
PURNENDU MISHRA
la source
15

scipy.miscdonne un avertissement de dépréciation sur la imsavefonction et suggère l'utilisation de imageioplutôt.

import imageio
imageio.imwrite('image_name.png', img)
Sefa
la source
12

Addendum à la réponse de @ ideasman42:

def saveAsPNG(array, filename):
    import struct
    if any([len(row) != len(array[0]) for row in array]):
        raise ValueError, "Array should have elements of equal size"

                                #First row becomes top row of image.
    flat = []; map(flat.extend, reversed(array))
                                 #Big-endian, unsigned 32-byte integer.
    buf = b''.join([struct.pack('>I', ((0xffFFff & i32)<<8)|(i32>>24) )
                    for i32 in flat])   #Rotate from ARGB to RGBA.

    data = write_png(buf, len(array[0]), len(array))
    f = open(filename, 'wb')
    f.write(data)
    f.close()

Vous pouvez donc faire:

saveAsPNG([[0xffFF0000, 0xffFFFF00],
           [0xff00aa77, 0xff333333]], 'test_grid.png')

Produire test_grid.png:

Grille de rouge, jaune, aqua foncé, gris

(La transparence fonctionne également, en réduisant l'octet de poids fort de 0xff.)

Evgeni Sergeev
la source
8

Pour ceux qui recherchent un exemple direct pleinement fonctionnel:

from PIL import Image
import numpy

w,h = 200,100
img = numpy.zeros((h,w,3),dtype=numpy.uint8) # has to be unsigned bytes

img[:] = (0,0,255) # fill blue

x,y = 40,20
img[y:y+30, x:x+50] = (255,0,0) # 50x30 red box

Image.fromarray(img).convert("RGB").save("art.png") # don't need to convert

aussi, si vous voulez des jpeg de haute qualité
.save(file, subsampling=0, quality=100)

Flaque
la source
6

matplotlib svn a une nouvelle fonction pour enregistrer les images comme une simple image - pas d'axes etc. c'est une fonction très simple à rétroporter aussi, si vous ne voulez pas installer svn (copié directement depuis image.py dans matplotlib svn, supprimé le docstring pour plus de concision):

def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None, origin=None):
    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure

    fig = Figure(figsize=arr.shape[::-1], dpi=1, frameon=False)
    canvas = FigureCanvas(fig)
    fig.figimage(arr, cmap=cmap, vmin=vmin, vmax=vmax, origin=origin)
    fig.savefig(fname, dpi=1, format=format)
Autoplectique
la source
3

Le monde n'a probablement pas encore besoin d'un autre paquet pour écrire un tableau numpy dans un fichier PNG, mais pour ceux qui n'en ont pas assez, j'ai récemment mis en place numpngwsur github:

https://github.com/WarrenWeckesser/numpngw

et sur pypi: https://pypi.python.org/pypi/numpngw/

La seule dépendance externe est numpy.

Voici le premier exemple du examplesrépertoire du référentiel. La ligne essentielle est tout simplement

write_png('example1.png', img)

imgest un tableau numpy. Tout le code avant cette ligne est des instructions d'importation et du code à créer img.

import numpy as np
from numpngw import write_png


# Example 1
#
# Create an 8-bit RGB image.

img = np.zeros((80, 128, 3), dtype=np.uint8)

grad = np.linspace(0, 255, img.shape[1])

img[:16, :, :] = 127
img[16:32, :, 0] = grad
img[32:48, :, 1] = grad[::-1]
img[48:64, :, 2] = grad
img[64:, :, :] = 127

write_png('example1.png', img)

Voici le fichier PNG qu'il crée:

example1.png

Warren Weckesser
la source
Je suis curieux, en quoi votre bibliothèque est-elle différente des autres? Est-ce plus rapide? At-il des fonctionnalités de fantaisie?
F Lekschas
Quelques fonctionnalités: (1) Il utilise des tableaux numpy. (2) Il est écrit en utilisant uniquement python et numpy, il ne nécessite donc pas l'installation d'une bibliothèque C. (3) Il peut créer des fichiers PNG animés. (4) Il fournit une classe pour écrire des animations matplotlib sous forme de fichiers PNG animés.
Warren Weckesser
Merci! Je serais curieux de voir comment il se compare à stackoverflow.com/a/19174800/981933 en termes de performances, qui est également du pur python. L'ancienne méthode est au-dessus de 2x plus rapide que PIL, ce qui est assez génial.
Peu importe
2

En supposant que vous souhaitiez une image en niveaux de gris:

im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")
Guillaume Lebreton
la source
2

Imageio est une bibliothèque Python qui fournit une interface simple pour lire et écrire une large gamme de données d'images, y compris des images animées, des vidéos, des données volumétriques et des formats scientifiques. Il est multiplateforme, fonctionne sur Python 2.7 et 3.4+, et est facile à installer.

Voici un exemple d'image en niveaux de gris:

import numpy as np
import imageio

# data is numpy array with grayscale value for each pixel.
data = np.array([70,80,82,72,58,58,60,63,54,58,60,48,89,115,121,119])

# 16 pixels can be converted into square of 4x4 or 2x8 or 8x2
data = data.reshape((4, 4)).astype('uint8')

# save image
imageio.imwrite('pic.jpg', data)
Denis Rasulev
la source
1

Si vous utilisez déjà [Py] Qt, vous pourriez être intéressé par qimage2ndarray . À partir de la version 1.4 (qui vient d'être publiée), PySide est également pris en charge, et il y aura une minuscule imsave(filename, array)fonction similaire à scipy's, mais utilisant Qt au lieu de PIL. Avec 1.3, utilisez simplement quelque chose comme ceci:

qImage = array2qimage(image, normalize = False) # create QImage from ndarray
success = qImage.save(filename) # use Qt's image IO functions for saving PNG/JPG/..

(Un autre avantage de la version 1.4 est qu'il s'agit d'une solution python pure, ce qui la rend encore plus légère.)

hans_meine
la source
La version 1.4 est maintenant disponible. :-) (J'ai modifié la réponse en conséquence.)
hans_meine
1

Si vous travaillez dans un environnement python Spyder, cela ne peut pas être plus facile que de simplement cliquer avec le bouton droit sur le tableau dans l'explorateur de variables, puis choisissez l'option Afficher l'image.

entrez la description de l'image ici

Cela vous demandera d'enregistrer l'image sur dsik, principalement au format PNG.

La bibliothèque PIL ne sera pas nécessaire dans ce cas.

abunickabhi
la source
1

Utilisez cv2.imwrite.

import cv2
assert mat.shape[2] == 1 or mat.shape[2] == 3, 'the third dim should be channel'
cv2.imwrite(path, mat) # note the form of data should be height - width - channel  
Christy Lee
la source
1

pour enregistrer un tableau numpy en tant qu'image, vous avez plusieurs choix:

1) le meilleur des autres: OpenCV

 import cv2   
 cv2.imwrite('file name with extension(like .jpg)', numpy_array)

2) Matplotlib

  from matplotlib import pyplot as plt
  plt.imsave('file name with extension(like .jpg)', numpy_array)

3) PIL

  from PIL import Image
  image = Image.fromarray(numpy_array)
  image.save('file name with extension(like .jpg)')

4) ...

nima farhadi
la source