Img2Word By Python

将一张图片用字符表示。

效果图:

63DD1284-3477-4DDC-82BC-77D3B8B11A1A

包结构

第一个是 py 文件,第二个是想要转换成字符的图片,第三个输出字符的文档。

导包

1
2
from PIL import Image
import argparse

这两个包前者是 Python 中强大的图片处理工具库,后者是由 optparse 驱动的用来管理命令行参数输入的工具:

1
2
3
4
5
6
7
8
9
This module is an optparse-inspired command-line parsing library that:

- handles both optional and positional arguments
- produces highly informative usage messages
- supports parsers that dispatch to sub-parsers

# 可处理可选择的和指定位置的参数
# 能够提取非常有用的信息
# 支持解析部分参数

获取输入的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#命令行输入参数处理
parser = argparse.ArgumentParser()

parser.add_argument('file') #输入文件
parser.add_argument('-o', '--output') #输出文件
parser.add_argument('--width', type = int, default = 120) #输出字符画宽
parser.add_argument('--height', type = int, default = 120) #输出字符画高

#获取参数
args = parser.parse_args()

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

字符集

1
ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")

这个字符集合可以自己来定义,一般情况下,越长越多,能表示颜色就越多,图片也就更清晰有层次感。

关于灰度

将一张彩色的照片转换成黑白的,用一定的算法,这里用的计算方式:

1
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)

映射

将灰度一一对应到定义好的字符集中:

1
2
3
4
5
6
7
8
def get_char(r,g,b,alpha = 256):
if alpha == 0:
return ' '
length = len(ascii_char)
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)

unit = (256.0 + 1)/length
return ascii_char[int(gray/unit)]

遍历像素并输出

获取到对应图片,通过 im.getpixel() 方法获取到该图片中每个像素点的色值,再通过之前的灰度映射方法获取到对应的字符,输出到指定的文档中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if __name__ == '__main__':

im = Image.open(IMG)
im = im.resize((WIDTH,HEIGHT), Image.NEAREST)

txt = ""

for i in range(HEIGHT):
for j in range(WIDTH):
txt += get_char(*im.getpixel((j,i)))
txt += '\n'

print txt

#字符画输出到文件
if OUTPUT:
with open(OUTPUT,'w') as f:
f.write(txt)
else:
with open("output.txt",'w') as f:
f.write(txt)

运行

到对应的目录下执行命令行就好了

1
python ascii.py img.png

记得要跟上图片的文件名(别的参数可选)

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PIL import Image
import argparse

#命令行输入参数处理
parser = argparse.ArgumentParser()

parser.add_argument('file') #输入文件
parser.add_argument('-o', '--output') #输出文件
parser.add_argument('--width', type = int, default = 120) #输出字符画宽
parser.add_argument('--height', type = int, default = 120) #输出字符画高

#获取参数
args = parser.parse_args()

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

ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")

# 将256灰度映射到70个字符上
def get_char(r,g,b,alpha = 256):
if alpha == 0:
return ' '
length = len(ascii_char)
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)

unit = (256.0 + 1)/length
return ascii_char[int(gray/unit)]

if __name__ == '__main__':

im = Image.open(IMG)
im = im.resize((WIDTH,HEIGHT), Image.NEAREST)

txt = ""

for i in range(HEIGHT):
for j in range(WIDTH):
txt += get_char(*im.getpixel((j,i)))
txt += '\n'

print txt

#字符画输出到文件
if OUTPUT:
with open(OUTPUT,'w') as f:
f.write(txt)
else:
with open("output.txt",'w') as f:
f.write(txt)

代码来源