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

Posted

技术标签:

【中文标题】如何使用 PIL 将透明 png 图像与另一个图像合并【英文标题】:How to merge a transparent png image with another image using PIL 【发布时间】:2011-07-16 12:41:48 【问题描述】:

我有一个透明的 png 图像“foo.png” 我用

打开了另一张图片
im = Image.open("foo2.png");

现在我需要将 foo.png 与 foo2.png 合并。

( foo.png 包含一些文本,我想在 foo2.png 上打印该文本)

【问题讨论】:

不要在 python 中的命令末尾使用;:这很难看... 我会记住的,谢谢!! 【参考方案1】:
from PIL import Image

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

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

.paste() 的第一个参数是要粘贴的图像。第二个是坐标,秘诀是第三个参数。它表示将用于粘贴图像的掩码。如果您传递具有透明度的图像,则 Alpha 通道将用作遮罩。

检查docs。

【讨论】:

要确保前景在所有情况下都包含透明度,请使用 foreground.convert('RGBA') 作为掩码参数。 谢谢。我太少了第三个参数。 我收到ValueError: bad transparency mask 秘制酱汁很好吃 @DenizOzger 修复 ValueError: bad transparency mask 使用 bg.paste(fg, (0, 0), fg.convert('RGBA'))【参考方案2】:

当背景图像也包含透明度时,Image.paste 无法按预期工作。您需要使用真实的Alpha Compositing。

Pillow 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,它按我的预期工作。它在哪些方面没有按您的预期工作? @PeterHansen,“当背景图像也包含透明度”时,paste() 无法按预期工作。 @PeterHansen 有例子:github.com/python-pillow/Pillow/issues/… @homm 谢谢。那是很久以前的事了,我不记得我尝试了什么。看来我确实错过了您引用的关于背景图像也具有透明度的部分。 我得到ValueError: image has wrong made 以及@DenizOzger【参考方案3】:

正如 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)

生成以下图像(覆盖的红色像素的 alpha 部分完全取自第 2 层。像素未正确混合):

像这样使用Image.alpha_composite合成图像:

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

产生以下(正确的)图像:

【讨论】:

感谢截图!真的很有帮助! 但是alpha_composite不能设置偏移量,你介意举个例子来完全替换paste函数吗? 我猜你必须创建一个与 garget 图像大小相同的新空图像,将图层粘贴到适当的位置并使用 alpha_compositing 将新图像混合到目标图像上。跨度> 我得到:ValueError:图像不匹配 图片大小必须一致【参考方案4】:

也可以使用混合:

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

【讨论】:

这个苦行僧为我工作。图像必须具有完全相同的大小,但没关系。粘贴功能并没有完全适合我... 'ValueError: 图片不匹配' 可能,它们的尺寸不同。您可能需要缩放或裁剪其中之一。 @Schütze 看到 nvd 的评论,因为他/她没有 ping(使用 @blahblah)你【参考方案5】:

有一个类似的问题,但很难找到答案。以下函数允许您将具有透明度参数的图像粘贴到另一个图像上的特定偏移处。

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【参考方案6】:
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

【讨论】:

嗨,您能否为您的答案添加更多上下文?否则,请求者不太可能了解其背后的“原因”。【参考方案7】:

关键代码是:

_, _, _, alpha = image_element_copy.split()
image_bg_copy.paste(image_element_copy, box=(x0, y0, x1, y1), mask=alpha)

完整的功能是:

def paste_image(image_bg, image_element, cx, cy, w, h, rotate=0, h_flip=False):
    image_bg_copy = image_bg.copy()
    image_element_copy = image_element.copy()

    image_element_copy = image_element_copy.resize(size=(w, h))
    if h_flip:
        image_element_copy = image_element_copy.transpose(Image.FLIP_LEFT_RIGHT)
    image_element_copy = image_element_copy.rotate(rotate, expand=True)
    _, _, _, alpha = image_element_copy.split()
    # image_element_copy's width and height will change after rotation
    w = image_element_copy.width
    h = image_element_copy.height
    x0 = cx - w // 2
    y0 = cy - h // 2
    x1 = x0 + w
    y1 = y0 + h
    image_bg_copy.paste(image_element_copy, box=(x0, y0, x1, y1), mask=alpha)
    return image_bg_copy

以上功能支持:

位置(cx, cy) 自动将 image_element 调整为 (w, h) 旋转 image_element 而不裁剪它 水平翻转

【讨论】:

【参考方案8】:

这是我合并 2 个不同大小的图像的代码,每个图像都具有透明度和偏移量:

from PIL import Image

background = Image.open('image1.png')
foreground = Image.open("image2.png")

x = background.size[0]//2
y = background.size[1]//2

background = Image.alpha_composite(
    Image.new("RGBA", background.size),
    background.convert('RGBA')
)

background.paste(
    foreground,
    (x, y),
    foreground
)

background.show()

这个 sn-p 是之前答案的混合,在处理不同大小的图像时混合元素和偏移量,每个图像都有透明度。

【讨论】:

以上是关于如何使用 PIL 将透明 png 图像与另一个图像合并的主要内容,如果未能解决你的问题,请参考以下文章

如何用PIL确定ICO图像的透明色指数?

如何使用 PIL 使所有白色像素透明?

Python用PIL将PNG图像合成gif时如果背景为透明时图像出现重影的解决办法

如何使用 Python PIL 模糊图像的非矩形或圆形区域?

如何使用 PIL 将 PNG 图像写入字符串?

如何使用 Python 将 .ICO 转换为 .PNG?