Come unire un'immagine png trasparente con un'altra immagine usando PIL


151

Ho un'immagine png trasparente "foo.png" e ho aperto un'altra immagine con

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

ora quello di cui ho bisogno è unire foo.png con foo2.png.

(foo.png contiene del testo e voglio stamparlo su foo2.png)


71
Non usare ;alla fine dei tuoi comandi in Python: è brutto ...
nosklo

6
Lo terrò a mente, grazie !!
Arackna,

Risposte:


288
import Image

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

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

Il primo parametro su .paste()è l'immagine da incollare. Secondo sono le coordinate e la salsa segreta è il terzo parametro. Indica una maschera che verrà utilizzata per incollare l'immagine. Se si passa un'immagine con trasparenza, il canale alfa viene utilizzato come maschera.

Controlla i documenti .


6
Per assicurarsi che il primo piano contenga trasparenza in tutti i casi, utilizzare foreground.convert('RGBA')per il parametro maschera.
Mark Ransom il

2
Grazie. Mi mancava troppo il terzo parametro.
Silouane Gerin,

13
RicevoValueError: bad transparency mask
Deniz Ozger

2
La salsa segreta era gustosa
AFP_555,

3
@DenizOzger Per correggere l' ValueError: bad transparency maskusobg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel

66

Image.pastenon funziona come previsto quando l'immagine di sfondo contiene anche trasparenza. Devi usare il vero Alpha Compositing .

Pillow 2.0 contiene una alpha_compositefunzione che lo fa.

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

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

EDIT: entrambe le immagini devono essere del tipo RGBA. Quindi devi chiamare convert('RGBA')se sono palettizzati, ecc. Se lo sfondo non ha un canale alfa, puoi usare il normale metodo di incolla (che dovrebbe essere più veloce).


Ho appena usato paste () per sovrapporre un'immagine semi-trasparente su un'altra, con PIL, e ha funzionato come mi aspettavo. In che modo non funziona come previsto?
Peter Hansen,

3
@PeterHansen, paste () non funziona come previsto "quando anche l'immagine di sfondo contiene trasparenza".
homm,

1
@PeterHansen C'è un esempio: github.com/python-pillow/Pillow/issues/…
homm,

@homm grazie. È stato tanto tempo fa che non ho memoria di ciò che ho provato. Sembra che mi sia sfuggita anche la parte che hai citato sull'immagine di sfondo con trasparenza.
Peter Hansen,

4
Ottengo ValueError: image has wrong madeanche @ DenizOzger
digitaldavenyc l'

48

Come già sottolineato da olt , Image.pastenon funziona correttamente, quando sia l'origine che la destinazione contengono alfa.

Considera il seguente scenario:

Due immagini di prova, entrambe contengono alfa:

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

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

Comporre l'immagine usando Image.pastecosì:

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

produce la seguente immagine (la parte alfa dei pixel rossi sovrapposti viene completamente presa dal 2 ° livello. I pixel non vengono miscelati correttamente):

inserisci qui la descrizione dell'immagine

Comporre l'immagine usando Image.alpha_compositecosì:

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

produce la seguente immagine (corretta):

inserisci qui la descrizione dell'immagine


1
Grazie per gli screenshot! Aiuta davvero!
Viet,

1
Ma alpha_compositenon puoi impostare l'offset, ti dispiacerebbe dare un esempio per sostituire completamente la pastefunzione?
Mithril,

3
Suppongo che dovresti creare una nuova immagine vuota con le stesse dimensioni dell'immagine del garget, incollare il livello nella posizione corretta e utilizzare alpha_compositing per fondere la nuova immagine sull'immagine di destinazione.
P.Melch,

11

Si può anche usare la fusione:

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

1
Questo ha funzionato in modo ascetico per me. Le immagini devono avere esattamente le stesse dimensioni, ma è ok. La funzione incolla non l'ha del tutto tagliata per me ...
Liviu Sosu il

2
"ValueError: le immagini non corrispondono"
Schütze

2
Forse, hanno dimensioni diverse. Potrebbe essere necessario ridimensionare o ritagliare uno di quelli.
nvd,

2
@ Schütze vedi il commento di nvd perché lui / lei non ha fatto il ping (usando @blahblah) tu
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
Ciao, puoi forse aggiungere un po 'più di contesto alla tua risposta? Altrimenti è improbabile che il richiedente apprenda il "perché" dietro di esso.
jimf

0

Aveva una domanda simile e ha avuto difficoltà a trovare una risposta. La seguente funzione consente di incollare un'immagine con un parametro di trasparenza su un'altra immagine con un offset specifico.

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

Ho finito per codificare me stesso il suggerimento di questo commento fatto dall'utente @ P.Melch e suggerito da @Mithril su un progetto a cui sto lavorando.

Ho codificato anche per motivi di sicurezza, ecco il codice per questo . (Ho collegato un commit specifico perché le cose possono cambiare nel futuro di questo repository)

Nota: mi aspetto matrici intorpidite dalle immagini in modo simile np.array(Image.open(...))agli ingressi A e B copy_frome agli overlayargomenti di questa funzione collegata .

Le dipendenze sono la funzione proprio prima di essa, il copy_frommetodo e gli array intorpiditi come contenuto di Immagine PIL per lo slicing.

Sebbene il file sia molto orientato alla classe, se si desidera utilizzare quella funzione overlay_transparent, assicurarsi di rinominare l' self.framearray numpy dell'immagine di sfondo.

Oppure puoi semplicemente copiare l'intero file (probabilmente rimuovere alcune importazioni e la Utilsclasse) e interagire con questa classe Frame in questo modo:

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

Quindi hai il tuo background.framecome array sovrapposto e composto alfa, puoi ottenere un'immagine PIL da esso con overlayed = Image.fromarray(background.frame)o qualcosa del genere:

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

O proprio background.save("save path")come quello prende direttamente dalla self.framevariabile interna composta da alfa .

È possibile leggere il file e trovare alcune altre funzioni belle con questa implementazione ho codificato come la modalità get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

Probabilmente vorrai rimuovere il resolve_pendingmetodo in quanto specifico per quel progetto.

Sono contento se ti ho aiutato, assicurati di controllare il repository del progetto di cui sto parlando, questa domanda e il thread mi hanno aiutato molto nello sviluppo :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.