原理很简单的,我们先来看看“字符”的产生,如果我们把一个方格放大N格,成为一个一个的格式,并用颜色替换,就会形成我们的字符如下图,那么由像素组成的图片也是如此的,只是每个格子里面放的是不同的色阶的颜色,也是我们常说的GRB色。
好丑的520,哈哈。把边框去了看看
现在总的来说一下实现的过程,就是在常见的RGB(A)模式图片中,利用每个像素点的R,G,B值按照公式转换成灰度值(0~255),然后在自己创建的字符表中找到灰度值对应的字符,添加到一个文本文件中,就实现了图片转字符画(黑白)。
但是此方法不适用于颜色种类丰富的图片,虽然有对应256个灰度值正好存在256个字符,可以完全区分不同的灰度值,但是毕竟一个像素和一个字符大小相差悬殊,转换后价值不大。
如果要转换一张宽高像素比较大的图片,除了使用ps等修图工具将像素改小,还可以使用pillow库改变图片大小。
以下是我利用pillow库函数把图片像素改小后的转换代码,代码是:
#!/usr/bin/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 = 80)
# 添加输出字符画高参数
parser.add_argument('-height', type = int, default = 80)
# 获取参数数据,使用parse_args()解析 解析对象
args = parser.parse_args()
其中o,width,height为非必须参数,参数数据类型默认为字符串,除非设置type属性,default为参数默认数据。
不加’-‘表示必须参数,同时也是参数名称,此时名称不可以通过添加’- -‘修改;
加’-‘表示可选参数,此时参数名称为当前,如果后面有加’- -‘的,则参数名称改为’- -‘紧接的字符串,此时’-o’和’–output’均可作为输入时的参数声明;
必须参数必须按照add_argument()的顺序添加参数值(中间可插入非必须参数),非必须参数可以打乱顺序,但需要参数名称和参数值一一对应
接下为是重头了,先来看看成果图
你能看出这是什么吗:
好啦,原图是这样子的
怎么样,好玩吧,好那么要怎么写,才能实现这个效果呢,我就不卖关子了,来吧,上代码:
class character():
def __init__(self):
self.IMG = args.file
self.WIDTH = args.width
self.HEIGHT = args.height
self.OUTPUT = args.output
# 不同字符代表不同色块,字符最好不要重复
self.ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
self.txt = ''
# 将256灰度映射到70个字符上
# 图片格式为RGB的*im.getpixel((j,i)后会得到三个参数r(red),g(green),b(blue);RGBA得到四个参数r,g,b,alpha(透明度,0表示完全透明)
# im.getpixel((j,i))得到一个由r, g, b, alpha(如果有的话)构成的元祖,加上*号即表示拆分元祖分别赋值引用
def get_char(self, r, g, b, alpha = 256):
# 如果是透明的,则输出空格
if alpha == 0:
return ' '
length = len(self.ascii_char)
# r,g,b转换为灰度值,白色是255,黑色是0
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
# 单元字符的灰度值大小
unit = (256.0 + 1)/length
# 字符从小到大表示灰度值,已知灰度值大小,一个字符表示的灰度值大小,求该灰度值由第几个字符表示,ascii_char[i]
return self.ascii_char[int(gray/unit)]
def convert(self):
im = Image.open(self.IMG)
# im.resize(size,filter)
# 变量filter为NEAREST、BILINEAR、BICUBIC或者ANTIALIAS之一
# 如果忽略,或者图像模式为“1”或者“P”,该变量设置为NEAREST,速度快
# ANTIALIAS 抗锯齿,质量最高;BICUBIC 三次样条插;BILINEAR 线性插值法
im = im.resize((self.WIDTH,self.HEIGHT), Image.NEAREST)
for i in range(self.HEIGHT):
for j in range(self.WIDTH):
self.txt += self.get_char(*im.getpixel((j,i)))
self.txt += '\n'
def save(self):
if self.OUTPUT:
with open(self.OUTPUT,'w') as f:
f.write(self.txt)
else:
with open("output.txt",'w') as f:
f.write(self.txt)
def start(self):
self.convert();
self.save();
if __name__ == '__main__':
c = character()
c.start()
python picTostr.py –output picTostr_output.txt -height 50 test.jpg -width 100(打乱顺序)
对了,由于要用到PIL,所以你还需要安装这个模块,pip install pillow.