- 作者简介:一名后端开发人员,每天分享后端开发以及人工智能相关技术,行业前沿信息,面试宝典。
- 座右铭:未来是不可确定的,慢慢来是最快的。
- 个人主页:极客李华-CSDN博客
- 合作方式:私聊+
- 这个专栏内容:BAT等大厂常见后端java开发面试题详细讲解,更新数目100道常见大厂java后端开发面试题。
- 我的CSDN社区:https://bbs.csdn.net/forums/99eb3042821a4432868bb5bfc4d513a8
- 微信公众号,抖音,b站等平台统一叫做:极客李华,加入微信公众号领取各种编程资料,加入抖音,b站学习面试技巧,职业规划
Python制作字符画
简介:本文讲解,如何使用python制作字符画,这里使用的是pillow和numpy这两个python的库。
字符画:
简单的字符画是利用字符的形状代替图画的线条来构成简单的人物、事物等形象,它一般由人工制作而成;复杂的字符画通常利用占用不同数量像素的字符代替图画上不同明暗的点,它一般由程序制作而成。
效果展示
这个是我的胡桃老婆,我用她来给大家演示一下。
编码
安装相关的库
首先安装pillow库
再安装numpy库
如果pycharm下载的速度过慢,可以尝试下面的命令的方式,进行下载。
pip install pillow -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
pip install numpy -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
进行编码
初始代码
原理分析:
将图片中的每个像素点,转换成对应的ASCII字符。
这里我用我的老婆,胡桃给大家演示一下
这是第一版的代码,详细的过程已经在代码中写下了注释,原理并不是特别困难,主要是一个pillow和numpy的使用。
from PIL import Image
import numpy as np
def ascill_art(file):
# 打开图片文件
im = Image.open(file)
# 通过灰度覆盖这张图片 降低图片的亮度
im = im.convert("L")
# 对图片进行降采样
sample_rate = 0.15
new_im_size = [int(x * sample_rate) for x in im.size]
im = im.resize(new_im_size)
# 将图片转换成一个numpy字符
im = np.array(im)
# symbols中定义了 我们字符画中的所有字符
# 按照字符亮度升序排列
# 文件转换的时候会不断的查询这个symbols字符集
symbols = np.array(list(" .-vM"))
# 设置这个字符集合的取值范围的最大和最小值[0,max_symbol_index)
im = (im - im.min()) / (im.max() - im.min()) * (symbols.size - 1)
# 完成字符的转换
ascii = symbols[im.astype(int)]
lines = "\n".join(("".join(r) for r in ascii))
print(lines)
if __name__=="__main__":
ascill_art("imgs/img.png")
运行结果:
还是比较大的,我们放到这个文本中观察一下。
放到文档里面之后的样子,是不是很好看了。
分析结果我们发现,做个图片还会被拉长了,希望解决这个问题,我们需要进行一点点的修改。
我们需要下载一个新的字符集,然后使用这段代码,对这个问题进行解决
# 这段代码可以处理图片拉伸的情况
font = ImageFont.truetype("Font/SourceCodePro-Black-1.ttf")
aspect_ratdio = font.getsize("x")[0] / font.getsize("x")[1]
new_im_size = np.array(
[im.size[0] * sample_rate, im.size[1] * sample_rate * aspect_ratdio]
).astype(int)
第二版
文件结构
from PIL import Image
from PIL import ImageFont
import numpy as np
def ascill_art(file):
# 打开图片文件
im = Image.open(file)
# 通过灰度覆盖这张图片 降低图片的亮度
im = im.convert("L")
# 对图片进行降采样
sample_rate = 0.15
# 这段代码可以处理图片拉伸的情况
font = ImageFont.truetype("Font/SourceCodePro-Black-1.ttf")
aspect_ratdio = font.getsize("x")[0] / font.getsize("x")[1]
new_im_size = np.array(
[im.size[0] * sample_rate, im.size[1] * sample_rate * aspect_ratdio]
).astype(int)
# 用新的的图片大小resize之前的
im = im.resize(new_im_size)
# 将图片转换成一个numpy字符
im = np.array(im)
# symbols中定义了 我们字符画中的所有字符
# 按照字符亮度升序排列
# 文件转换的时候会不断的查询这个symbols字符集
symbols = np.array(list(" .-vM"))
# 设置这个字符集合的取值范围的最大和最小值[0,max_symbol_index)
im = (im - im.min()) / (im.max() - im.min()) * (symbols.size - 1)
# 完成字符的转换
ascii = symbols[im.astype(int)]
lines = "\n".join(("".join(r) for r in ascii))
print(lines)
if __name__=="__main__":
ascill_art("imgs/img.png")
运行结果:
第三版
分析第二版,我们发现还是优缺点,这个版本是,灰色的,没有彩色高亮显示,这个问题如何解决了。
解决问题就是,在设置图片为灰度之前,先保留一个原来图片的彩色副本。
然后我这里还解决了如何保存字符画为图片的问题,详细可以看代码,特别是如何设置这个图片的存储位置的方法。
完整代码
from PIL import Image
from PIL import ImageFont, ImageDraw
import numpy as np
def ascill_art(file):
# 打开图片文件
im = Image.open(file)
# 存放图片文件的位置
file2 = file.split("/")[0] + "/"
# 对图片进行降采样
sample_rate = 0.15
# 这段代码可以处理图片拉伸的情况
# 这个truetype可以有第二个参数 也就是指定字符的大小
font = ImageFont.truetype("Font/SourceCodePro-Black-1.ttf")
aspect_ratdio = font.getsize("x")[0] / font.getsize("x")[1]
new_im_size = np.array(
[im.size[0] * sample_rate, im.size[1] * sample_rate * aspect_ratdio]
).astype(int)
# 用新的的图片大小resize之前的
im = im.resize(new_im_size)
# 再进行图片的灰度之前,先保留一个图片的副本
im_color = np.array(im)
# 通过灰度覆盖这张图片 降低图片的亮度
im = im.convert("L")
# 将图片转换成一个numpy字符
im = np.array(im)
# symbols中定义了 我们字符画中的所有字符
# 按照字符亮度升序排列
# 文件转换的时候会不断的查询这个symbols字符集
symbols = np.array(list(" .-vM"))
# 设置这个字符集合的取值范围的最大和最小值[0,max_symbol_index)
im = (im - im.min()) / (im.max() - im.min()) * (symbols.size - 1)
# 完成字符的转换
ascii = symbols[im.astype(int)]
# 创建一个字符图片
letter_size = font.getsize('x')
im_out_size = new_im_size * letter_size
bg_color = "black"
im_out = Image.new("RGB", tuple(im_out_size), bg_color)
draw = ImageDraw.Draw(im_out)
# Draw text
y = 0
for i, line in enumerate(ascii):
for j, ch in enumerate(line):
color = tuple(im_color[i, j])
draw.text((letter_size[0] * j, y), ch, fill=color, font=font)
y += letter_size[1]
lines = "\n".join(("".join(r) for r in ascii))
im_out.save(file2 + "ascii.png")
print(lines)
if __name__=="__main__":
ascill_art("imgs/img.png")
最后的运行结果
一张完美的我老婆的字符画。
如果大家觉得有用的话,可以关注我下面的微信公众号,极客李华,我会在里面更新更多行业资讯,企业面试内容,编程资源,如何写出可以让大厂面试官眼前一亮的简历,让大家更好学习编程,我的抖音,B站也叫极客李华。