字符画是一系列字符的组合,我们可以把字符看作是比较大块的像素,一个字符能表现一种颜色(暂且这么理解吧),字符的种类越多,可以表现的颜色也越多,图片也会更有层次感。
问题来了,像素是有颜色深浅的,我们如何将带有不同颜色的像素编码为对应的字符呢?我们是要转换一张彩色的图片,这么多的颜色,要怎么对应到单色的字符画上去?
转化方法
转化的整体思路就是:RGB->灰度->字符,详细来说就是:
- 将彩色图片转化为灰度图,根据颜色深浅的 RGB 值映射为灰度值;
- 根据字符集顺序及字符集长度,将灰度值映射到字符。
这里就要介绍灰度值和 RGB 的概念了。
- RGB
RGB 色彩模式是通过对红(R)、绿(G)、蓝(B) 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB 即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色。
通常情况下,RGB 各有 256 级亮度,用数字表示为从 0、1、2… 到 255。
- 灰度图
灰度值:指黑白图像中点的颜色深度,范围一般从 0 到 255,白色为 255,黑色为 0,故黑白图片也称灰度图像
那么如何将彩色图片转为灰度呢?
常用的公式如下,可以将像素的 RGB 值映射到灰度值:
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
得到灰度值后,就可以将灰度值和字符进行映射了。可以创建一个不重复的字符列表,灰度值小(暗)的用列表开头的符号,灰度值大(亮)的用列表末尾的符号。
下面是我们的字符画所使用的字符集,一共有 70 个字符,从左住右, 表示的颜色深度依次递减。字符的种类与数量可以自己根据字符画的效果反复调试。
1 | ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ") |
实现
字符集容量为 70,一个字符对应的值:区间宽度= 256/字符集长度,即区间宽度为 256/70 = 3.6。
gray 区间和字符的对应关系
1 | [0.0, 3.6) --> $ |
RGB 转字符的函数
1 | # 将256 灰度映射到 70 个字符上 |
完整代码
1 | import argparse |
运行结果
- 原图
1 | $ python ascii.py ascii_dora.png --width=80 --height=40 |
😜
知识点
命令行解析模块 argparse
看下样例就可以:
1 | # 命令行输入参数处理 |
使用:
1 | $ python ascii.py --help |