非常喜欢 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 条评论
博主 sakki
最近刚好有个需求是要抠签名,实在太感谢了QAQ
博主 星旅人
(=・ω・=)
博主 买个床大人
博主 [—_—]
想要被投喂也要换个猫嘛
回头再来学习
我先把我的屏保整回来
博主 雨宫星谣
表示初中党看不懂博主发的技术性文章,只是喜欢DEEMO罢了,
话说这个是什么网页啊
博主 Rvo
嘿嘿
博主 ZivLi
非常感谢你!解决了一个困扰我很多天的问题,差点想气的直接重撸源码了!看到你的这个文章很有思路~~~非常感谢~~~
博主 1062363138
(`・ω・´)
有点意思的办法,可以试试看博主 hundanli
UI界面做得真好看,教教我吧~
博主 MarshiroHellscythe
虽然看不懂但还是喊666
博主 1115084538
cooool!
博主 吠犬
该评论为私密评论
博主 Mashiro
@吠犬 该评论为私密评论
博主 葛一速
Python很强大,有时间要了解了解
博主 weimo
哎嘿嘿
博主 IIJ
Onedrive链接挂了//
博主 Mashiro
@IIJ OneDrive 删啦
博主 Harogo
棒棒的d=====( ̄▽ ̄*)b