本文主要介绍使用python实现图片转为字符画的流程以及代码实现。
你看!字符画胖企鹅!!
你看!!字符画彩色胖企鹅!!
一 流程介绍
要将图片转为字符串画,我们需要做几个步骤:
1. 将图片转为单通道
2. 获取每个像素的亮度值
3. 近似亮度值的像素点使用同一个字符替换
4. 将替换后的字符串(字符画)保存为文本
下面我们一步一步使用python实现。
1. 首先,安装Pillow库
代码语言:javascript复制pip install pillow==9.4.0
2. 读取胖企鹅的图片
代码语言:javascript复制from PIL import Image
image = Image.open("qq.png")
3. 调整图片大小以及格式
由于字符显示的长宽不是相等的,为了转换后的字符画比例正常,我们需要将原图的比例进行压缩。
另外由于文本格式过长会进行自动转换,防止转换出现的乱码问题,我们限制最终字符画的宽度为100。
代码语言:javascript复制# 获取图片宽高
width, height = image.size
ratio = 0.45
# 字符画宽
new_width = 100
# 字符画高
new_height = height / width * new_width * ratio
# 对原始图片进行比例压缩
image = image.resize((new_width, int(new_height)))
# 图片转为灰度图
image = image.convert('L')
4. 创建一个字符集,用于将像素值映射到字符
上面我们将图片映射为灰度图就是想后续相似灰度的像素使用同一个字符进行替换。我们都知道灰度值区间是0--255。黑色为0,白色为255。
所以,这里我们的替换原则是:灰度值越低,使用展示越密集的字符;灰度值越高,使用越稀疏的字符。
所以我们定义字符画中的字符串如下:
代码语言:javascript复制ascii_chars = "$@B%8&WM#*oahkbdpqmZOLJUYXzcunxrft/|()1{}[]?-_ ~<>i!lI;:,"^`'. "
len = len(ascii_chars)
level = 256 // lenth
我们使用的字符串有64个,灰度值一共256个,所以4个灰度值公用一个字符。
5. 图像像素值替换为字符
现在,我们只需要遍历图像,逐点获取每个像素点的像素值,然后用对应的字符去替换即可。
代码语言:javascript复制# 灰度图像像素值
pixels = image.getdata()
# 保存字符串画
ascii_image = ''
for index , pixel_value in enumerate(pixels):
# 每个像素值找到对应的字符串
ascii_image = ascii_chars[pixel_value // level]
# 注意在每行增加一个换行符
if index > 0 and index % new_width == 0:
ascii_image = 'n'
print(ascii_image)
6. 将字符画保存
代码语言:javascript复制with open("ascii_image.txt", "w") as file:
file.write(ascii_image)
我们来看看保存的文本文件什么样子
二 进阶:上色
以上操作就完成了图片转字符串的功能,但是不太完美,企鹅的黄嘴和红围巾没有展示。。
如果我们想保留图片的颜色呢?那我们就需要使用Pillow库的draw功能了。
同样的思路,只是这里获取的像素值是原图原始的rgb值,另外需要将文字绘制到对应位置。
同样,下面我们一步一步使用python实现。
1. 读取图片,调整文件大小
代码语言:javascript复制# 读取图片文件
image = Image.open("qq.png")
# 调整图片大小
# 通过你的字体大小和原始图片大小调整scale
scale = 8
width, height = image.size
new_width = width * scale
new_height = height * scale
image = image.resize((new_width, int(new_height)))
2. 创建字符画ImageDraw
Python图像处理库PIL的ImageDraw模块提供了图像对象的简单2D绘制。我们可以使用ImageDraw创建新的图像,在整个图像上自己绘制字符。
代码语言:javascript复制# 创建新的图片对象,用于绘制字符画
output_image = Image.new('RGB', (new_width, new_height), color='white')
draw = ImageDraw.Draw(output_image)
3. 创建ImageFont
使用ImageDraw绘制字符的接口函数如下
代码语言:javascript复制image_draw.text(xy, text, font=font, fill=(225, 225, 225, 225))
text_xy – 文字的左上角位置
text – 绘制文本
fill – 文字颜色
font – 字体,需要时ImageFont实例
xy就是绘制像素的坐标
text就是绘制的字符,和上一步一样,从自定义的字符中找到合适字符
fill是文字颜色,我们这里使用原图的像素点颜色即可
font对象需要创建,如下:
代码语言:javascript复制# 加载字体文件,可以根据需要修改字体和大小
font = ImageFont.truetype(font_file, size=font_size)
font_file是期望字符画中的字体样式文件,ttf格式
4 绘制和展示字符画
代码语言:javascript复制# 遍历每个像素点,将其转换为对应的字符,并绘制到输出图片上
for x in range(0, new_width, scale * 2):
for y in range(0, new_height, scale * 2):
pixel = image.getpixel((x, y))
char = ascii_chars[pixel[0] // level]
draw.text((x, y), char, fill=pixel, font=font)
# 显示生成的字符画
output_image.show()
我们看看最终效果
三 完整实例代码
talk is cheap show me the code!
灰度字符画完整代码:
代码语言:javascript复制# pip install Pillow库
from PIL import Image
# 读取图片文件
image = Image.open("qq.png")
width, height = image.size
# 字符显示比例
ratio = 0.45
# 字符图过宽会转行乱码
new_width = 100
new_height = int(height / width * new_width * ratio)
image = image.resize((new_width, int(new_height)))
# 图片转为灰度图
image = image.convert('L')
# 定义用于显示的字符串,字符由密到稀排列--黑色密白色稀,最好能被256整除
ascii_chars = "$@B%8&WM#*oahkbdpqmZOLJUYXzcunxrft/|()1{}[]?-_ ~<>i!lI;:,"^`'. "
lenth = len(ascii_chars)
level = 256 // lenth
# 灰度图像像素值
pixels = image.getdata()
# 保存字符串画
ascii_image = ''
for index , pixel_value in enumerate(pixels):
# 每个像素值找到对应的字符串
ascii_image = ascii_chars[pixel_value // level]
# 注意在每行增加一个换行符
if index > 0 and index % new_width == 0:
ascii_image = 'n'
print(ascii_image)
# 保存到文件
with open("ascii_image.txt", "w") as file:
file.write(ascii_image)
彩色字符画完整代码:
代码语言:javascript复制from PIL import Image, ImageDraw, ImageFont
ascii_chars = "$@B%8&WM#*oahkbdpqmZOLJUYXzcunxrft/|()1{}[]?-_ ~<>i!lI;:,"^`'. "
lenth = len(ascii_chars)
level = 256 // lenth
font_file = "font1.ttf"
font_size = 24
# 读取图片文件
image = Image.open("qq.png")
# 调整图片大小
# 通过你的字体大小和原始图片大小调整scale
scale = 8
width, height = image.size
new_width = width * scale
new_height = height * scale
image = image.resize((new_width, int(new_height)))
# 创建新的图片对象,用于绘制字符画
output_image = Image.new('RGB', (new_width, new_height), color='white')
draw = ImageDraw.Draw(output_image)
# 加载字体文件,可以根据需要修改字体和大小
font = ImageFont.truetype(font_file, size=font_size)
# 遍历每个像素点,将其转换为对应的字符,并绘制到输出图片上
for x in range(0, new_width, scale * 2):
for y in range(0, new_height, scale * 2):
pixel = image.getpixel((x, y))
char = ascii_chars[pixel[0] // level]
draw.text((x, y), char, fill=pixel, font=font)
# 显示生成的字符画
output_image.show()
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!