一.介绍什么是图片转字符画
字符画是一系列字符组合成的文本,看起来就像一幅画一样,如图1所示。
手动绘制肯定是不现实的,但是我们可以使用python来实现图片转字符画如下面的示意图一般:
这样转换出来的效果还是不错的自我感觉良好。
二.实现过程
首先认清,一张图片是由一个一个像素点组成的,我们转换成字符画就需要将其每个像素点转换成合适的字符。
1.彩色图片我们一般是先转换成黑白色的再进行转换
有两种方案可以实现彩色图片转为灰度图片
方案一:利用灰度公式将像素的 RGB 值映射到灰度值
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
方案二:利用PIL库所带的convert(“L”)函数转化图片
2.将图片与自己准备的字符集建立映射,也就是使灰度值和字符集建立映射
字符集可以自己设置,也可以在网上找,以下给出两种方案:
方案一:
code_list = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
方案二:
code_list = list("qwertyuiop[]asdfghjkl;'zxcvbnm,./`~!@#$%^&<()*+{}:"?> |")
两种字符集我都使用过,在我的代码和测试图片下是方案一的字符集转换出来图片更加真实
3.将转换后的字符串保存进txt文档中
三、代码实现
1.完整代码如下:
class ASCIIart(object):
def __init__(self, file):
"""
传入参数为文件名进行一个赋值方便后续调用,codelist是字符集,用于替换每像素点的灰度值
count计算字符集的长度
:param file:
"""
self.file = file
self.codelist = """$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. """
self.img = Image.open(file)
self.count = len(self.codelist)
def get_char(self, r, g, b, alpha=256):
"""
用来处理灰度值和字符集的关系
:return:
"""
if alpha == 0:
return " "
length = self.count # 获取字符集的长度
gary = 0.2126 * r + 0.7152 * g + 0.0722 * b # 将RGB值转为灰度值
unit = 265 / length
return self.codelist[int(gary / unit)]
def get_new_img(self):
"""
用于处理图片是转换的字符画不至于失真
:return:
"""
w, h = self.img.size
print(f"图片的原始宽度和高度为:{w},{h}")
if not w or not h:
pass
else:
if w <= 299 or h <= 299:
w = int(w / 1.4)
h = int(h / 1.4)
if 300 <= w <= 500 or 300 <= h <= 500:
w = int(w / 2)
h = int(h / 2)
if 500 < w < 1000 or 500 < h < 1000:
w = int(w / 3.8)
h = int(h / 3.8)
if 1000 <= w or 1000 <= h:
w = int(w / 10)
h = int(h / 10)
print(f"修改后图片的宽度和高度为:{w},{h}")
"""
Image.ANTIALIAS: 高质量
Image.NEAREST: 低质量
Image.BILINEAR: 双线性
Image.BICUBIC: 三次样条插值
"""
im = self.img.resize((w, h), Image.ANTIALIAS)
return im
def get_str_img(self, im, output=None):
"""
获取字符串图片
:return:
"""
w, h = im.size
txt = ""
for i in range(h):
for j in range(w):
txt += self.get_char(*im.getpixel((j, i)))
txt += "\n"
# 字符画输出到文件
if output:
with open(output, "w") as file:
file.write(txt)
else:
with open("output/output3.txt", "w") as file:
file.write(txt)
if __name__ == '__main__':
file = "image/thing.jpg"
img = ASCIIart(file)
im = img.get_new_img()
img.get_str_img(im)
2.各个函数(方法)的讲解
def __init__(self, file):
"""
传入参数为文件名进行一个赋值方便后续调用,codelist是字符集,用于替换每像素点的灰度值
count计算字符集的长度
:param file:
"""
self.file = file
self.codelist = """$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. """
self.img = Image.open(file)
self.count = len(self.codelist)
__init__其实是面向对象一个类中的内置方法,用于给类的属性传递参数
file图片文件的名字
codelist用于存储字符集
img是PIL库中Image实例出来的对象,调用open方法打开文件file
count用于保存字符集的长度
def get_char(self, r, g, b, alpha=256):
"""
用来处理灰度值和字符集的关系
:return:
"""
if alpha == 0:
return " "
length = self.count # 获取字符集的长度
gary = 0.2126 * r + 0.7152 * g + 0.0722 * b # 将RGB值转为灰度值
unit = 265 / length # 由于灰度值有256,但是字符集只有70多个
return self.codelist[int(gary / unit)]
此函数用来获取每个灰度值对应的字符
由于灰度值有256,但是字符集只有70多个,所以需要相邻的几个灰度值对应相同的字符
gary得到的结果就是灰度值,返回值实际上就是一个字符
def get_new_img(self):
"""
用于处理图片是转换的字符画不至于失真
:return:
"""
w, h = self.img.size
print(f"图片的原始宽度和高度为:{w},{h}")
if not w or not h:
pass
else:
if w <= 299 or h <= 299:
w = int(w / 1.4)
h = int(h / 1.4)
if 300 <= w <= 500 or 300 <= h <= 500:
w = int(w / 2)
h = int(h / 2)
if 500 < w < 1000 or 500 < h < 1000:
w = int(w / 3.8)
h = int(h / 3.8)
if 1000 <= w or 1000 <= h:
w = int(w / 10)
h = int(h / 10)
print(f"修改后图片的宽度和高度为:{w},{h}")
"""
Image.ANTIALIAS: 高质量
Image.NEAREST: 低质量
Image.BILINEAR: 双线性
Image.BICUBIC: 三次样条插值
"""
im = self.img.resize((w, h), Image.ANTIALIAS)
return im
get_new_img函数的作用是裁剪图片将其变为合适的尺寸,这样转换出来的字符画更接近真实
not w or not h这里是为了将损坏的图片检查出来
Image中的size方法可以直接返回这张图片的宽和高
Image.ANTIALIAS: 高质量
Image.NEAREST: 低质量
Image.BILINEAR: 双线性
Image.BICUBIC: 三次样条插值
这几个方法可以修改图片的质量
返回值是一个新的im对象
def get_str_img(self, im, output=None):
"""
获取字符串图片
:return:
"""
w, h = im.size
txt = ""
for i in range(h):
for j in range(w):
txt += self.get_char(*im.getpixel((j, i)))
txt += "\n"
# 字符画输出到文件
if output:
with open(output, "w") as file:
file.write(txt)
else:
with open("output/output3.txt", "w") as file:
file.write(txt)
get_str_img此函数用于遍历黑白图片的每一个像素点,并使用Image中的getpixel方法获得其r,g.b和alpha(并不是每个像素点都有)三个值
使用for循环的嵌套,将每个像素点对应的字符获取从到并拼接起来,一行一行拼接。
最后将txt这个字符串输出到文件中即可