文章目录(Table of Contents)
简介
这一篇介绍一下使用 Python 来进行字符画的生成。会详细介绍一下生成的步骤和生成的代码,主要分为三个步骤,使用 Pillow
获取每个像素的 RGB
值,将每个像素转换为字符串,以及最后的将图像转换为字符画。最终的生成的效果会是下面的这个样子:
上面的图可以看出,缩小看后是「铁臂阿童木」,放大看会发现这个图像是由「你好呀,我是小王。」这几个字符串组成的。
参考资料
- Python 中 Pillow 使用介绍,处理图像部分会使用到
Pillow
; - Python Fire介绍,让我们很方便的直接使用命令行来进行运行;
字符画生成的方式和原理
这一部分介绍一下生成字符画的原理和代码实现。会详细来讲解如何生成字符画,主要分为以下的几个部分,会逐一进行介绍:
- 使用
Pillow
来获取每个像素的RGB
值; - 将每个像素转换为字符;
- 将图像转换为字符画;
使用 Pillow 来获取每个像素的 RGB 值
一张彩色的图片是由红色 (R),绿色 (G) 和蓝色 (B)
三种颜色的矩阵组成的。这里我们利用 Pillow
来详细说明一下。当 Pillow
读取图片的时候,整个图片相当于是在一个二位坐标系上,每个像素都有一个坐标。例如一个 2×2
的图像,每个像素的坐标如下图所示。从左到右,从上到下,坐标值为从 0 到 N:
我们使用 .getpixel()
来获得每个像素点的 RGB
值,这里返回的是元组(tuple)。例如我们想要获得 (1, 1)
这个像素的 RGB
值,则代码如下所示:
- from PIL import Image
- test_image = Image.open('./girl.jpg')
- print(test_image.getpixel((1,1)))
- # (110, 22, 20)
有两个特殊 RGB 色需要记忆,分别是「黑色」为 (0, 0, 0) 和「白色」的 (255, 255, 255)。关于 Pillow 的更多使用介绍,可以查看链接,Python 中 Pillow 使用介绍。
将每个像素转换为字符
上面我们了解了如何得到每个像素的 RGB
值。现在我们希望将每个像素转换为字符串。这里还是分为两个步骤:
- 首先创建一个列表,其中为所有可以使用的符号。
- 接着将每个像素转换为数字(可以首先将每个像素的
RGB
值求和,接着转换到0-列表长度
这个范围内),作为列表的索引,从而实现将RGB
色转换为符号。
我们来说明一下如何将像素的 RGB
值转换为符号列表的索引。这个问题简化一下就是希望有一个函数,输入 x
是在 [0, M]
之间,希望输出的值 y
是在 [0, N]
之间。最简单的方法是建立一个一元函数,如下图所示:
于是将每个像素转换为字符串,可以写成下面的两个函数:
- from PIL import Image
- def num_convert_M2N(M, N, x):
- """将 x 从 0-M 转换为 0-N
- """
- y = N/M*x
- return int(y)
- def convert_rgb2sign(r, g, b, signs):
- """将 rgb 值转换为一个符号
- """
- N = len(signs) # 计算 signs 的长度
- y = num_convert_M2N(256*3, N, r+g+b)
- return signs[y]
图像转字符画
讲完上面的「使用 Pillow
来获取每个像素的 RGB
值」和「将每个像素转换为字符」后,所有的准备工作就已经做好了。现在来完成最后一步,将图片转换为字符画。概括起来一共三个步骤:
- 读取图片,并对图片进行缩放(通常情况需要缩小图片,为了最后便于查看);
- 定义使用的符号集(注意这里的符号需要使用全角的,因为全角长宽相等),最后图片中每个像素会使用符号集中的符号替换(通常情况白色像素点使用空格替换);
- 遍历每一个像素点,将像素点转换为符号,并写入文件(注意换行等);
我们将上面的三个步骤实现,最终完成的代码如下所示。主要看函数 image_process
中的三个步骤,与上面讲的三个步骤是吻合的(在 get_char_linear
中有一个参数 k
,这个是因为可能输入的是 png
的图片,会多一个通道使用的):
- from PIL import Image
- import fire
- def convert_m2n(m, n, x):
- """将 0-k 范围的数字转换为 0-n
- """
- return int(n/m*x)
- def get_char_linear(r, g, b, k=None, ascii_char=None):
- """将像素点转换为符号
- """
- length = len(ascii_char)
- ascii_index = convert_m2n(256*3, length, r+g+b)
- return ascii_char[ascii_index]
- def image_process(
- input_file,
- output_file='res.txt',
- pic_height=100,
- pic_width=100):
- # 步骤一, 读取图片并调整图片大小
- im = Image.open(input_file)
- im = im.resize((pic_width, pic_height), Image.NEAREST)
- # 步骤二, 定义使用的符号集
- ascii_char = list("你好呀,我是小王。 ")
- # 步骤三, 遍历像素点, 将每一个像素点转换为符号并保存到文件
- txt = ""
- for i in range(pic_height):
- for j in range(pic_width):
- txt += get_char_linear(*im.getpixel((j,i)), ascii_char=ascii_char)
- txt += ' '
- txt += '\n'
- # 字符画输出到文件
- with open(output_file,'w', encoding='utf-8') as f:
- f.write(txt)
- if __name__ == '__main__':
- """
- input_file: 图像的名称
- output_file: 保存文件的名称
- """
- fire.Fire(image_process)
最终在使用的时候,可以直接在命令行中进行操作:
- python char_pic.py ../char_pic/62.jpg
我们再看一个例子的效果。关于效果的查看,可以使用文本编辑器进行缩放,使用Ctrl+-
进行缩放:
一些其他的
今天打开 bing
的时候没打开,第一次看到这样的错误提示,很是可爱:
- 微信公众号
- 关注微信公众号
- QQ群
- 我们的QQ群号
评论