非常喜欢 Deemo 的歌曲封面插画,不过拆包后发现图片素材有白色背景,想要得到透明背景图的话,用 Photoshop 抠倒是不难,但是三百多张图处理起来工作量巨大,所以考虑用 Python 强大的图像处理库——Pillow (PIL Fork) 来处理吧。
现在有两种实现思路:
- 逐一分离 RGB 色彩通道,去除白色的
255
部分; - 直接把白色像素
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(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 通道法慢得多。