基于python 3.8
- github :https://github.com/heli-link/pyCharStyle
- csdn : https://download.csdn.net/download/qq_42733641/13084065
所有更新及打包 exe 都在github,因为更新方便,csdn链接只有代码(忘了加exe,后面发现不能修改,遂罢)周知
界面及使用
复选框选择对应的转换格式,在下方会出现字符选择器和颜色选择器,点击即可选择
图片转换时,界面会卡顿,表现为按钮按下去不会回弹,正常现象,是因为没有加线程,反正只要几秒钟,不影响
转换完成的图片视频在软件根目录
视频转换请勿使用高分辨率,速度太慢,当然输入分辨率越高,转换后的分辨率也高
参考 : i5-7200u 实测 500x300 mp4, 每秒只能处理 1.5 帧
效果(这里只能上图,视频就不做展示,效果参考图片)
- 原图
-图片转 txt
图片转 txt文本
- 图片转指定字符-jpg彩色
同一个字符,通过颜色的变换展现出图像
- 图片转字符-jpg彩色
图片转txt 顺便在添加个颜色
- 图片转字符-jpg指定颜色
不同字符组成的图片,通过指定颜色可以实现,黑白,彩色字符图
绿色貌似不太好,慎用
代码
图片处理
import time
import cv2
import util as u
from PIL import Image, ImageDraw, ImageFont
# 图片转字符文本
def getTxt(src):
txt = ""
path = u.getTime() + '-txt.txt'
file = open(path, 'w')
img = cv2.imread(src)
# 调整图片大小
img = cv2.resize(img, (int(img.shape[1] / 3), int(img.shape[0] / 8.5)))
# 遍历像素
for i in range(img.shape[0]):
for j in range(img.shape[1]):
r, g, b = img[i, j]
txt += u.getchar(r,g,b)
txt += "\n"
file.write(txt)
file.close()
return txt,img.shape[1],img.shape[0]
# 图片转字符图片 两种模式
# mode 0/固定字符/str
# 1/彩色
# 2/指定颜色/color
def img_txtimg(src, msg='o', mode=0, color = '#000000', outpath=None, isvedio=False):
start = time.time()
img = cv2.imread(src)
if outpath == None:
outpath = u.getTime() + '-color.jpg'
# 字符间隔
if isvedio:
coe = 10
font = ImageFont.truetype("C:\\Windows\\Fonts\\AdobeHeitiStd-Regular.otf", coe + 5) # 设置字体
else:
coe = 25
font = ImageFont.truetype("C:\\Windows\\Fonts\\AdobeHeitiStd-Regular.otf", coe+10) # 设置字体
img = cv2.resize(img, (int(img.shape[1] * 0.2), int(img.shape[0] * 0.2)))
H = img.shape[0]*coe
W = img.shape[1]*coe
# 创建画布
im_txt = Image.new("RGB", (W, H), (220, 220, 220))
dr = ImageDraw.Draw(im_txt)
x=y = 0
# 设置字体
# font = ImageFont.truetype("C:\\WINDOWS\\Fonts\\Gill Sans\\GILSANUB.TTF", coe) # 设置字体
# 遍历像素 转成字符
index = 0
buf = 0
first = time.time()
for i in range(0, img.shape[0]):
two = time.time()
for j in range(0, img.shape[1]):
r, g, b = img[i, j]
# 指定字符
if mode == 0:
# 指定字符绘制
dr.text([x, y], msg, (r, g, b), font)
if mode == 1:
msg = u.getchar(r, g, b)
dr.text([x, y], msg, (r, g, b,), font) # 彩色
if mode == 2:
msg = u.getchar(r, g, b)
dr.text([x, y], msg, color, font) # 指定颜色
x += coe
index+=1
buf = index
index = 0
three = time.time()
y += coe
x = 0
fore = time.time()
# 保存字符图片
im_txt.save(outpath,encoding='utf-8')
three = time.time()
print("1=" + str(first - start) + '--> '+str(buf)+'次=' + str(three - two) + '--> 3=' + str(three - two))
# 视频转字符 mode
# 0: '视频转指定字符mp4-原彩'
# 1: '视频转字符jpg-原彩'
# 2: '图片转字符jpg-指定颜色'
def vidio_txtimg(src,mode,msg='o',color=(255,255,255),var=None):
# 清空文件夹
u.clearFile('image')
vidio = cv2.VideoCapture(src)
# 获取原视频帧率
fps = vidio.get(5)
c = 0
while True:
start = time.time()
check, frame = vidio.read()
if check:
src = 'image/'+str(c)+'.jpg'
# 视频抽帧 转换
cv2.imwrite(src,frame)
# '视频转指定字符mp4-原彩'
if mode == 0:
img_txtimg(src, mode=0, msg=msg, outpath=src, isvedio=True)
# '视频转字符mp4-原彩'
if mode == 1:
img_txtimg(src,mode=1,outpath=src,isvedio=True)
# '图片转字符mp4-指定颜色'
if mode == 2:
img_txtimg(src,mode=2,color=color,outpath=src,isvedio=True)
# 实时播放
# img = cv2.imread(src)
# cv2.imshow("frame",cv2.imread(src))
c += 1
var.set('正在处理第'+str(c)+'帧')
else:
break
cv2.waitKey(1)
end = time.time()
print('帧率:'+str(1/(end-start)))
print('帧数:' + str(c))
vidio.release()
u.createVidio(fps,var)
if __name__ == '__main__':
img_txtimg('icon/color.png', mode=2)
GUI 界面
import threading
import tkinter
from tkinter import filedialog
from PIL import Image, ImageTk
import windnd
import tkinter.ttk
import util as u
import cvimg
import text as tx
import tkinter.colorchooser as cc # 给导入的包指定一个别名
from text import color as c
import tkinter.messagebox #这个是消息框,对话框的关键
win = tkinter.Tk()
var = tkinter.StringVar()
# 把图片绑定在类属性中,防止运行过程中被gc清理
class iconimg():
ssabericon = None
coloricon = None
def __init__(self):
# tk只支持 gif,所以需要先使用pil转一下 改代码需放在tk初始化之后,否则会报错
# 设置条形框,插入图片
image = Image.open("icon/saber.jpg")
image = image.resize((32,32))
self.sabericon = ImageTk.PhotoImage(image)
img = Image.open('icon/color.png') # 打开图片
img = img.resize((48,48))
self.coloricon = ImageTk.PhotoImage(img) # 用PIL模块的PhotoImage打开
iconimg = iconimg()
coloricon = iconimg.coloricon
sabericon = iconimg.sabericon
def Conversion(path):
# 获取文件和命令下标
suf = u.suffix(path)
index = combobox.current()
print('suf'+str(suf))
print('index'+str(index))
# 获取字符和颜色
msg = tx.letter[cb.current()]
color = img.color
# 图片处理
if suf == 0:
# 图片转txt
if index == 0:
var.set('图片转txt...')
cvimg.getTxt(path)
var.set('图片转txt,转换结束,请在根目录查看,宁也可以选择继续转换')
# 图片转指定字符画 - 彩色
elif index == 1:
msg = tx.letter[cb.current()]
var.set('图片转指定字符-jpg彩色...')
cvimg.img_txtimg(path, mode=0, msg=msg)
var.set('图片转指定字符-jpg彩色,完成,请在根目录查看,宁也可以选择继续转换')
# 图片转字符画-原彩
elif index == 2:
var.set('图片转字符-jpg彩色...')
cvimg.img_txtimg(path,mode=1)
var.set('图片转字符-jpg彩色,完成,请在根目录查看,宁也可以选择继续转换')
# 图片转字符画-指定颜色
elif index == 3:
var.set('图片转字符-jpg指定颜色...')
cvimg.img_txtimg(path, mode=2,color=color)
var.set('图片转字符-jpg指定颜色,完成,请在根目录查看,宁也可以选择继续转换')
else:
var.set('错误选项')
# 视频处理
if suf == 1:
# '视频转指定字符-mp4彩色',
if index == 4:
msg = tx.letter[cb.current()]
var.set('视频转指定字符-mp4彩色...'+msg)
threading.Thread(target=cvimg.vidio_txtimg,args=(path,0,msg,(255,255,255),var)).start()
# '视频转字符-mp4彩色',
elif index == 5:
var.set('视频转字符-mp4彩色...')
threading.Thread(target=cvimg.vidio_txtimg, args=(path, 1, msg, (255, 255, 255), var)).start()
# cvimg.vidio_txtimg(path, mode=1)
# '视频转字符-mp4指定颜色'
elif index == 6:
var.set('视频转字符-mp4指定颜色...')
threading.Thread(target=cvimg.vidio_txtimg, args=(path, 2, msg, color, var)).start()
# cvimg.vidio_txtimg(path,mode=2,color=color)
else:
var.set('错误选项')
for i in tx.mat:
tx.labermsg += i
# 获取图片路径,并进行格式判别
class img():
def __init__(self):
self.imgfile = ''
self.color = '#000000'
def _func(self,ls):
for i in ls:
#得到的是一个字节
i = i.decode()
if u.suffix(i) == 2:
var.set('不支持的格式')
else:
self.imgfile = i
var.set('已选择:'+self.imgfile)
def showfile(self,event):
cur = filedialog.askopenfilenames(filetypes=[('图片视频',tx.mat)])
for i in cur:
if u.suffix(i) == 2:
var.set('不支持的格式')
else:
self.imgfile = i
var.set('已选择:' + self.imgfile)
img = img()
# 全局点击事件
class winOnclick():
def logoclick(self,event):
tkinter.messagebox.showinfo(title='Hi', message=tx.info)
# 图片选择器点击事件
def colorclick(self,event):
(rgb, hx) = cc.askcolor()
img.color = hx
# 复选框点击事件
def comboboxclick(self,event):
index = combobox.current()
if index == 1 or index == 4:
# 开启字符选择
var.set('请选择目标字符,默认为 o ')
cb.place(x=270, y=90)
else:
var.set('')
cb.place_forget()
if index == 3 or index == 6:
var.set('请选择要转换的颜色,默认为黑白 ')
colorlaber.place(x=370, y=80)
else:
colorlaber.place_forget()
# 开始转换点击事件
def start(self):
path = img.imgfile
print('imgfile:' + path)
if path == '':
var.set('没有选择任何文件')
return
else:
Conversion(path)
wc = winOnclick()
def initWindows(w,h):
win.title("图片视频转字符")
# 获取屏幕宽高
ws = win.winfo_screenwidth()
hs = win.winfo_screenheight()
# 计算中心点
x = (ws - w) / 2
y = (hs - h) / 3
win.geometry('%dx%d+%d+%d' % (w, h, x, y))
# win.configure(bg='#95938a')
# 可调整大小
win.resizable(0, 0)
initWindows(450,200)
# 文件拖拽上传区域绘制
canvas = tkinter.Canvas(win, width=500, height=300,bg=c.bg)
canvas.create_rectangle(15, 45, 255, 185, outline = c.frame,fill=c.frame)
x=130
y= 70
line = canvas.create_line(x,y-20,x,y+20,fill = c.line,dash=1)
line2 = canvas.create_line(x-20,y,x+20,y,fill = c.line,dash=1)
canvas.place(x=-3, y=-3)
tkinter.Label(win, text=tx.labermsg,bg=c.frame).place(x=50, y=100)
# 信息提示
# tkinter.Label(win,text='提示:',fg='red').place(x=40,y=10)
info = tkinter.Label(win,textvariable=var,fg=c.info,bg=c.bg)
info.place(x=55, y=10)
# 图片选择器 laber没有点击事件 通过通用事件绑定 Button-1表示左键单击事件
colorlaber = tkinter.Label(win, image = coloricon)
colorlaber.bind('<Button-1>', wc.colorclick)
# 个人logo
sabericon = tkinter.Label(win, image = sabericon)
sabericon.bind('<Button-1>', wc.logoclick)
sabericon.place(x=10, y=3)
# tkinter.Label(win,text='UID:4669').place(x=340, y=120)
# 复选框
combobox = tkinter.ttk.Combobox(win)
combobox['value'] = tx.mode
combobox.current(0)
combobox['state'] = 'readonly'
combobox.bind("<<ComboboxSelected>>",wc.comboboxclick)
combobox.place(x = 270,y = 45)
# 字符选择器
cb = tkinter.ttk.Combobox(win, width=4)
cb['value'] = tx.letter
cb.current(78)
cb['state'] = 'readonly'
# 按钮
bt1 = tkinter.Button(win, text='开始',bg=c.bt,width=22, command=wc.start)
bt1.place(x=270, y=150)
# 文件上传
windnd.hook_dropfiles(win,func=img._func)
bt2 = tkinter.Label(win, text='点击上传',bg=c.bt, width=8)
bt2.bind('<Button-1>', img.showfile)
bt2.place(x=181, y=48)
win.mainloop()
工具类
import os
from datetime import datetime
import cv2
import shutil
def clearFile(file):
shutil.rmtree(file)
os.mkdir(file)
# 返回当前时间
def getTime():
return datetime.now().strftime("%Y%m%d_%H%M%S")
# rgb 转 字符
def getchar(r,g,b):
# 我们定义的不重复的字符列表,灰度值小(暗)的用列表开头的符号,灰度值大(亮)的用列表末尾的符号
ascii_char = list("MNHQ$OC67)oa+>!:+. ")
length = len(ascii_char)
unit = (256.0 + 1) / length
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
return ascii_char[int(gray / unit)]
# 合成视频
def createVidio(fps,var):
img = cv2.imread('image/1.jpg') # 读取第一张图片
outpath = getTime()+'-color.mp4'
imgInfo = img.shape
size = (imgInfo[1], imgInfo[0]) # 获取图片宽高度信息
print(size)
# 设置视频格式 MP4
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
videoWrite = cv2.VideoWriter(outpath, fourcc, fps, size) # 根据图片的大小,创建写入对象 (文件名,支持的编码器,5帧,视频大小(图片大小))
# videoWrite = cv2.VideoWriter('0.mp4',fourcc,fps,(1920,1080))
files = os.listdir('image/')
# 获取图片数量
out_num = len(files)
for i in range(0, out_num):
fileName = 'image/' + str(i) + '.jpg' # 循环读取所有的图片,假设以数字顺序命名
img = cv2.imread(fileName)
videoWrite.write(img) # 将图片写入所创建的视频对象
# 进度条
per = int((i / out_num)*100)
print('进度:'+str(per)+'%')
var.set('正在生成视频,进度:'+str(per)+'%')
videoWrite.release()
var.set('完成,请在根目录中查看,帧率:'+str(fps))
# 清除痕迹
clearFile('image')
def suffix(path):
suf = path.split('.')[-1]
if suf == 'jpg' or suf == 'png' or suf == 'jpeg':
return 0
if suf == 'mp4':
return 1
else:
return 2
if __name__ == '__main__':
print(str(suffix('D:\python\python.exe D:/code/Python/风格转换/main.mp4')))
还有一些零零碎碎的
- delete 删除的部分代码,总感觉以后有用
- text 一些文本信息