Python Image Library: ¿Cómo combinar 4 imágenes en una cuadrícula de 2 x 2?

Tengo 4 directorios con imágenes para una animación. Me gustaría tomar el conjunto de imágenes y generar una sola imagen con las 4 imágenes organizadas en una cuadrícula de 2×2 para cada fotogtwig de la animación.

Mi código hasta ahora es:

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) 

No estoy seguro de por qué no está funcionando. Estoy recibiendo el error:

 Traceback (most recent call last): File "C:\Users\Casey\Desktop\Image_composite.py", line 24, in  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 

Cualquier ayuda sería increíble. ¡Gracias!

El único problema es que “pegar” no devuelve un objeto de imagen, sino que modifica la imagen “en blanco” en el lugar.

Entonces, cuando se llama a la segunda pegada (la que usa la imagen fuild128), intenta aplicarse en “Ninguno”, que es el valor de retorno de la primera imagen.

Si ese es el único problema que tiene, solo haga una llamada de pegado por línea, como esta:

 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) 

Aunque parece probable que necesitarías escalar cada imagen para que su formato coincida también. Y su código para la variable “image_num” es innecesario. Python es realmente bueno con las cuerdas, solo haz algo como esto:

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

Es posible que desee utilizar algo en la línea de:

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

Esto creará una nueva área en la memoria en la que puede generar su imagen. Entonces deberías poder pegar tus imágenes en eso.

Luego tendrás que guardarlo nuevamente más tarde con:

 blank_image.save("blank.jpg") 

Lea el mensaje de error:

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

Esto significa que intentó llamar a .paste en algo que era de tipo NoneType , es decir, en el objeto None .

Image.paste devuelve Ninguno. No puede “encadenar” llamadas así, excepto cuando las funciones están específicamente diseñadas para Image.paste , y Image.paste no lo está. (El soporte para este tipo de cosas se logra haciendo que la función se return self . Recibirá un error que habla sobre NoneType porque la función está escrita para no devolver nada, y todo en Python devuelve None por defecto si no se devuelve nada más explícitamente) Esto se considera Pythonic: los métodos devuelven un nuevo valor o modifican self y devuelven None . Por lo tanto, las llamadas “interfaces fluidas” no se usan cuando las funciones tienen efectos secundarios: los pitonistas lo consideran dañino. La devolución de None es una advertencia de que la función tiene efectos secundarios. 🙂

Solo haz cuatro llamadas de .paste .

A diferencia de las API de PIL, copy , crop , resize o rotate que devuelve un objeto de Image , paste devuelve None que evita las llamadas a métodos encadenados. Diseño de API no tan conveniente.

Sería fácil lograr cifras en una cuadrícula de 2 por 2 con la función append_images definida en esta respuesta https://stackoverflow.com/a/46623632/8738113

Por ejemplo:

 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")