Comment fusionner une image PNG transparente avec une autre image en utilisant PIL

151

J'ai une image png transparente "foo.png" et j'ai ouvert une autre image avec

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

maintenant ce dont j'ai besoin est de fusionner foo.png avec foo2.png.

(foo.png contient du texte et je veux imprimer ce texte sur foo2.png)

Arackna
la source
71
Ne pas utiliser ;à la fin de vos commandes en python: c'est moche ...
nosklo
6
Je vais garder cela à l'esprit, merci !!
Arackna

Réponses:

288
import Image

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

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

Le premier paramètre à .paste()est l'image à coller. Deuxièmement, les coordonnées et la sauce secrète est le troisième paramètre. Il indique un masque qui sera utilisé pour coller l'image. Si vous passez une image avec transparence, alors le canal alpha est utilisé comme masque.

Consultez les documents .

nosklo
la source
6
Pour vous assurer que le premier plan contient de la transparence dans tous les cas, utilisez foreground.convert('RGBA')pour le paramètre de masque.
Mark Ransom
2
Merci. Il me manquait trop le troisième paramètre.
Silouane Gerin
13
Je reçoisValueError: bad transparency mask
Deniz Ozger
2
La sauce secrète était savoureuse
AFP_555
3
@DenizOzger Pour corriger l' ValueError: bad transparency maskutilisationbg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel
66

Image.pastene fonctionne pas comme prévu lorsque l'image d'arrière-plan contient également de la transparence. Vous devez utiliser un véritable Alpha Compositing .

Pillow 2.0 contient une alpha_compositefonction qui fait cela.

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

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

EDIT: Les deux images doivent être de type RGBA. Vous devez donc appeler convert('RGBA')si elles sont palettisées, etc. Si l'arrière-plan n'a pas de canal alpha, vous pouvez utiliser la méthode de collage classique (qui devrait être plus rapide).

olt
la source
Je viens d'utiliser paste () pour superposer une image semi-transparente sur une autre, avec PIL, et cela a fonctionné comme prévu. De quelle manière cela ne fonctionne-t-il pas comme prévu?
Peter Hansen
3
@PeterHansen, paste () ne fonctionne pas comme prévu "lorsque l'image d'arrière-plan contient également de la transparence".
homm
1
@PeterHansen Il y a un exemple: github.com/python-pillow/Pillow/issues
...
@homm merci. C'était il y a si longtemps que je n'ai aucun souvenir de ce que j'ai essayé. Il semble que j'ai manqué la partie que vous avez citée sur l'image d'arrière-plan ayant également de la transparence.
Peter Hansen
4
Je reçois ValueError: image has wrong madeaussi @DenizOzger
digitaldavenyc
48

Comme olt l'a déjà souligné, Image.pastene fonctionne pas correctement, lorsque la source et la destination contiennent toutes deux alpha.

Considérez le scénario suivant:

Deux images de test, toutes deux contiennent de l'alpha:

entrez la description de l'image ici entrez la description de l'image ici

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

Image de composition en utilisant Image.pastecomme ceci:

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

produit l'image suivante (la partie alpha des pixels rouges superposés est entièrement extraite du 2ème calque. Les pixels ne sont pas fusionnés correctement):

entrez la description de l'image ici

Image de composition en utilisant Image.alpha_compositecomme ceci:

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

produit l'image suivante (correcte):

entrez la description de l'image ici

P.Melch
la source
1
Merci pour les captures d'écran! Aide vraiment!
Viet
1
Mais alpha_compositene pouvez pas définir le décalage, pourriez-vous donner un exemple pour remplacer complètement la pastefonction?
Mithril
3
Je suppose que vous devrez créer une nouvelle image vide avec la même taille que l'image garget, coller le calque à la bonne position et utiliser alpha_compositing pour mélanger la nouvelle image sur l'image cible.
P.Melch
11

On peut également utiliser le mélange:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")
nvd
la source
1
Celui-ci a fonctionné ascétiquement pour moi. Les images doivent avoir exactement la même taille, mais c'est correct. La fonction coller ne m'a pas tout à fait coupé pour moi ...
Liviu Sosu
2
'ValueError: les images ne correspondent pas'
Schütze
2
Peut-être sont-ils de dimensions différentes. Vous devrez peut-être mettre à l'échelle ou recadrer l'un d'entre eux.
nvd
2
@ Schütze voir le commentaire de nvd parce qu'il / elle n'a pas ping (en utilisant @blahblah) vous
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
陈旭 周 记
la source
2
Bonjour, pouvez-vous éventuellement ajouter un peu plus de contexte à votre réponse? Sinon, il est peu probable que le demandeur en apprenne le «pourquoi».
jimf
0

Avait une question similaire et avait du mal à trouver une réponse. La fonction suivante vous permet de coller une image avec un paramètre de transparence sur une autre image à un décalage spécifique.

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
la source
ValueError: images do not match
lllllllllllll
0

J'ai fini par coder moi-même la suggestion de ce commentaire faite par l'utilisateur @ P.Melch et suggérée par @Mithril sur un projet sur lequel je travaille.

J'ai également codé la sécurité hors limites, voici le code pour cela . (J'ai lié un commit spécifique car les choses peuvent changer dans le futur de ce référentiel)

Remarque: J'attends des tableaux numpy des images comme np.array(Image.open(...))les entrées A et B copy_fromet ces overlayarguments de fonction liés .

Les dépendances sont la fonction juste avant elle, la copy_fromméthode et les tableaux numpy en tant que contenu d'image PIL pour le découpage.

Bien que le fichier soit très orienté classe, si vous souhaitez utiliser cette fonction overlay_transparent, assurez-vous de renommer le self.frametableau numpy de votre image d'arrière-plan.

Ou vous pouvez simplement copier le fichier entier (supprimer probablement certaines importations et la Utilsclasse) et interagir avec cette classe Frame comme ceci:

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

Ensuite, vous avez votre background.frametableau composé superposé et alpha, vous pouvez en obtenir une image PIL avec overlayed = Image.fromarray(background.frame)ou quelque chose comme:

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

Ou tout background.save("save path")comme cela prend directement de la self.framevariable interne composée alpha .

Vous pouvez lire le fichier et trouver d'autres fonctions de Nice avec cette I mise en œuvre codée comme les méthodes get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

Vous voudrez probablement supprimer la resolve_pendingméthode car elle est spécifique à ce projet.

Heureux si je vous ai aidé, assurez-vous de vérifier le repo du projet dont je parle, cette question et ce fil m'ont beaucoup aidé sur le développement :)

Tremeschin
la source