如何使用PIL将透明png图像与另一个图像合并


Answers:


288
import Image

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

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

的第一个参数.paste()是要粘贴的图像。第二个是坐标,秘密调味料是第三个参数。它表示将用于粘贴图像的遮罩。如果通过透明图像,则Alpha通道将用作遮罩。

检查文档


6
要确保前景在所有情况下均包含透明度,请使用foreground.convert('RGBA')mask参数。
Mark Ransom

2
谢谢。我太错过了第三个参数。
Silouane Gerin 2013年

13
我得到了ValueError: bad transparency mask
Deniz Ozger '16

2
秘密的酱汁很美味
AFP_555 '18

3
@DenizOzger要解决ValueError: bad transparency mask使用bg.paste(fg, (0, 0), fg.convert('RGBA'))
明威塞缪尔

66

Image.paste当背景图像也包含透明度时,将无法正常工作。您需要使用真正的Alpha合成

枕头2.0包含alpha_composite执行此操作的功能。

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

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

编辑:两个图像都必须是RGBA类型。因此,convert('RGBA')如果它们带有调色板等,则需要调用。如果背景没有Alpha通道,则可以使用常规的粘贴方法(应该更快)。


我只是使用paste()在PIL上将一个半透明图像覆盖在另一个图像上,并且按预期工作。它以什么方式无法按预期工作?
彼得·汉森

3
@ PeterHansen,paste()无法正常工作,“当背景图像还包含透明度时”。
homm 2014年


@homm谢谢。那是很久以前的事,我对自己的尝试一无所知。似乎我确实错过了您引用的关于背景图像也具有透明度的部分。
彼得·汉森

4
ValueError: image has wrong made也很好@DenizOzger
digitaldavenyc

48

正如olt已经指出的那样,Image.paste当源目标都包含alpha 时,将无法正常工作。

请考虑以下情形:

两个测试图像都包含alpha:

在此处输入图片说明 在此处输入图片说明

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

Image.paste像这样合成图像:

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

产生以下图像(红色像素的叠加部分完全取自第二层。像素未正确混合):

在此处输入图片说明

Image.alpha_composite像这样合成图像:

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

产生以下(正确)图像:

在此处输入图片说明


1
感谢您的截图!真的有帮助!
越南

1
但是alpha_composite无法设置偏移量,您介意举一个完全替代paste功能的例子吗?
秘银

3
我猜您将不得不创建一个与小工具图像大小相同的新空图像,将图层粘贴到正确的位置,然后使用alpha_compositing将新图像混合到目标图像上。
P.Melch '17

11

也可以使用混合:

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

1
这个人为我工作。图像必须具有完全相同的大小,但是可以。粘贴功能对我来说还
算不上理想

2
'ValueError异常:图像不匹配'
Schütze

2
它们可能具有不同的尺寸。您可能需要缩放或裁剪其中之一。
nvd

2
@Schütze看到nvd的评论,因为他/她没有ping(使用@blahblah)给您
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
嗨,您可以在回答中添加更多内容吗?否则,请求者不太可能了解其背后的“原因”。
jimf

0

有类似的问题,很难找到答案。通过以下功能,您可以将具有透明度参数的图像以特定的偏移量粘贴到另一幅图像上。

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

我结束了自己的编码的建议此评论用户@ P.Melch一个项目我正在做,并建议通过@Mithril。

我也编码了安全性,这是它的代码。(我链接了一个特定的提交,因为在此存储库的将来情况可能会发生变化)

注意:我希望图像中有numpy数组,例如np.array(Image.open(...)),输入A和B copy_from以及此链接的函数overlay参数。

依赖项是位于其之前的函数,copy_from方法和numpy数组,它们是要切片的PIL图像内容。

尽管该文件是非常面向类的,但是如果要使用该函数overlay_transparent,请确保将重命名self.frame为背景图像numpy数组。

或者,您可以仅复制整个文件(可能删除一些导入和Utils类),然后与此Frame类进行交互,如下所示:

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

然后,您将其background.frame作为叠加和alpha合成数组,可以使用overlayed = Image.fromarray(background.frame)或类似的东西从中获取PIL图像:

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

或者就像background.save("save path")直接取自alpha复合内部self.frame变量一样。

您可以读取该文件,并找到其它的一些功能,这个实现我喜欢的编码方法get_rgb_frame_arrayresize_by_ratioresize_to_resolutionrotategaussian_blurtransparencyvignetting:)

您可能想要删除该resolve_pending项目专用的方法。

很高兴能为您提供帮助,请务必查看我正在谈论的项目的回购协议,该问题和线程对我的发展大有帮助:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.