用 Python 绘制炫酷的 Icon
最近在做一个和 Swift 编码相关的项目,就想给项目做一个 logo 出来,不然光秃秃的不好看。因为是编码相关,因此就想到可以用 0 和 1 填充 Swift 的图标,再加上一个炫酷的渐变色。Swift 的 logo 在官网就可以下载矢量图格式。最终实现的效果如下:
感觉还是挺好看的。
思路
用 Pillow 和 OpenCV 库,先随机生成彩色的 0 和 1 排列,之后用 Swift 的 logo 做一下 mask 就可以了。生成彩色 0 1 图又需要先生成一张渐变图,然后用黑白的 0 和 1 图做一次 mask。整体思路比较简单。
PIL 渐变图
我这张图是从上到下渐变,给定两个 RGB 颜色值,从上到下做线性插值。这里的实现比较简单粗暴,直接去遍历 1024x1024 的图像的每个像素,速度比较慢(又不是不能用系列)。毕竟是参考的网上其他人的实现,实际上用 np.linspace
会快很多…… 而且同样的值直接复制也不需要依次循环…… 偷懒了。
1 | from PIL import Image, ImageDraw, ImageFont |
生成的渐变图如下:
0-1 排列图
之后要制作一张 0 和 1 随机排列的黑白图。只要写个循环把随机数排满画布就可以了:
1 | img = Image.new(mode='RGB', size=(1024, 1024), color='white') |
效果如下:
渐变 0-1 排列
之后就是使用黑白的 0-1 图当作蒙版去给渐变图做遮罩。那我们很容易就写出这样的代码:
1 | numbers[numbers_gray == 0, :] = grad[numbers_gray == 0, :] |
也就是把图片中黑色的地方(为 0)替换成渐变图的颜色。但是如果事情发展的这么顺利我就不写这篇文章了…… 直接这样做,生成的渐变数字会带有黑边:
看起来感觉很脏。显然数字本身并不是纯黑色的,边缘位置是灰色。那如果我们把图片中不是白色的地方都替换掉呢?
1 | numbers[numbers_gray != 255, :] = grad[numbers_gray != 255, :] |
这次黑边确实看不见了,但是总感觉文字很模糊,不够锐利。尤其是数字 0,边缘非常毛糙。
如果我们仔细观察黑白图片,就会发现文字的边缘的颜色是逐渐变浅的,这是因为绘图库为我们做了抗锯齿(Anti-Aliasing)操作。如果我们简单把所有非 255 的值都替换掉,文字的锯齿效果就很明显,特别是 0 这样带有弧度的字符。
为了继承这种抗锯齿效果,最直接的想法就是按照黑色的深浅来调整颜色。如果某个像素的颜色比较浅,则应该把对应的渐变图的颜色也向白色的方向调整。在 RGB 色彩空间中我们不好这样操作,因此更适合转换到 HSV 空间中,调整饱和度。
1 | numbers_gray = cv2.cvtColor(numbers, cv2.COLOR_BGR2GRAY) |
最终效果如下,还是比较满意的:
Logo Mask
最后就是把黑白的 Logo 图当作 mask,制作最终的图片了。
1 | swift = cv2.imread('swift.png', cv2.IMREAD_UNCHANGED) |
理论上我们也应该考虑抗锯齿,但是由于 logo 本身尺寸比较大,效果不明显,所以又偷懒了 : )
最后再来欣赏一下成果吧: