python 图像转成字符画
这里写目录标题
前言
最近没什么事研究一下python,发现一个图像转字符图的demo,我试了一下
发现最后生成的是txt文件,感觉不太好看。
所以我改了一下,让他最后生成的是png图像
实现步骤
首先选一张图片—>转化成字符txt文档—>读取txt文档,转换成图像—>保存
实现代码
环境
python3.6
import PIL
import PIL.ImageFont
import PIL.Image
import PIL.ImageDraw
import PIL.ImageOps
import tkinter.filedialog
from tkinter import messagebox
import os
import datetime
代码
1.选择图片
default_dir=r"d:\\"
# 选择图片所在位置
file_path=tkinter.filedialog.askopenfilename(title=u'选择图片jpg,png格式',initialdir=(os.path.expanduser(default_dir)))
print(file_path)
messagebox.showinfo("提示","正在生成字符画请稍后")
#打开图片
im=PIL.Image.open(file_path)
2.修改图片的尺寸
有的图片太大的话,生成的txt文件也大,处理的会很慢,最后一步生成图像时会更慢,还会导致内存不够
#获取图片的宽和高
newWidth=im.width
newHeight=im.height
#判断原图的尺寸,原图越大,修改后的尺寸越小
if(newWidth>1500 or newHeight>1500):
w = int(im.width*0.45)
h = int(im.height/4)
elif(newWidth>1000 or newHeight*1.8>1000):
w = int(im.width * 1.8 / 2)
h = int(im.height / 2)
else:
w = int(im.width * 0.9)
h = int(im.height/2)
#修改图片的尺寸
im=im.resize((w,h),PIL.Image.NEAREST)
3.把图像中的像素的颜色值转换成字符
for i in range(h):
for j in range(w):
txt+=get_char(*im.getpixel((j,i)))
txt+='\n'
#生成字符画所使用的的字符
ascii_char=list(r"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'.")
#将256灰度映射到字符集上
def get_char(r,g,b,alpha=256):
if alpha==0:
return ''
length=len(ascii_char)
gray=int(0.2126*r+0.7152*g+0.0722*b) #计算灰度
unit=(256.0+1)/length
return ascii_char[int(gray/unit)] #不同灰度对应不同字符
#通过灰度来区分色块
4.保存txt文件
保存txt文件,这时候你就得到了一个txt类型的字符画
#选择文件保存的位置
txtpath=file_path.replace('jpg','txt').replace('png','txt').replace('gif','txt')
with open(txtpath,'w') as f:
f.write(txt)
5.把txt文件转换成image文件
先生成img图像,在保存
5.1生成img图像
首先读取txt文件,把txt文件中的字符保存到一个元组中,
然后使用PIL创建一个空白图像
最后把txt文件中的字符作为文本添加到空白图像中,再去掉图像的空白部分就成功了
#txt转image
def text_image(text_path,font_path=None):
grayscale='L'
#解析txt文件,读取文件每行的字符,放到一个元组中
with open(text_path) as text_file:
lines=tuple(l.rstrip() for l in text_file.readlines())
#rstrip :删除字符串结尾字符
#tuple :元组
large_font=10 #字体大小 字体越小生成的图片的大小也会越小
font_path=font_path or 'cour.tff'
#创建一个字体对象
try:
font=PIL.ImageFont.truetype(font_path,size=large_font)
except IOError:
font=PIL.ImageFont.load_default()
#制作背景图像根据 字体和线条
pt2px=lambda pt: int(round(pt*96.2/72))
# 获取lines元组中宽度最大的一个字符串
#作为最后的图像的宽度
max_width_line = max(lines, key=lambda s: font.getsize(s)[0])
test_string=r"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'."
#获取字符串test_string的高度,转换成像素的高度
max_height=pt2px(font.getsize(test_string)[1])
#获取txt中宽度最大的字符串的宽度,转换成像素的宽度
max_width=pt2px(font.getsize(max_width_line)[0])
#图像的高度
#每一行字符串的高度*字符串的行数
height=max_height*len(lines)
#图像的宽度
width=int(round(max_width+20))
#创建一张空白图片 grayscale:模式,L,RGB...
image=PIL.Image.new(grayscale,(width,height),color=PIXEL_OFF)
#创建一个可以用来对image进行操作的对象
draw=PIL.ImageDraw.Draw(image)
vertical_position=5 #垂直
horizontal_position=5 #水平
line_spacing=int(round(max_height*0.8)) #行间距
#向空白图像上写入文本
for line in lines:
#向图片上写文字
# (horizontal_position,vertical_position):开始的位置
# line:内容
#fill=PIXEL_ON,颜色
# font=font 字体 draw.text((horizontal_position,vertical_position),line,fill=PIXEL_ON,font=font)
vertical_position+=line_spacing
print("结束写入文本:%s", datetime.datetime.now())
#将输入图像转换为反色图像
c_box=PIL.ImageOps.invert(image).getbbox()
# image.resize((500, 500), PIL.Image.NEAREST)
print("去掉图像的边框开始:%s", datetime.datetime.now())
#去掉图像的边框
image=image.crop(c_box)
print("去掉图像的边框结束:%s", datetime.datetime.now())
return image
5.2保存图像
保存图像之后在调整一下图像的大小,让新生成的字符画图像和原图大小一致,这样基本上就完成了
#保存图像
newPath=txtpath.replace('txt','png')
image.save(newPath)
#调整图像的大小
ims = PIL.Image.open(newPath)
out = ims.resize((newWidth, newHeight),PIL.Image.ANTIALIAS)
out.save(newPath, 'png')
最后
注意:原图不要太大,因为PIL操作图像时会造成内存泄漏,原图越大使用的内存越大,并且原图越大生成字符画所使用的的时间也越长
原代码在我的github上有需要的可以下载:https://github.com/p910/img-charImg
原代码