因为在做图像补全任务时,想要展示缺陷图像的样子,需要将背景透明的mask图像加到原图像上,生成需要补全的图像.

原本的mask长这样

originMask

原本的图像长这样

originImg

预期的图片长这样

preImg

省流版: img.alpha_composite(mask)

我们发现背景是黑色的,一开始想的是创建一个新的图片,和目标图像一样大小,使用mask.getpixel((i,j)) 去获取mask每一个像素点,然后如果获取的黑色的,那就设置新图的像素为原图的像素newImg.putpixel((i,j),originImg.getpixel((i,j))),大概这个思路,因为原图是没有通道的,可能要简单的修改. 之前试过,这个方法是可行的,但是速度太慢了,我要对上百张图片进行这个操作要好久,所以去找别的方法.

首先我希望把mask盖到原图像上,就像PS一样,透明的部分不会印象下面的内容.因此我先把不透明的mask转化成透明的,因为mask是通用的,所以一张图片的效率低可以接受,以下是代码和效果.

mask = Image.open("mask.png")
W, H = mask.size
newMask = Image.new("RGBA", mask.size, (0, 0, 0, 0))
for i in range(W):
    for j in range(H):
        # print(mask.getpixel((i, j)))
        if mask.getpixel((i, j)) == (255, 255, 255):
            newMask.putpixel((i, j), (255, 255, 255, 255))
newMask.save("newMask.png")

这里才知道 img.size 返回的是先是宽度,然后才是高
getpixel((i,j)), 这里的i和j也分别是宽的位置和高的位置.

得到了新的mask

newMask

希望把newMask直接盖到原图像上,查了半天,网上要么是一个个像素去判断的,效率难以接受,要么是用Image.blend(image,mask,alpha),这种方法会改变原图像的透明度,效果如此公式:

$$\text{image} * (1-\text{alpha})+\text{mask} * \text{alpha}$$

truthImg = Image.open(os.path.join(basepath, "truth", imgName))
newImg = Image.new('RGBA', truthImg.size, (255, 0, 0, 0))
newImg.paste(truthImg, (0, 0))
Image.blend(newImg, newMask, 0.5).show()

效果如下:
blend

显然这不是我们想要的效果.

查了半天,终于找到了一个满足我要的效果,并且效率可以接受的方式,原来它自带一个函数: img.alpha_composite(mask)

truthImg = Image.open(os.path.join(basepath, "truth", imgName))
newImg = Image.new('RGBA', truthImg.size, (255, 0, 0, 0))
newImg.paste(truthImg, (0, 0))
newImg.alpha_composite(newMask)
newImg.show()

效果如下:
preImg

效果非常好!这就是我想要的!


如果是直接上传PNG,透明背景的图片上传到github图床好像现实的效果不是很好,就像下面这样

PNG Mask