Python 生成字符画

王 茂南 2019年10月2日07:33:17
评论
2833字阅读9分26秒
摘要这一篇文章介绍使用 Python 生成字符画的方式。会给出简单的原理介绍和实现的方式。最后会给出源代码的链接地址。

简介

这一篇介绍一下使用 Python 来进行字符画的生成。会详细介绍一下生成的步骤和生成的代码,主要分为三个步骤,使用 Pillow 获取每个像素的 RGB 值,将每个像素转换为字符串,以及最后的将图像转换为字符画。最终的生成的效果会是下面的这个样子:

Python 生成字符画

上面的图可以看出,缩小看后是「铁臂阿童木」,放大看会发现这个图像是由「你好呀,我是小王。」这几个字符串组成的。

参考资料

 

字符画生成的方式和原理

这一部分介绍一下生成字符画的原理和代码实现。会详细来讲解如何生成字符画,主要分为以下的几个部分,会逐一进行介绍:

  • 使用 Pillow 来获取每个像素的 RGB 值;
  • 将每个像素转换为字符;
  • 将图像转换为字符画;

 

使用 Pillow 来获取每个像素的 RGB 值

一张彩色的图片是由红色 (R),绿色 (G) 和蓝色 (B) 三种颜色的矩阵组成的。这里我们利用 Pillow 来详细说明一下。当 Pillow 读取图片的时候,整个图片相当于是在一个二位坐标系上,每个像素都有一个坐标。例如一个 2×2 的图像,每个像素的坐标如下图所示。从左到右,从上到下,坐标值为从 0 到 N:

Python 生成字符画

我们使用 .getpixel() 来获得每个像素点的 RGB 值,这里返回的是元组(tuple)。例如我们想要获得 (1, 1) 这个像素的 RGB 值,则代码如下所示:

  1. from PIL import Image
  2. test_image = Image.open('./girl.jpg')
  3. print(test_image.getpixel((1,1)))
  4. # (110, 22, 20)

有两个特殊 RGB 色需要记忆,分别是「黑色」为 (0, 0, 0) 和「白色」的 (255, 255, 255)。关于 Pillow 的更多使用介绍,可以查看链接,Python 中 Pillow 使用介绍

 

将每个像素转换为字符

上面我们了解了如何得到每个像素的 RGB 值。现在我们希望将每个像素转换为字符串。这里还是分为两个步骤:

  1. 首先创建一个列表,其中为所有可以使用的符号。
  2. 接着将每个像素转换为数字(可以首先将每个像素的 RGB 值求和,接着转换到 0-列表长度这个范围内),作为列表的索引,从而实现将 RGB 色转换为符号。

我们来说明一下如何将像素的 RGB 值转换为符号列表的索引。这个问题简化一下就是希望有一个函数,输入 x 是在 [0, M] 之间,希望输出的值 y 是在 [0, N] 之间。最简单的方法是建立一个一元函数,如下图所示:

Python 生成字符画

于是将每个像素转换为字符串,可以写成下面的两个函数:

  1. from PIL import Image
  2. def num_convert_M2N(M, N, x):
  3.     """将 x 从 0-M 转换为 0-N
  4.     """
  5.     y = N/M*x
  6.     return int(y)
  7. def convert_rgb2sign(r, g, b, signs):
  8.     """将 rgb 值转换为一个符号
  9.     """
  10.     N = len(signs) # 计算 signs 的长度
  11.     y = num_convert_M2N(256*3, N, r+g+b)
  12.     return signs[y]

 

图像转字符画

讲完上面的「使用 Pillow 来获取每个像素的 RGB 值」和「将每个像素转换为字符」后,所有的准备工作就已经做好了。现在来完成最后一步,将图片转换为字符画。概括起来一共三个步骤:

  • 读取图片,并对图片进行缩放(通常情况需要缩小图片,为了最后便于查看);
  • 定义使用的符号集(注意这里的符号需要使用全角的,因为全角长宽相等),最后图片中每个像素会使用符号集中的符号替换(通常情况白色像素点使用空格替换);
  • 遍历每一个像素点,将像素点转换为符号,并写入文件(注意换行等);

我们将上面的三个步骤实现,最终完成的代码如下所示。主要看函数 image_process 中的三个步骤,与上面讲的三个步骤是吻合的(在 get_char_linear 中有一个参数 k,这个是因为可能输入的是 png 的图片,会多一个通道使用的):

  1. from PIL import Image
  2. import fire
  3. def convert_m2n(m, n, x):
  4.     """将 0-k 范围的数字转换为 0-n
  5.     """
  6.     return int(n/m*x)
  7. def get_char_linear(r, g, b, k=None, ascii_char=None):
  8.     """将像素点转换为符号
  9.     """
  10.     length = len(ascii_char)
  11.     ascii_index = convert_m2n(256*3, length, r+g+b)
  12.     return ascii_char[ascii_index]
  13. def image_process(
  14.     input_file,
  15.     output_file='res.txt',
  16.     pic_height=100,
  17.     pic_width=100):
  18.     # 步骤一, 读取图片并调整图片大小
  19.     im = Image.open(input_file)
  20.     im = im.resize((pic_width, pic_height), Image.NEAREST)
  21.     # 步骤二, 定义使用的符号集
  22.     ascii_char = list("你好呀,我是小王。 ")
  23.     # 步骤三, 遍历像素点, 将每一个像素点转换为符号并保存到文件
  24.     txt = ""
  25.     for i in range(pic_height):
  26.         for j in range(pic_width):
  27.             txt += get_char_linear(*im.getpixel((j,i)), ascii_char=ascii_char)
  28.             txt += '  '
  29.         txt += '\n'
  30.     # 字符画输出到文件
  31.     with open(output_file,'w', encoding='utf-8') as f:
  32.         f.write(txt)
  33. if __name__ == '__main__':
  34.     """
  35.     input_file: 图像的名称
  36.     output_file: 保存文件的名称
  37.     """
  38.     fire.Fire(image_process)

最终在使用的时候,可以直接在命令行中进行操作:

  1. python char_pic.py ../char_pic/62.jpg

我们再看一个例子的效果。关于效果的查看,可以使用文本编辑器进行缩放,使用Ctrl+-进行缩放:

Python 生成字符画

 

一些其他的

今天打开 bing 的时候没打开,第一次看到这样的错误提示,很是可爱:

Python 生成字符画

  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南
  • 本文由 发表于 2019年10月2日07:33:17
  • 转载请务必保留本文链接:https://mathpretty.com/11253.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: