python3实现图片转换为字符画

记得之前看到过有人做了一个小工具,可以将图片用字符展示出来,就是所谓的 字符画 了,今天咱也用python3实现这么一个有趣的小工具。

20180914153691718315759.png

原理

首先理一下思路:

  1. 用字符画图,其实就是用字符替代像素点,所以得有一个字符表;
  2. 字符是偏大的为了更好的呈现字符画的状态,还应该调整图片大小为更低像素,比如80*80
  3. 一幅图片一般情况下就是RGB位图,但是纯文本字符没有色彩可言,所以需要将图片转换为灰度图;
  4. 灰度图一般时8位,取值范围会是0~255,255的值是白色,所以字符表是空格效果会好一些;
  5. 这里使用半角字符作为基本元素,为了是字符画更规整,使用两个一样的半角字符代替一个像素,字符表里的元素位两个一样的字符;
  6. 需要建立图片灰度值与字符表的映射关系,这里使用灰度值映射表索引取字符,可用以下公式计算索引: $$ index = gray / 256 * length $$
    • index: 元素索引
    • gray: 像素点的灰度值
    • length: 字符表的长度

实现思路

本文目标是设计一个命令行小工具,使用命令的时候,需要制定图片的路径,可以指定宽高和保存目录,指定按照上述原理,实现思路也就非常明了:

  1. 建立字符表;
  2. 获取指定的命令参数:
    • 图片路径;
    • 图片宽高;
    • 字符画保存路径;
  3. 读取图片,按照指定尺寸转换图片大小;
  4. 将图片转换为灰度图;
  5. 按行读取像素灰度值获取字符追加到结果字符串中,每读一行追加一个换行;
  6. 保存结果字符串为文本文件;

根据上述思路,会使用以下库:

  • pillow:处理图片并获取图片数据;
  • argparse:放便过滤命令参数,比如指定图片、保存目录,宽高等

实现过程

安装库

argparse 库是官方库,不用安装,这里只需安装 pillow 库:

$ pip3 install pillow

注: 可以阅读 argparse 库的使用 了解 argparse 库的使用!

实现

准备文件

创建文件 img2ascii,然后添加以下内容:

#!/usr/local/bin/python3
from PIL import Image
import argparse

第一行指明脚本解释器的路径,后两行导入所需库,然后为文件指定执行权限:

$ chmod +x img2ascii

这样就可以通过以下方式执行脚本了:

$ ./img2ascii

添加参数解析实现

添加四个参数:

parser = argparse.ArgumentParser(description='此工具可以将图片转换为字符画。')
parser.add_argument('file', help='待转换的图片路径')
parser.add_argument('-o', '--output', help='指定生成字符画的保存路径')
parser.add_argument('-W', '--width', type=int, default=80, help='可以通过此参数指定图片转换大小到一定宽度,单位:像素,默认值:80')
parser.add_argument('-H', '--height', type=int, default=80, help='可以通过此参数指定图片转换大小到一定高度,单位:像素,默认值:80')
args = parser.parse_args()


IMG = args.file
WIDTH = args.width
HEIGHT = args.height
OUTPUT = args.output

生成字符表

构建需要的字符表,其实这个表里的字符可以任意添加:

ascii_chars = list("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ!@#$%^&*()_+|?><.,:;~`1234567890 ")
ascii_table = [c*2 for c in ascii_chars]
TABLE_LENGTH = len(ascii_table)

创建映射函数

映射函数用于获取对应像素点上应该放置的字符串:

def getChars(gray):
    if gray == 255:
        return '  '
    else:
        return ascii_table[int(gray / 256  * TABLE_LENGTH)]

打开图像并灰度化

使用 pillow 库打开图片,将图片转换为灰度图:

im = Image.open(IMG)
im = im.resize((WIDTH, HEIGHT), Image.NEAREST)
im = im.convert('L')
txt = ''

生成字符画

通过读取每个像素点的灰度值,获取替代字符串,生成字符画:

for y in range(HEIGHT):
    for x in range(WIDTH):
        gray = int(im.getpixel((x, y)))
        txt += getChars(gray)
    txt += '\n'

导出字符画文件

将生成的字符画字符串以文件的形式保存到指定路径:

if OUTPUT:
    with open(OUTPUT, 'w') as f:
        f.write(txt)
else:
    with open('output.txt', 'w') as f:
        f.write(txt)

注:

点我 查看完整代码!

测试效果

这里以图片 android-chrome-512x512.png 为例:

$ ./img2ascii android-chrome-512x512.png

这时会看到图片同级目录下出现 output.txt ,打开后就会看到字符画了,尝试加入宽高参数的指定:

$ ./img2ascii android-chrome-512x512.png -W 20 -H 20

得到如下字符画:

20180914153693707997013.png

总结

终于完成了一个简单的工具可以帮助我们得到图片对应的字符画,应该有更好的实现方式,如果以后发现会继续在博客中分享,欢迎持续关注!