4 votes

Comment puis-je charger une image en Python, tout en la gardant compressée ?

J'ai une série d'images, toutes disponibles à la fois sur JP2 et PNG, et j'ai besoin de charger cette image sur un programme python pour les afficher dans une séquence. Maintenant j'ai besoin de montrer seulement une partie de la séquence, par exemple :

  • une fois de la trame 12 à la trame 24,
  • la deuxième fois de l'image 2 à l'image 7,
  • etc.

    charger toutes les images me prend trop de mémoire et charger à chaque fois une nouvelle séquence est une tâche longue à faire.
    il existe une fonction/méthode pour charger l'image dans un programme, mais en la gardant compressée ? Puis-je sauvegarder ces images en mémoire pour être prêt à l'emploi, mais avec une faible occupation mémoire ?

4voto

Mark Setchell Points 11698

Vous pouvez lire les jolies petites images JPEG/PNG/JP2 dans la mémoire sous la forme d'un tas d'octets et les y maintenir compressées avec la même taille que sur le disque, puis les décompresser de la mémoire lorsque vous en avez besoin.

Tout d'abord, regardons la mémoire requise par une image 1280x1024 de RGB888 en mémoire - c'est un énorme 3.9MB :

# Decompressed image in memory takes 3.9MB memory
im = np.zeros([1280,1024,3], dtype=np.uint8)

# print(im.nbytes) => 3932160

Maintenant, regardons un JPEG de la même taille :

enter image description here

Le voici sur le disque, avec ls -l :

-rw-r--r--@  1 mark  staff      47276  2 Apr 17:13 image.jpg

Et ici, il est toujours compressé en mémoire, également à 47kB ou seulement 1,2% de la taille :

# Same image as JPEG takes 47kB of memory
with open('image.jpg','rb') as f: 
   jpg = f.read() 

# print(len(jpg)) => 47276

Maintenant, lorsque vous voulez une image, vous la décompressez depuis la mémoire plutôt que depuis le disque.

# Read with 'imageio'
from io import BytesIO 
import imageio
numpyArray = imageio.imread(BytesIO(jpg))
# print(numpyArray.shape) =>(1024, 1280, 3)

# Or, alternatively, and probably faster, read with OpenCV
import cv2
numpyArray = cv2.imdecode(np.frombuffer(jpg,dtype=np.uint8), -1)  
# print(numpyArray.shape) =>(1024, 1280, 3)

Une autre option, totalement différente, qui décodera des kilomètres plus vite, mais qui ne réduira l'empreinte mémoire que par un facteur 3, consiste à palettiser les images. Vous réduisez le nombre de couleurs à moins de 256 couleurs uniques et stockez une palette de 256 couleurs. À chaque emplacement de pixel, vous stockez alors un seul octet qui est l'index dans la palette, plutôt que 3 octets de RVB. Cela réduira votre utilisation de la mémoire de 3,9 Mo/image à 1,3 Mo/image. Cela ne nécessite aucun décodage, mais peut entraîner une légère perte de la fidélité des couleurs et/ou des bandes - ce qui peut ou non être un problème selon la qualité de votre appareil photo ou de vos images.

Cela ressemble à quelque chose comme ceci (non testé) :

from PIL import Image
import numpy as np

im = Image.open('image.jpg')

# Make into Numpy array - size is 3.9MB
a = np.array(im)

# Now make a 256 colour palletised version
p = im.convert('P',palette=Image.ADAPTIVE)

# Make into Numpy array - size is now only 1.3MB
a = np.array(p)

-1voto

gunpowdercairn Points 11

PIL est la bibliothèque d'imagerie Python qui fournit à l'interpréteur Python des capacités d'édition d'images.

Windows : Téléchargez le paquet Pillow approprié en fonction de votre version de python. Assurez-vous de télécharger en fonction de la version de python que vous avez.

Pour importer le module Image, notre code doit commencer par la ligne suivante :

    from PIL import Image

    Open a particular image from a path
    #img  = Image.open(path)      
    # On successful execution of this statement, 
    # an object of Image type is returned and stored in img variable) 

    try:  
        img  = Image.open(path)  
    except IOError: 
    pass

# Use the above statement within try block, as it can  
# raise an IOError if file cannot be found,  
# or image cannot be opened.

Récupérer la taille de l'image : Les instances de la classe Image qui sont créées ont de nombreux attributs, l'un de ses attributs utiles est la taille.

from PIL import Image 

filename = "image.png"
with Image.open(filename) as image: 
    width, height = image.size 
#Image.size gives a 2-tuple and the width, height can be obtained 

D'autres attributs sont : Image.width, Image.height, Image.format, Image.info etc.

Enregistrez les changements dans l'image : Pour enregistrer les modifications apportées au fichier image, nous devons indiquer le chemin d'accès ainsi que le format de l'image.

img.save(path, format)     
# format is optional, if no format is specified,  
#it is determined from the filename extension

 from PIL import Image  

def main(): 
    try: 
     #Relative Path 
    img = Image.open("picture.jpg") 
    width, height = img.size 

    img = img.resize((width/2, height/2)) 

    #Saved in the same relative location 
    img.save("resized_picture.jpg")  
except IOError: 
    pass

if __name__ == "__main__": 
    main()

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