一段时间以前用于练手的一个小项目。实现的主要功能是做一个exe(简陋的 XD),上传一张图片,并自动将其转化成字符画。效果如下:
1. 一些Tips:
(1)适合图片主体为大面积、不同色图像;
(2)可以调整字符数、字符类型,用以改进效果;
(3)设置用于画图的字符时,尽量用形状更小的字符代表更浅的颜色;也可以根据生成的字符画,选择合适的字符类型(如上图中的眼泪用 ‘l’ 就比较合适);
(4)远看效果会好一些;
2. 以下是其实现代码:
# Encoding=UTF-8
"""
CreateTime: ***
说明:点击上传图片,并将之转化为字符图
"""
from tkinter import *
from tkinter import simpledialog, filedialog
from tkinter import messagebox
from PIL import Image,ImageTk
import os
# 创建窗口:实例化一个窗口对象
window = Tk()
# 设置窗口大小:注意该乘号为 小写字母x
window_width = 1000
window_height = 600
window.geometry('1000x600')
# 设置窗口位置:window.geometry('800x400+位置横坐标+位置纵坐标')
# 设置窗口名称:
window.title('trans')
# 图片大小转化。先以高度为准。
def scale_resize(img):
w_old, h_old = img.size[0], img.size[1]
h_new = int(window_height*0.8) # 高度为窗口高度的0.8
scale = h_new/h_old
w_new = int(w_old*scale) # 按原比例转换
if w_new > 0.4*window_width: # 如果按原比例转换后宽度超过窗口宽度的0.4倍
w_new = int(0.4*window_width) # 则按宽度转换
scale = w_new / w_old
h_new = int(h_old*scale)
img_new = img.resize((w_new,h_new))
return img_new
# 获取用于替换的字符
def get_char(r, g, b, alpha=256):
# 判断 alpha 值
if alpha == 0:
return ' '
# 用于画图的字符
# ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
# 选取适合图片的字符集
ascii_char = list("$@#%*bil,'. ")
# 获取字符集的长度,这里为 70
length = len(ascii_char)
# 将 RGB 值转为灰度值 gray,灰度值范围为 0-255
# Gray = R*0.299 + G*0.587 + B*0.114
gray = int(0.299 * r + 0.587 * g + 0.114 * b)
# 灰度值范围为 0-255,而字符集只有 70,需要将灰度值映射到指定的字符上
unit = (256.0 + 1) / length
# 返回灰度值对应的字符
return ascii_char[int(gray / unit)]
# 图片转换为字符画任务脚本
def task1(img):
width, height = int(0.1*img.size[0]), int(0.1*img.size[1])
img = img.resize((width, height))
# 初始化输出的字符串
txt = ""
for i in range(height):
# 遍历该行中的每一列
for j in range(width):
# 将 (j,i) 坐标的 RGB 像素转为字符后添加到 txt 字符串
txt += get_char(*img.getpixel((j, i))) # getpixel是获取图像中某一点像素的RGB颜色值
txt += get_char(*img.getpixel((j, i))) # 鉴于一个字符长度比宽度大,故为了显示好看,每行输出两次。未必通用
# 遍历完一行后需要增加换行符
txt += '\n'
# 输出到屏幕
return txt
# 选择图片文件并显示图片
def choose_pic():
file = filedialog.askopenfilename(initialdir=os.path.dirname(__file__)) #打开文件
img_open = Image.open(file)
global img_resize
img_resize = scale_resize(img_open) # 图片大小转换
img = ImageTk.PhotoImage(img_resize)
label_pic.config(image=img)
label_pic.image = img
# 转换图片函数
def trans_pic():
# 得到转换后字符图的txt
txt = task1(img_resize)
#print(txt)
text_pic.delete("1.0", 'end') # 清理文本框中原有内容
text_pic.insert("1.0", txt) # 将生成的字符图文本输入到文本框
# 上传按钮
button = Button(window,text="上传图片",font=("宋体",10),fg="blue",command=choose_pic)
button.grid(row=1,column=1)
label_pic = Label(window)
label_pic.grid(row=2,column=1)
# 图片转换按钮
button = Button(window,text="图片转换",font=("宋体",10),fg="blue",command=trans_pic)
button.grid(row=1,column=2)
# 设置转换后字符画展示窗口
text_pic = Text(window, font=('Courier New',8),width=80,height=40)
text_pic.grid(row=2,column=2)
# 展示窗口
window.mainloop()