Cómo combinar una imagen png transparente con otra imagen usando PIL


151

Tengo una imagen png transparente "foo.png" y he abierto otra imagen con

im = Image.open("foo2.png");

ahora lo que necesito es fusionar foo.png con foo2.png.

(foo.png contiene texto y quiero imprimir ese texto en foo2.png)


71
No utilice ;al final de sus comandos en Python: Es feo ...
nosklo

66
Lo tendré en mente, ¡gracias!
Arackna

Respuestas:


288
import Image

background = Image.open("test1.png")
foreground = Image.open("test2.png")

background.paste(foreground, (0, 0), foreground)
background.show()

El primer parámetro para .paste()es la imagen para pegar. En segundo lugar están las coordenadas, y la salsa secreta es el tercer parámetro. Indica una máscara que se utilizará para pegar la imagen. Si pasa una imagen con transparencia, el canal alfa se usa como máscara.

Revisa los documentos .


66
Para asegurarse de que el primer plano contenga transparencia en todos los casos, utilice foreground.convert('RGBA')el parámetro de máscara.
Mark Ransom

2
Gracias. También me faltaba el tercer parámetro.
Silouane Gerin

13
Me estoy poniendoValueError: bad transparency mask
Deniz Ozger

2
La salsa secreta estaba sabrosa
AFP_555

3
@DenizOzger Para arreglar el ValueError: bad transparency maskusobg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel

66

Image.pasteno funciona como se esperaba cuando la imagen de fondo también contiene transparencias. Necesita usar Alpha Compositing real .

Pillow 2.0 contiene una alpha_compositefunción que hace esto.

background = Image.open("test1.png")
foreground = Image.open("test2.png")

Image.alpha_composite(background, foreground).save("test3.png")

EDITAR: Ambas imágenes deben ser del tipo RGBA. Por lo tanto, debe llamar convert('RGBA')si están paletizados, etc. Si el fondo no tiene un canal alfa, puede usar el método de pegado regular (que debería ser más rápido).


Acabo de usar paste () para superponer una imagen semitransparente en otra, con PIL, y funcionó como esperaba. ¿De qué manera no funciona como esperabas?
Peter Hansen

3
@PeterHansen, paste () no funciona como se esperaba "cuando la imagen de fondo también contiene transparencias".
homm

1
@ PeterHansen Hay un ejemplo: github.com/python-pillow/Pillow/issues/…
homm el

@homm gracias. Eso fue hace tanto tiempo que no recuerdo nada de lo que intenté. Parece probable que me perdí la parte que citó sobre la imagen de fondo que también tiene transparencia.
Peter Hansen el

44
También me pongo ValueError: image has wrong made@DenizOzger
digitaldavenyc

48

Como OLT ya se ha señalado, Image.pasteno funciona correctamente, cuando la fuente y el destino de ambos contienen alfa.

Considere el siguiente escenario:

Dos imágenes de prueba, ambas contienen alfa:

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

layer1 = Image.open("layer1.png")
layer2 = Image.open("layer2.png")

Composición de imagen usando Image.pasteasí:

final1 = Image.new("RGBA", layer1.size)
final1.paste(layer1, (0,0), layer1)
final1.paste(layer2, (0,0), layer2)

produce la siguiente imagen (la parte alfa de los píxeles rojos superpuestos se toma completamente de la segunda capa. Los píxeles no se mezclan correctamente):

ingrese la descripción de la imagen aquí

Composición de imagen usando Image.alpha_compositeasí:

final2 = Image.new("RGBA", layer1.size)
final2 = Image.alpha_composite(final2, layer1)
final2 = Image.alpha_composite(final2, layer2)

produce la siguiente imagen (correcta):

ingrese la descripción de la imagen aquí


1
Gracias por las capturas de pantalla! Realmente ayuda!
Viet

1
Pero alpha_compositeno puede establecer el desplazamiento, ¿le importaría dar un ejemplo para reemplazar completamente la pastefunción?
Mithril

3
Supongo que tendrías que crear una nueva imagen vacía con el mismo tamaño que la imagen del objeto, pegar la capa en la posición correcta y usar alpha_compositing para mezclar la nueva imagen sobre la imagen de destino.
P.Melch

11

También se puede usar la mezcla:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")

1
Este asceticamente funcionó para mí. Las imágenes deben tener exactamente el mismo tamaño, pero está bien. La función de pegar no me funcionó ...
Liviu Sosu

2
'ValueError: las imágenes no coinciden'
Schütze

2
Posiblemente, son de diferentes dimensiones. Es posible que necesite escalar o recortar uno de esos.
nvd

2
@ Schütze ve el comentario de nvd porque no hizo ping (usando @blahblah) a usted
MilkyWay90

1
def trans_paste(bg_img,fg_img,box=(0,0)):
    fg_img_trans = Image.new("RGBA",bg_img.size)
    fg_img_trans.paste(fg_img,box,mask=fg_img)
    new_img = Image.alpha_composite(bg_img,fg_img_trans)
    return new_img

2
Hola, ¿puedes agregar un poco más de contexto a tu respuesta? De lo contrario, no es probable que el solicitante aprenda el "por qué" detrás de él.
jimf

0

Tenía una pregunta similar y tuvo dificultades para encontrar una respuesta. La siguiente función le permite pegar una imagen con un parámetro de transparencia sobre otra imagen en un desplazamiento específico.

import Image

def trans_paste(fg_img,bg_img,alpha=1.0,box=(0,0)):
    fg_img_trans = Image.new("RGBA",fg_img.size)
    fg_img_trans = Image.blend(fg_img_trans,fg_img,alpha)
    bg_img.paste(fg_img_trans,box,fg_img_trans)
    return bg_img

bg_img = Image.open("bg.png")
fg_img = Image.open("fg.png")
p = trans_paste(fg_img,bg_img,.7,(250,100))
p.show()

ValueError: images do not match
lllllllllllll

0

Terminé codificando la sugerencia de este comentario hecha por el usuario @ P.Melch y sugerida por @Mithril en un proyecto en el que estoy trabajando.

También codifiqué la seguridad fuera de los límites, aquí está el código para ello . (Enlace un commit específico porque las cosas pueden cambiar en el futuro de este repositorio)

Nota: Espero matrices numpy de las imágenes, así np.array(Image.open(...))como las entradas A y B copy_fromy los overlayargumentos de esta función vinculada .

Las dependencias son la función justo antes, el copy_frommétodo y las matrices numpy como contenido de imagen PIL para segmentar.

Aunque el archivo está muy orientado a la clase, si desea utilizar esa función overlay_transparent, asegúrese de cambiar el nombre de la self.framematriz numpy de la imagen de fondo.

O simplemente puede copiar todo el archivo (probablemente eliminar algunas importaciones y la Utilsclase) e interactuar con esta clase de marco de la siguiente manera:

# Assuming you named the file frame.py in the same directory
from frame import Frame

background = Frame()
overlay = Frame()

background.load_from_path("your path here")
overlay.load_from_path("your path here")

background.overlay_transparent(overlay.frame, x=300, y=200)

Luego tiene su background.framematriz compuesta superpuesta y alfa, puede obtener una imagen PIL de ella con overlayed = Image.fromarray(background.frame)o algo así como:

overlayed = Frame()
overlayed.load_from_array(background.frame)

O simplemente background.save("save path")como eso toma directamente de la self.framevariable interna compuesta alfa .

Usted puede leer el archivo y encontrar algunas otras funciones interesantes con esta aplicación que codificado como el métodos get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

Probablemente desee eliminar el resolve_pendingmétodo, ya que es específico para ese proyecto.

Me alegro de haberte ayudado, asegúrate de revisar el repositorio del proyecto del que estoy hablando, esta pregunta y este hilo me ayudaron mucho en el desarrollo :)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.