字符画就是将一幅图片用字符来表示,保存为一个txt文本文档,主要的效果如图。

安装PIL / install Pillow
我们需要用到Pthon的PIL第三方库,PIL是一个python的强大的图形库。
PIL在Python2.7的时候就停止维护了,在Python3中维护使用的PIL叫作Pillow,可以将这俩看作同一个库。
我这里使用的Pycharm平台,在左上角设置 - 文件 - Python解释器 - 加号 - 搜索pillow - 选择第一个并点击左下角安装。
在安装完成后引入PIL库并命名为Image(这只是一个编程习惯,并不一定要重新命名)。
#引入第三方库 from PIL import Image
读取图片并转换成灰度图片 / open & convert
准备一张图片(这张图片用了超分辨率算法进行增强)。
首先用一个变量来存下原图片,这里用im来表示,将其按照一定比例缩小,因为字符普遍高度比宽度更大,所以注意缩小比例时高度应该缩小更多以保证字符画的比例正常,这个需要根据图片原本比例和字符宽高比例调整,这里就不那么严谨了,写一个差不多的比例就好了。
im = Image.open('src.png') k = 3 # 缩小倍数,需要保证 k >= 1 im = im.resize((im.width // k,im.height // (k + 2)), Image.Resampling.LANCZOS)# 最高精度转换 im = im.convert('L') # 转为黑白图, 每个像素都一个灰度值,从0到255, 0是黑色, 255是白色
open参数为一个字符串表示图片地址。这里需要提前将图片放到和py文件同一个目录下保证相对路径正确。
resize参数第一个是一个二元组(宽度,高度),第二参数为转换模式,Image.Resampling.LANCZOS表示最高精度转换。
convert参数一般有'1'(二值图,非黑即白), 'L'(灰度图片,每一个像素的灰度0 ~ 255), 'P'(8位彩色), 'RGBA'(32位彩色), 'CMYK'等。
设定字符集 / char_set
字符集的作用是,将不同灰度的像素点用不同的字符去代替。比如灰度越高(越黑)的像素点就用@$等单位覆盖率高的字符,而越白的像素点就用. / ( ) 空格等单位覆盖率低的字符去表示。
这里这个字符集出处请见文末参考文档。
# 创建字符集 char_set = '''$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. '''
遍历图片并构造出字符文本 / construct the text
通过双重循环来遍历图片的每一个像素点,再根据像素点的灰度值来选择一个字符加入到字符串后面即可。
for i in range(im.height): for j in range(im.width): gray = im.getpixel((j, i)) # 一个二元组,这里的坐标(x, y)和遍历的顺序相反,所以要用 (j ,i) if isinstance(gray, tuple): # 如果这个灰度值不是一个整数而是一个三元组,就算出一个整型来表示灰度值 gray = int(0.2 * gray[0] + 0.6 * gray[1] * 0.2 * gray[2]) buf += get_char(gray) buf += '\n'
写入文件 / wirte to file
# 将buf内容写入pic.txt open('pic.txt', 'w').write(buf)
完整代码 / complete code
from PIL import Image #设定字符集 char_set = '''$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ''' #打开图片 im = Image.open('src.png') k = 2 # 缩小倍数,需要保证 k >= 1,如果倍数为1,需要调整下一行的 k + 2 改成 k 即可 im = im.resize((im.width // k,im.height // (k + 2)), Image.Resampling.LANCZOS)# 最高精度转换 im = im.convert('L') # 转为黑白图, 每个像素都一个灰度值,从0到255, 0是黑色, 255是白色 def get_char(gray: int)->str: # 将灰度值对应到字符集中 return ' ' if gray > 240 else char_set[int(gray / 257.0 * len(char_set))] buf = '' # 最终结果将存入 buf 再保存到 pic.txt 中 #遍历图片 for i in range(im.height): for j in range(im.width): gray = im.getpixel((j, i)) # 一个二元组,这里的坐标(x, y)和遍历的顺序相反,所以要用 (j ,i) if isinstance(gray, tuple): # 如果这个灰度值不是一个整数而是一个三元组,就算出一个整型来表示灰度值 gray = int(0.2 * gray[0] + 0.6 * gray[1] * 0.2 * gray[2]) buf += get_char(gray) buf += '\n' # 将buf内容写入pic.txt open('pic.txt', 'w').write(buf)
注意最后要用浏览器打开txt文件,否则显示比例会不协调。
Comments 2 条评论
Python3为什么这么牛逼!为什么为什么为什么!还要什么自行车c++ :drooling:
hhhh,要是效率高点就好了,我之前用 Pillow 写的原神抽卡,一张图要渲染大概 3 秒才结束,完全不够过瘾。