非常喜欢 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 通道法慢得多。
「樱花庄的白猫」原创文章:《使用 Pillow 按色彩范围抠图》,转载请保留出处!https://2heng.xin/2018/04/05/python-pil/
Q.E.D.
Comments | 29 条评论
博主 LYM
超喜欢deemo的
博主 Mikumikumi0116
emmmmm,博主,这个算法把所有255白的像素都抠掉了,我加了个带边缘检测的,放这里了。(๑•̀ㅂ•́)و✧
https://github.com/MIkumikumi0116/Solid-color-background-cutout
博主 utared
@Mikumikumi0116 哥们链接没了?可以补一下档吗?
博主 不朽のしおや
博主 榎
博主玩arcaea嘛?id 180 691 822 可以互换一下好友码!
博主 同桌的我自己
大佬可以加个微信或者qq嘛
博主 鱼子酱
deemo又更新啦~(可不可以把新的也做一下呀,小声BB~
博主 Mashiro
@鱼子酱 好的,改天看看
博主 Georical
@Mashiro 一人血书求新的Deemo(不懂python也不懂Photoshop的小白QAQ
博主 鱼子酱
deemo厨~dalao还玩不玩其他的音游啊
博主 Mashiro
@鱼子酱 啊手机上主流的几个都玩