python3彩色图片转字符图

Python3 彩色图片转字符图

实现的最终效果

我们想要实现的一种如下所示的效果:

输入的原图

happy.jpg

输出的效果图(由字符构成的图)

微信截图_20230201184917.png

我们来看看如何通过Python的PIL库来实现。

具体实现代码

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
56
57
58
from PIL import Image, ImageDraw, ImageFont

# 将图片处理成字符画
def img2ascii(img, outName, ascii_chars, isgray, font, scale):
# 将图片转换为 RGB 模式
im = Image.open(img).convert('RGB')
# 设定处理后的字符画大小
print(im.width)
print(im.height)
raw_width = int(im.width * scale)
raw_height = int(im.height * scale)
# 获取设定的字体的尺寸
font_x, font_y = font.getsize(' ')
# 确定单元的大小
block_x = int(font_x * scale)
block_y = int(font_y * scale)
# 确定长宽各有几个单元
w = int(raw_width/block_x)
h = int(raw_height/block_y)
# 将每个单元缩小为一个像素
im = im.resize((w, h), Image.NEAREST)
# txts 和 colors 分别存储对应块的 ASCII 字符和 RGB 值
txts = []
colors = []
for i in range(h):
line = ''
lineColor = []
for j in range(w):
# 获取RGB的值,pixel格式[R, G, B]
pixel = im.getpixel((j, i))
lineColor.append((pixel[0], pixel[1], pixel[2]))
# 根据该点的RGB值,将其转换成对应的字符
line += get_char(ascii_chars, pixel[0], pixel[1], pixel[2])
txts.append(line)
colors.append(lineColor)
# 创建新画布
img_txt = Image.new('RGB', (raw_width, raw_height), (255, 255, 255))
# 创建 ImageDraw 对象以写入 ASCII
draw = ImageDraw.Draw(img_txt)
for j in range(len(txts)):
for i in range(len(txts[0])):
if isgray:
# 可以去https://www.sioe.cn/yingyong/yanse-rgb-16/ 查一下(119,136,153)是什么颜色的
draw.text((i * block_x, j * block_y), txts[j][i], (119,136,153))
else:
draw.text((i * block_x, j * block_y), txts[j][i], colors[j][i])
img_txt.save(outName)

# 将不同的灰度值映射为 ASCII 字符
def get_char(ascii_chars, r, g, b):
length = len(ascii_chars)
# 对于 sRGB 色彩空间,一种颜色的相对亮度定义为:
# L = 0.2126 * R + 0.7152 * G + 0.0722 * B
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
# gray在0-255之间,因此gray/256 * length 肯定是介于 [0, length - 1]之间
return ascii_chars[int(gray/(256/length))]

img2ascii('happy.jpg', 'after_happy.jpg', 'MNHQ$OC67+>!:-. ', True, ImageFont.load_default(), 1)

相关库

Python的Image库:Pillow

可以链接查看其各个模块的详细使用文档,该程序使用的主要是以下几个方法Image.openImage.convertImage.resizeImage.newImageDraw.Drawimage.save

代码解读

首先通过Image.open读原图,并通过Image.convert将其转换为RGB模式。convert函数支持的具体模式列表可参考官方文档

官方文档中对于L模式(8-bit pixels, black and white)与RGB模式的转换公式如下:

1
L = R * 299/1000 + G * 587/1000 + B * 114/1000

所以,如果我们不采用sRGB也可以尝试一下通过这种方式来将RGB转换为亮度,即上文代码中的get_char函数中的gray的计算方式。

获取图片后,紧接着获取图片的宽高,并根据scale值计算处理后图的宽高,并原图按照处理后的宽高进行缩放,即resize,第二个参数为缩放过程的取样方式,Image.NEAREST即取距离最近的像素而忽略其他的输入像素,其他可取的值还有Image.BOX等等,具体可以参考文档

然后通过txts存储像素转换之后的字符,colors存储像素转换后的颜色。

最终,通过ImageDraw逐个字符的写入并保存。

感谢您的支持,予人玫瑰,手有余香