web-dev-qa-db-fra.com

Python Image Library: Comment combiner 4 images dans une grille 2 x 2?

J'ai 4 répertoires avec des images pour une animation. J'aimerais prendre l'ensemble des images et générer une seule image avec les 4 images disposées dans une grille 2x2 pour chaque image de l'animation.

Mon code jusqu'ici est:

import Image

fluid64 = "Fluid64_half_size/00"
fluid128 = "Fluid128_half_size/00"
fluid512 = "Fluid512_half_size/00" 
fluid1024 = "Fluid1024_half_size/00" 

out_image = "Fluid_all/00"

for pic in range(1, 26):
    blank_image = Image.open("blank.jpg")

    if pic < 10:
        image_num = "0"+str(pic)
    else:
        image_num = str(pic)

    image64 = Image.open(fluid64+image_num+".jpg")
    image128 = Image.open(fluid128+image_num+".jpg")
    image512 = Image.open(fluid512+image_num+".jpg")
    image1024 = Image.open(fluid1024+image_num+".jpg")
    out = out_image + image_num + ".jpg"

    blank_image.paste(image64, (0,0)).paste(fluid128, (400,0)).paste(fluid512, (0,300)).paste(fluid1024, (400,300)).save(out)

Je ne sais pas pourquoi ça ne marche pas. Je reçois l'erreur:

Traceback (most recent call last):
  File "C:\Users\Casey\Desktop\Image_composite.py", line 24, in <module>
    blank_image.paste(image64, (0,0)).paste(fluid128, (400,0)).paste(fluid512, (
ste(fluid1024, (400,300)).save(out)
AttributeError: 'NoneType' object has no attribute 'paste'
Shell returned 1

Toute aide serait géniale. Merci!

25
Nope

Le seul problème est que "coller" ne retourne pas un objet image - il modifie plutôt l'image "vierge" en place.

Ainsi, lorsque le deuxième collage est appelé (celui qui utilise l'image fuild128), il essaie de s'appliquer sur "Aucun" - qui est la valeur de retour de la première image.

Si c'est le seul problème que vous rencontrez, il suffit de faire un appel coller par ligne, comme ceci:

blank_image.paste(image64, (0,0))
blank_image.paste(fluid128, (400,0))
blank_image.paste(fluid512, (0,300))
blank_image.paste(fluid1024, (400,300))
blank_image.save(out)

Bien qu'il semble probable que vous deviez redimensionner chaque image de manière à ce que leur format corresponde également… .. Et votre code pour la variable "numéro d'image" n'est pas nécessaire. Python est vraiment bon avec les chaînes - faites juste quelque chose comme ça:

image64 = Image.open(fluid64 + "%02d.jpg" % pic)
39
jsbueno

Vous voudrez peut-être utiliser quelque chose comme:

blank_image = Image.new("RGB", (800, 600))

Cela créera une nouvelle zone en mémoire dans laquelle vous pourrez générer votre image. Vous devriez alors pouvoir coller vos images dans cela.

Ensuite, vous devrez le sauvegarder ultérieurement avec:

blank_image.save("blank.jpg")
10
David Hewitt

Lisez le message d'erreur:

AttributeError: 'NoneType' object has no attribute 'paste'

Cela signifie que vous avez essayé d'appeler .paste sur quelque chose qui était de type NoneType, c'est-à-dire sur l'objet None.

Image.paste ne renvoie aucun. Vous ne pouvez pas "chaîner" des appels comme celui-ci, sauf lorsque les fonctions sont spécifiquement conçues pour le prendre en charge, alors que Image.paste ne l’est pas. (La fonction return self permet d'obtenir ce type de support. Vous obtenez une erreur qui parle de NoneType car la fonction est écrite pour ne rien retourner, et tout dans Python renvoie None par défaut si rien d'autre n'est retourné explicitement.) est considéré comme Pythonic: les méthodes renvoient une nouvelle valeur ou modifient self et renvoient None. Ainsi, les "interfaces fluides" ne sont pas utilisées lorsque les fonctions ont des effets secondaires - les pythonistes considèrent cela comme néfaste. Retourner None est un avertissement indiquant que la fonction a des effets secondaires. :)

Il suffit de faire quatre appels .paste distincts.

4
Karl Knechtel

Contrairement aux API PIL copy, crop, resize ou rotate qui renvoient un objet Image, paste renvoie None qui empêche les appels de méthode en chaîne. Pas si pratique _ API design.

1
michaelliu

Il est facile d'obtenir des chiffres en mosaïque dans une grille 2-sur-2 avec la fonction append_images définie dans cette réponse https://stackoverflow.com/a/46623632/8738113

Par exemple:

img1 = append_images([image64, image128], direction='horizontal')
img2 = append_images([image512, image1024], direction='horizontal')
final = append_images([img1, img2], direction='vertical')
final.save("Fluid_all/00.jpg")
1
teekarna