非常喜欢 Deemo 的歌曲封面插画,不过拆包后发现图片素材有白色背景,想要得到透明背景图的话,用 Photoshop 抠倒是不难,但是三百多张图处理起来工作量巨大,所以考虑用 Python 强大的图像处理库——Pillow (PIL Fork) 来处理吧。

现在有两种实现思路:

  1. 逐一分离 RGB 色彩通道,去除白色的 255 部分;
  2. 直接把白色像素 rgba(255,255,255,255)A 通道替换为透明。

对技术细节不感兴趣这里直接下载图包。另外用这些素材做了一个古树旋律复刻 Online,以及一个 Wallpaper Engine 壁纸(如果没有购买 WE,可以在这里体验,密码:oba7),项目源码在这,求 Star~

通道分离法:

from PIL import Image

def cut(file_name):
    im = Image.open(file_name)
    newim = im.convert("RGBA")

    source = im.split()
    R, G, B = 0, 1, 2  
    rmask = source[R].point(lambda i:i >= 255 and 255)
    gmask = source[G].point(lambda i:i >= 255 and 255)
    bmask = source[B].point(lambda i:i >= 255 and 255)

    out = Image.new("RGBA", im.size, None)
    newim.paste(out, None, rmask)
    newim.paste(out, None, gmask)
    newim.paste(out, None, bmask)      

    newim.save("new_" + file_name)

cut('alice.png')

抠完后发现有多余的颜色被过滤掉了:

rgb.png

检查发现原因是各个通道都出现了误伤,一些特殊的颜色比如 rgb(255,100,100) 的 R 值正好是和白色一样的 255,于是在 R 通道里也一同被过滤了。所以如果要通过通道过滤,那么还需要考虑对三个通道结果进行比对,根据三个通道重叠的部分再对原图像进行处理,这样一来显然这就不如下面的方法了。

像素替换法

from PIL import Image

def cut(file_name):
    img = Image.open(file_name)
    img = img.convert("RGBA")

    pixdata = img.load()

    for y in range(img.size[1]):
        for x in range(img.size[0]):
            if pixdata[x, y] == (255, 255, 255, 255):
                pixdata[x, y] = (0, 0, 0, 0)

    img.save("new_" + file_name)

cut('alice.png')

结果很理想,唯一的不足就是运行速度比 RGB 通道法慢得多。
pix.png

Q.E.D.

Comments