Como mesclar uma imagem png transparente com outra imagem usando PIL

151

Tenho uma imagem png transparente "foo.png" e abri outra imagem com

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

agora o que eu preciso é mesclar foo.png com foo2.png.

(foo.png contém algum texto e quero imprimi-lo em foo2.png)

Arackna
fonte
71
Não use ;no final de seus comandos em python: É feio ...
nosklo
6
Vou manter isso em mente, obrigado !!
Arackna

Respostas:

288
import Image

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

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

O primeiro parâmetro para .paste()é a imagem a colar. Segundo são as coordenadas, e o molho secreto é o terceiro parâmetro. Indica uma máscara que será usada para colar a imagem. Se você passar uma imagem com transparência, o canal alfa será usado como máscara.

Verifique os documentos .

nosklo
fonte
6
Para garantir que o primeiro plano contenha transparência em todos os casos, use foreground.convert('RGBA')o parâmetro mask.
Mark Ransom
2
Obrigado. Eu estava com saudade do terceiro parâmetro.
Silouane Gerin 19/08/2013
13
Estou ficandoValueError: bad transparency mask
Deniz Özger
2
O segredo era saborosa
AFP_555
3
@DenizOzger Para corrigir o ValueError: bad transparency maskusobg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel
66

Image.pastenão funciona como esperado quando a imagem de fundo também contém transparência. Você precisa usar o Alpha Compositing real .

Pillow 2.0 contém uma alpha_compositefunção que faz isso.

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

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

EDIT: As duas imagens precisam ser do tipo RGBA. Portanto, é necessário chamar convert('RGBA')se eles estão em paleta, etc. Se o plano de fundo não tiver um canal alfa, você poderá usar o método de colagem regular (que deve ser mais rápido).

olt
fonte
Eu apenas usei paste () para sobrepor uma imagem semitransparente em outra, com PIL, e funcionou como eu esperava. De que maneira não funciona como o esperado?
27613 Peter Hansen
3
@ PeterHansen, paste () não funciona como esperado "quando a imagem de plano de fundo também contém transparência".
homm
1
@PeterHansen Há exemplo: github.com/python-pillow/Pillow/issues/...
homm
@homm obrigado. Isso foi há tanto tempo que não tenho lembrança do que tentei. Parece que eu perdi a parte que você citou sobre a imagem de fundo também ter transparência.
Peter Hansen
4
Eu recebo ValueError: image has wrong madetambém @DenizOzger
digitaldavenyc
48

Como olt já apontou, Image.pastenão funciona corretamente quando a origem e o destino contêm alfa.

Considere o seguinte cenário:

Duas imagens de teste, ambas contêm alfa:

insira a descrição da imagem aqui insira a descrição da imagem aqui

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

Composição da imagem usando Image.pasteo seguinte:

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

produz a seguinte imagem (a parte alfa dos pixels vermelhos sobrepostos é completamente retirada da 2ª camada. Os pixels não são misturados corretamente):

insira a descrição da imagem aqui

Composição da imagem usando Image.alpha_compositeo seguinte:

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

produz a seguinte imagem (correta):

insira a descrição da imagem aqui

P.Melch
fonte
1
Obrigado pelas capturas de tela! Realmente ajuda!
Viet
1
Mas alpha_compositenão é possível definir o deslocamento, você se importaria em dar um exemplo para substituir completamente a pastefunção?
Mithril
3
Eu acho que você teria que criar uma nova imagem vazia com o mesmo tamanho da imagem do garget, colar a camada na posição correta e usar alpha_compositing para misturar a nova imagem sobre a imagem de destino.
21417 P.Pelch
11

Pode-se também usar a mistura:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")
nvd
fonte
1
Este funcionou asceticamente para mim. As imagens devem ter exatamente o mesmo tamanho, mas tudo bem. A função pasta não chegou a cortá-la para mim ...
Liviu Sosu
2
'ValueError: as imagens não correspondem'
Schütze
2
Possivelmente, eles são de dimensões diferentes. Pode ser necessário dimensionar ou cortar um desses.
nvd
2
@ Schütze veja o comentário de nvd porque ele / ela não fez ping (usando @blahblah) você
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
陈旭 周 记
fonte
2
Olá, você pode adicionar um pouco mais de contexto à sua resposta? Caso contrário, o solicitante provavelmente não aprenderá o "porquê" por trás dele.
jimf
0

Tinha uma pergunta semelhante e tinha dificuldade em encontrar uma resposta. A função a seguir permite colar uma imagem com um parâmetro de transparência sobre outra imagem em um deslocamento 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()
lee
fonte
ValueError: images do not match
Lllllllllllll
0

Acabei codificando a sugestão desse comentário feito pelo usuário @ P.Melch e sugerido por @Mithril em um projeto em que estou trabalhando.

Também codifiquei fora dos limites de segurança, eis o código para isso . (Vinculei um commit específico porque as coisas podem mudar no futuro deste repositório)

Nota: Espero matrizes numpy das imagens, np.array(Image.open(...))como as entradas A e B copy_frome os overlayargumentos dessa função vinculada .

As dependências são a função logo antes, o copy_frommétodo e as matrizes numpy como o conteúdo da imagem PIL para fatiar.

Embora o arquivo seja muito orientado a classe, se você quiser usar essa função overlay_transparent, renomeie self.framepara a matriz numpy da imagem de plano de fundo.

Ou você pode simplesmente copiar o arquivo inteiro (provavelmente remover algumas importações e a Utilsclasse) e interagir com essa classe Frame da seguinte maneira:

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

Então, background.framecomo o array composto sobreposto e alfa, você pode obter uma imagem PIL com overlayed = Image.fromarray(background.frame)ou algo como:

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

Ou, exatamente background.save("save path")como é tirado diretamente do componente interno composto alfaself.frame variável .

Você pode ler o arquivo e encontrar algumas outras funções agradáveis com esta implementação eu codificado como a métodos get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

Você provavelmente desejaria remover o resolve_pendingmétodo específico para esse projeto.

Que bom que eu ajudei você, não deixe de conferir o repo do projeto que estou falando, essa pergunta e discussão me ajudaram muito no desenvolvimento :)

Tremeschin
fonte