用python写了一个超酷的视频转ASCII码的软件
开发实录
- UI设计
- tkinter
- 功能实现
- 程序开始运行
- 视频提取帧图片
- 图片转换为ASCII形式
- 图片合成视频
- 提取音频与合成音频
- 打包为exe形式
- 源代码
- github源地址
UI设计
- 浏览文件夹及输入视频地址框
- 浏览文件夹及保存位置输入框
- 颜色模式选择单选按钮
- 视频缩放比例滑动刻度条
- 程序执行结果输出滚动文本框
tkinter
- 设置窗口图标,将图片转换为base64编码形式以变量存放,代码运行时解码并转换为图片,图标设置完成之后删除图片。背景图片也是这样设置,base64编码过长就不放出来了
img=b'AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAlJSX/KSkp/y0tLf8wMDD/NjY2/0RERP+Dg4P/Pz8//x4eHv8hISH/IiIi/x0dHf8rKyv/Ly8v/4SEhP+jo6P/HBwc/yEhIf8mJib/KCgo/yEhIf9gYWH/PT4+/x4eHv8gICD/RERE/0xMTP8rKyv/ICAg/zExMf+QkJD/qKio/xoaGv8cHBz/HBwc/x4eHv8gICD/LS0t/x8fH/8fHx//LS0t/3l5ef9qamr/SkpK/yQkJP8oKSj/kZGQ/6ysrP8bGxv/HBwc/x0dHf8cHBz/Hx8f/yAgIP8hISH/NTY2/4OFhf+Xl5f/ampq/2JiYv8zNDL/Jycn/5OTk/+wsLD/Gxsb/xwcHP8dHR3/HR0d/x4eHv8hISH/RUVF/6Ghof/BwcH/tLS0/21ubP9FRkX/TU1N/yoqKv+VlZX/s7Oz/xwcHP8dHR3/HR0d/x0dHf8fHx//Pj4+/66urv/CwsL/ycnJ/7Gxsf89PT3/Nzc3/1tbW/89PT3/eXl5/7e3t/8cHBz/HR0d/x8fH/8fHx//JiYm/4qKiv/MzMz/w8PD/8rKyv+mpqb/QEBA/zs7O/9hYWH/VlZW/1tbW/+5ubn/HBwc/x0dHf8eHh7/ICAg/y0uLv/FxcX/1dXV/9XV1f/W1tb/1NTU/7Ozs/+Kior/bGxs/2JiYv9OTk3/t7e3/xwcHP8cHBz/HR0d/x8fH/8jJCT/ampp/8rKyv+Xl5b/i4yK/87Ozv/Dw8P/dnZ2/2hoaP9qamr/Q0ND/7e3t/8dHR3/Hh4e/x4eHv8fHx//KSkp/yoqKv9aWlr/dnZ2/4WFhf+np6f/iYmJ/y0tLf9LS0v/Y2Nj/1JSUv+/v7//MzQ0/zExMf8vLy//MzMz/6SkpP86Ojr/Jycn/3Nzc/+3t7b/r6+v/8zMzP9FRUX/MDAw/ysrK/9dXV3/v7+//0hJSf9FRUX/QkND/21ubv9nZ2f/RERE/yIiIv8nJyf/NDQ0/2tra/+en5//Ly8v/yMjI/8qKir/lJSU/729vf9ERUX/QENC/z4/P/9fYGD/V1dX/2lpaf8kJCT/Hx8f/yMjI/8pKSn/LCws/yIiIv8lJSX/Wlpa/66urv+6urr/MzMz/zExMf8uLi7/RkZG/15eXv8yMjL/KSkp/yoqKv8uLi7/KSkp/ycnJ/88Pj3/MjIy/2hoaP+mpqb/sLCw/yEhIf8gICD/Hx8f/x4eHv8dHR3/NjY2/yYmJv8cHBz/Hx8f/ycnJ/8mJib/aWpp/z4+Pv9tbW3/np6e/6Wlpf8vLy//MzQ0/y8vL/80NTX/MDAw/zU1Nf8gICD/Ghoa/xoaGv8aGhr/Kysr/0dHR/9BQUH/a2tr/5WUlf+bm5v/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='
#设置窗口图标
tmp = open("tmp.ico","wb+")
tmp.write(base64.b64decode(img))
tmp.close()
root.iconbitmap("tmp.ico")
os.remove("tmp.ico")
- 视频输入与保存位置,分别包含一个标签、一个文本输入框与一个按钮,通过place绝对定位将控件放到指定位置。
#选择输入视频:
tip1=Label(root, text='请选择输入视频(必填!): ',font = ('楷体',25),bg='#CCCEC4',bd=0)
tip1.place(relx=0.1,rely=0.10,anchor=W)
#视频地址输入框
input_vedio_address= Entry(root,bg='#C4C7C5')
input_vedio_address.place(width=420,height=38,relx=0.1,rely=0.159,anchor=W)#选择保存地址:
tip2=Label(root, text='请选择保存位置(必填!): ',font = ('楷体',25),bg='#CCCEC4',bd=0)
tip2.place(relx=0.1,rely=0.24,anchor=W)
#保存地址输入框
input_save_address= Entry(root,bg='#C4C7C5')
input_save_address.place(width=420,height=38,relx=0.1,rely=0.30,anchor=W)# “浏览文件夹”按钮
browse_folder_button = Button(root, text='浏览',font = ('楷体',15),bg="#C4C7C5",command=lambda :thread_it(browse_folder1))
browse_folder_button.place(relx=0.73,rely=0.159,anchor="w")# “浏览文件夹”按钮
browse_folder_button = Button(root, text='浏览',font = ('楷体',15),bg='#C4C7C5',command=lambda :thread_it(browse_folder2))
browse_folder_button.place(relx=0.73,rely=0.30,anchor="w")
- 选择颜色模式为radiobutton单选按钮,选择缩放比例为一个滑动刻度条,可以通过颜色模式选择ASCII码是否上色,缩放比例可以有效减少运行时间与提高视频可观赏性
#选择颜色模式
tip3=Label(root, text='请选择颜色模式 ',font = ('楷体',25),bg='#CCCEC4',bd=0)
tip3.place(width=500,relx=0.1,rely=0.385,anchor=W)
v=IntVar()
v.set(1)
radiobutton=Radiobutton(root,text='彩色',font = ('楷体',18),variable=v,value=1,bg='#CCCEC4')
radiobutton.place(relx=0.55,rely=0.385,anchor=W)
radiobutton=Radiobutton(root,text='黑白',font = ('楷体',18),variable=v,value=2,bg='#CCCEC4')
radiobutton.place(relx=0.65,rely=0.385,anchor=W)#选择缩放比例
s=IntVar()
s.set(100)
scale=Scale(root, from_=0, to_=100, tickinterval=10, orient='horizontal',sliderrelief=RIDGE,bg='#CCCEC4',troughcolor='#D5CDC6',bd=0,resolution=10, variable=s,showvalue=False,length=500,borderwidth=0,label='请选择缩放比例!!!!!!数值越大越接近原视频,耗时更长;1080p(60~80),720p及以下(100)')
scale.place(relx=0.1,rely=0.49,anchor=W)
- 程序运行通过一个滚动文本框输出,点击开始转换按钮程序开始运行
# “开始转换”按钮
browse_folder_button = Button(root, text='开始转换',font = ('楷体',15),bg='#C4C7C5',command=lambda :thread_it(run))
browse_folder_button.place(width=100,height=40,relx=0.75,rely=0.71,anchor="nw")# ScrolledText组件(滚动文本框)
stext = ScrolledText(root, width=65, height=23, bg='#C4C7C5')
stext.place(width=420,height=300,relx=0.1,rely=0.58,anchor="nw")
功能实现
程序开始运行
- 点击开始转换之后,首先或许视频输入地址、保存位置、颜色模式、缩放比例四个变量
def run():INPUT=input_vedio_address.get()OUTPUT=input_save_address.get()color_radio=v.get()scale_scale=s.get()
视频提取帧图片
- 将视频每一帧提取出来保存为jpg格式,运行时将图片存放在Cache缓存文件夹,程序运行结束后自动删除
def video2txt_jpg(file_name,color_radio,scale_scale):vc = cv2.VideoCapture(file_name)c=1if vc.isOpened():r,frame = vc.read()if not os.path.exists('Cache'):os.mkdir('Cache')os.chdir('Cache')else:r = Falsewhile r:cv2.imwrite(str(c)+'.jpg',frame)txt2image(str(c)+'.jpg',color_radio,scale_scale)#同时转换为ascii图r,frame = vc.read()c += 1os.chdir('..')return vc
图片转换为ASCII形式
- 该功能实现主要根据像素点的rgb值对应一个ASCII代码,不同的颜色值对应不同的ASCII码。不同ASCII码组合起来就能形成一幅画面。我们还可以调整颜色模式与缩放比例来改善
图片合成视频
- 将图片合成视频后删除缓存文件夹即可,利用一个for循环遍历所有jpg格式图片,将所有图片作为帧加入视频中,最后生成avi格式的视频文件
def jpg2video(outfile_name,fps):fourcc = VideoWriter_fourcc(*"MJPG")images = os.listdir('Cache')im = Image.open('Cache/'+images[0])if(os.path.exists(outfile_name+'avi')):os.remove(outfile_name+'avi')vw = cv2.VideoWriter(outfile_name+'.avi',fourcc,fps,im.size)os.chdir('Cache')for image in range(len(images)):#Image.open(str(image)+'.jpg').convert("RGB").save(str(image)+'.jpg')frame = cv2.imread(str(image+1)+'.jpg')vw.write(frame)stext.insert(END,str(image+1)+'.jpg'+' finished\n')stext.see(END)os.chdir('..')vw.release()
提取音频与合成音频
- 调用ffmpeg提取音频文件并与avi格式文件合成音频生成mp4文件,删除mp3文件与avi文件
打包为exe形式
- 使用pyinstaller将程序打包为exe文件格式
pyinstaller -F gudu12306 -i 1.ico -w --clean
源代码
from tkinter import *
import tkinter.messagebox
import base64
from tkinter import filedialog
from tkinter.scrolledtext import ScrolledText
import threading
import time
import os
import cv2
import subprocess
from cv2 import VideoWriter,VideoWriter_fourcc,imread,resize
from PIL import Image, ImageFont, ImageDraw ,ImageTkascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:oa+>!:+. ")
root=Tk()
root.title("欢迎关注知乎账号gudu12306")
path1=os.path.dirname(os.path.abspath(__file__))
# print(path1)
os.environ['PATH']+=os.pathsep+path1
# print(os.environ['PATH'])width=700
height=800
screenwidth=root.winfo_screenwidth()
screenheight=root.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/5)
root.geometry(alignstr)
root.resizable(0,0)img=b'AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAlJSX/KSkp/y0tLf8wMDD/NjY2/0RERP+Dg4P/Pz8//x4eHv8hISH/IiIi/x0dHf8rKyv/Ly8v/4SEhP+jo6P/HBwc/yEhIf8mJib/KCgo/yEhIf9gYWH/PT4+/x4eHv8gICD/RERE/0xMTP8rKyv/ICAg/zExMf+QkJD/qKio/xoaGv8cHBz/HBwc/x4eHv8gICD/LS0t/x8fH/8fHx//LS0t/3l5ef9qamr/SkpK/yQkJP8oKSj/kZGQ/6ysrP8bGxv/HBwc/x0dHf8cHBz/Hx8f/yAgIP8hISH/NTY2/4OFhf+Xl5f/ampq/2JiYv8zNDL/Jycn/5OTk/+wsLD/Gxsb/xwcHP8dHR3/HR0d/x4eHv8hISH/RUVF/6Ghof/BwcH/tLS0/21ubP9FRkX/TU1N/yoqKv+VlZX/s7Oz/xwcHP8dHR3/HR0d/x0dHf8fHx//Pj4+/66urv/CwsL/ycnJ/7Gxsf89PT3/Nzc3/1tbW/89PT3/eXl5/7e3t/8cHBz/HR0d/x8fH/8fHx//JiYm/4qKiv/MzMz/w8PD/8rKyv+mpqb/QEBA/zs7O/9hYWH/VlZW/1tbW/+5ubn/HBwc/x0dHf8eHh7/ICAg/y0uLv/FxcX/1dXV/9XV1f/W1tb/1NTU/7Ozs/+Kior/bGxs/2JiYv9OTk3/t7e3/xwcHP8cHBz/HR0d/x8fH/8jJCT/ampp/8rKyv+Xl5b/i4yK/87Ozv/Dw8P/dnZ2/2hoaP9qamr/Q0ND/7e3t/8dHR3/Hh4e/x4eHv8fHx//KSkp/yoqKv9aWlr/dnZ2/4WFhf+np6f/iYmJ/y0tLf9LS0v/Y2Nj/1JSUv+/v7//MzQ0/zExMf8vLy//MzMz/6SkpP86Ojr/Jycn/3Nzc/+3t7b/r6+v/8zMzP9FRUX/MDAw/ysrK/9dXV3/v7+//0hJSf9FRUX/QkND/21ubv9nZ2f/RERE/yIiIv8nJyf/NDQ0/2tra/+en5//Ly8v/yMjI/8qKir/lJSU/729vf9ERUX/QENC/z4/P/9fYGD/V1dX/2lpaf8kJCT/Hx8f/yMjI/8pKSn/LCws/yIiIv8lJSX/Wlpa/66urv+6urr/MzMz/zExMf8uLi7/RkZG/15eXv8yMjL/KSkp/yoqKv8uLi7/KSkp/ycnJ/88Pj3/MjIy/2hoaP+mpqb/sLCw/yEhIf8gICD/Hx8f/x4eHv8dHR3/NjY2/yYmJv8cHBz/Hx8f/ycnJ/8mJib/aWpp/z4+Pv9tbW3/np6e/6Wlpf8vLy//MzQ0/y8vL/80NTX/MDAw/zU1Nf8gICD/Ghoa/xoaGv8aGhr/Kysr/0dHR/9BQUH/a2tr/5WUlf+bm5v/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='
#设置窗口图标
tmp = open("tmp.ico","wb+")
tmp.write(base64.b64decode(img))
tmp.close()
root.iconbitmap("tmp.ico")
os.remove("tmp.ico")f=open('bg.txt','r')
imgdata=base64.b64decode(f.read())
tmp=open('bg.jpg','wb+')
tmp.write(imgdata)
f.close()
tmp.close()
canvas_root=tkinter.Canvas(root,width=700,height=800)
image=ImageTk.PhotoImage(Image.open('bg.jpg').resize((700,800),Image.NEAREST))
canvas_root.create_image(350,400,image=image)
canvas_root.pack()#欢迎关注知乎账号
tip0=Label(root, text='欢迎关注知乎账号gudu12306',font = ('楷体',15),bg='#CCCEC4')
tip0.place(relx=0.03,rely=0.03,anchor=W)#选择输入视频:
tip1=Label(root, text='请选择输入视频(必填!): ',font = ('楷体',25),bg='#CCCEC4',bd=0)
tip1.place(relx=0.1,rely=0.10,anchor=W)
#视频地址输入框
input_vedio_address= Entry(root,bg='#C4C7C5')
input_vedio_address.place(width=420,height=38,relx=0.1,rely=0.159,anchor=W)#选择保存地址:
tip2=Label(root, text='请选择保存位置(必填!): ',font = ('楷体',25),bg='#CCCEC4',bd=0)
tip2.place(relx=0.1,rely=0.24,anchor=W)
#保存地址输入框
input_save_address= Entry(root,bg='#C4C7C5')
input_save_address.place(width=420,height=38,relx=0.1,rely=0.30,anchor=W)#选择颜色模式
tip3=Label(root, text='请选择颜色模式 ',font = ('楷体',25),bg='#CCCEC4',bd=0)
tip3.place(width=500,relx=0.1,rely=0.385,anchor=W)
v=IntVar()
v.set(1)
radiobutton=Radiobutton(root,text='彩色',font = ('楷体',18),variable=v,value=1,bg='#CCCEC4')
radiobutton.place(relx=0.55,rely=0.385,anchor=W)
radiobutton=Radiobutton(root,text='黑白',font = ('楷体',18),variable=v,value=2,bg='#CCCEC4')
radiobutton.place(relx=0.65,rely=0.385,anchor=W)#选择缩放比例
s=IntVar()
s.set(100)
scale=Scale(root, from_=0, to_=100, tickinterval=10, orient='horizontal',sliderrelief=RIDGE,bg='#CCCEC4',troughcolor='#D5CDC6',bd=0,resolution=10, variable=s,showvalue=False,length=500,borderwidth=0,label='请选择缩放比例!!!!!!数值越大越接近原视频,耗时更长;1080p(60~80),720p及以下(100)')
scale.place(relx=0.1,rely=0.49,anchor=W)#为避免在下载时tkinter界面卡死,创建线程函数
def thread_it(func, *args):# 创建t = threading.Thread(target=func, args=args)# 守护 !!!t.setDaemon(True)# 启动t.start()#浏览本地文件夹,选择输入视频
def browse_folder1():#浏览选择本地文件夹save_address = filedialog.askopenfilename()#把获得路径,插入保存地址输入框(即插入input_vedio_address输入框)input_vedio_address.insert(0,save_address)#浏览本地文件夹,选择保存位置
def browse_folder2():#浏览选择本地文件夹save_address = filedialog.askdirectory()#把获得路径,插入保存地址输入框(即插入input_save_address输入框)input_save_address.insert(0,save_address)#将像素转换为ascii码
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)/lengthreturn ascii_char[int(gray/unit)]#将txt转换为图片
def txt2image(file_name,color_radio,scale_scale):im = Image.open(file_name).convert('RGB')im_width=im.widthim_height=im.heightim=im.resize((int(im.width/100*scale_scale),int(im.height/100*scale_scale)),Image.NEAREST)#gif拆分后的图像,需要转换,否则报错,由于gif分割后保存的是索引颜色raw_width = im.width raw_height = im.heightwidth = int(raw_width/6)height = int(raw_height/15)im = im.resize((width,height),Image.NEAREST)txt=""colors = []for i in range(height):for j in range(width):pixel = im.getpixel((j,i))if(color_radio==1):colors.append((pixel[0],pixel[1],pixel[2]))else:colors.append((0,0,0))if(len(pixel) == 4):txt += get_char(pixel[0],pixel[1],pixel[2],pixel[3])else:txt += get_char(pixel[0],pixel[1],pixel[2]) txt += '\n' colors.append((255,255,255))im_txt = Image.new("RGB",(raw_width,raw_height),(255,255,255))dr = ImageDraw.Draw(im_txt)# font = ImageFont.truetype(os.path.join("fonts","timesbi.ttf"),12)font=ImageFont.load_default().fontx=y=0#获取字体的宽高font_w,font_h=font.getsize(txt[1])font_h *= 1.37 #调整后更佳#ImageDraw为每个ascii码进行上色for i in range(len(txt)):if(txt[i]=='\n'):x+=font_hy=-font_wdr.text((y,x),txt[i], fill = colors[i])y+=font_wname = file_namestext.insert(END,name+' changed\n')stext.see(END)im_txt=im_txt.resize((im_width,im_height),Image.NEAREST)im_txt.save(name)#将视频拆分成图片
def video2txt_jpg(file_name,color_radio,scale_scale):vc = cv2.VideoCapture(file_name)c=1if vc.isOpened():r,frame = vc.read()if not os.path.exists('Cache'):os.mkdir('Cache')os.chdir('Cache')else:r = Falsewhile r:cv2.imwrite(str(c)+'.jpg',frame)txt2image(str(c)+'.jpg',color_radio,scale_scale)#同时转换为ascii图r,frame = vc.read()c += 1os.chdir('..')return vc#将图片合成视频
def jpg2video(outfile_name,fps):fourcc = VideoWriter_fourcc(*"MJPG")images = os.listdir('Cache')im = Image.open('Cache/'+images[0])if(os.path.exists(outfile_name+'avi')):os.remove(outfile_name+'avi')vw = cv2.VideoWriter(outfile_name+'.avi',fourcc,fps,im.size)os.chdir('Cache')for image in range(len(images)):#Image.open(str(image)+'.jpg').convert("RGB").save(str(image)+'.jpg')frame = cv2.imread(str(image+1)+'.jpg')vw.write(frame)stext.insert(END,str(image+1)+'.jpg'+' finished\n')stext.see(END)os.chdir('..')vw.release() #递归删除目录
def remove_dir(path):if os.path.exists(path):if os.path.isdir(path):dirs = os.listdir(path)for d in dirs:if os.path.isdir(path+'/'+d):remove_dir(path+'/'+d)elif os.path.isfile(path+'/'+d):os.remove(path+'/'+d)os.rmdir(path)returnelif os.path.isfile(path):os.remove(path)return#调用ffmpeg获取mp3音频文件
def video2mp3(file_name):outfile_name = file_name.split('.')[-2]+'.mp3'if(os.path.exists(outfile_name)):os.remove(outfile_name)p = subprocess.Popen('ffmpeg -i '+file_name+' -f mp3 '+outfile_name,shell=True)while p.poll() is None:stext.insert(END,'正在提取音频......\n')stext.see(END)time.sleep(2)if p.poll()==0:stext.insert(END,'提取音频成功!\n')stext.see(END)else:stext.insert(END,'提取音频失败!\n')stext.see(END)tkinter.messagebox.showerror(title='Fail', message='转换失败!请查找原因并重试!')#合成音频和视频文件
def video_add_mp3(file_name,mp3_file,OUTPUT):outfile_name = OUTPUT+'/'+file_name.split('.')[-2].split('/')[-1]+'-txt.mp4'if(os.path.exists(outfile_name)):os.remove(outfile_name)p = subprocess.Popen('ffmpeg -i '+file_name+' -i '+mp3_file+' -strict -2 -f mp4 '+outfile_name,shell=True)while p.poll() is None:stext.insert(END,'正在合成音频......\n')stext.see(END)time.sleep(2)if p.poll()==0:stext.insert(END,'合成音频成功!\n')stext.see(END)else:stext.insert(END,'合成音频失败!\n')stext.see(END)tkinter.messagebox.showerror(title='Fail', message='转换失败!请查找原因并重试!')if os.path.exists(outfile_name):tkinter.messagebox.showinfo(title='Success', message='转换完成!请退出程序!!!')else:tkinter.messagebox.showerror(title='Fail', message='转换失败!请查找原因并重试!')def run():INPUT=input_vedio_address.get()OUTPUT=input_save_address.get()color_radio=v.get()scale_scale=s.get()print(color_radio)vc = video2txt_jpg(INPUT,color_radio,scale_scale)FPS = vc.get(cv2.CAP_PROP_FPS)#获取帧率vc.release()jpg2video(INPUT.split('.')[-2],FPS)stext.insert(END,INPUT.split('.')[-2]+'.mp3\n')video2mp3(INPUT)video_add_mp3(INPUT.split('.')[-2]+'.avi',INPUT.split('.')[-2]+'.mp3',OUTPUT)remove_dir("Cache")os.remove(INPUT.split('.')[-2]+'.mp3')os.remove(INPUT.split('.')[-2]+'.avi')# “浏览文件夹”按钮
browse_folder_button = Button(root, text='浏览',font = ('楷体',15),bg="#C4C7C5",command=lambda :thread_it(browse_folder1))
browse_folder_button.place(relx=0.73,rely=0.159,anchor="w")# “浏览文件夹”按钮
browse_folder_button = Button(root, text='浏览',font = ('楷体',15),bg='#C4C7C5',command=lambda :thread_it(browse_folder2))
browse_folder_button.place(relx=0.73,rely=0.30,anchor="w")# “开始转换”按钮
browse_folder_button = Button(root, text='开始转换',font = ('楷体',15),bg='#C4C7C5',command=lambda :thread_it(run))
browse_folder_button.place(width=100,height=40,relx=0.75,rely=0.71,anchor="nw")# ScrolledText组件(滚动文本框)
stext = ScrolledText(root, width=65, height=23, bg='#C4C7C5')
stext.place(width=420,height=300,relx=0.1,rely=0.58,anchor="nw")root.mainloop()
github源地址
https://github.com/gudu12306/vedio_to_ASCII
用python写了一个超酷的视频转ASCII码的软件相关推荐
- 用Python写了一个上课点名系统(附源码)
今天刷到了一个这样的短视频,我寻思我是不是也可以写一个类似的上课点名程序,想法经不起等待,说写就写~ 一.准备工作 1.Tkinter Tkinter 是 python 内置的 TK GUI 工具集. ...
- 用 Python 写了一个天天酷跑(附源码)
写出来的效果图就是这样了: 下面就更新一下全部的代码吧 还是老样子先定义 import pygame,sys import random 写一下游戏配置 width = 1200 #窗口宽度 heig ...
- 用Python写了一个网易云音乐(附源码、视频教程)
今天给大家分享一个实战项目,用Python整个网易云出来,实现音乐自由!文末附本项目源码以及视频教程! 这一次,咱们来玩点花活,整个网易云出来,实现音乐自由! 环境 Python3.6.8 PyCha ...
- 拜托,有一个python画的生日蛋糕超酷的好吧~
前言: 相信大家对生日蛋糕不陌生吧! 今天给大家分享一下用代码写个生日蛋糕出来,拜托,有一个python画的生日蛋糕超酷的好吧~ 代码: import turtle as t import math ...
- python课程报告模板_用Python做一次超酷的项目进度汇报,你值得拥有
大家有没有为项目进度的汇报而发愁,到处寻找模板,发挥十二分的想象力来达到BOSS的效果,今天就结合Python来做一次炫丽的软件项目进度汇报. 项目进度的汇报关注的是项目的总体进度,项目的延迟情况,项 ...
- 用人工智能取一个超酷的名字(一)
用人工智能取一个超酷的名字(一) 在我年轻的时候,我总是讨厌别人叫我春阳.这主要是因为我觉得这个名字有点土,听起来不够有格调.但是没有办法,按照我们中国人的传统,我这辈按照族谱中的规定,第二个字是春, ...
- 一个超酷的横向多列响应式布局效果
日期:2013-1-26 来源:GBin1.com 在线演示 还记得上周介绍的一个超酷的星际争霸2视差滚动效果吧,如果你希望生成一个类似ipad效果的漂亮横向多列响应式滚动效果的话,那么你可以考虑使 ...
- python写机器人程序_用Python写的一个多线程机器人聊天程序
本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows).后来发现实现起来特别麻烦, 就想到python.听说这家伙在什么地方都能发挥作用.所以想用python来做通讯模块...所 ...
- 用 python 写了一个日记本
写一个随机任务抽取器 一.前言 二.逻辑构思 2.1 目标实现 2.2 搭建开发环境 2.3 Pyinstaller 打包 三.效果展示 3.1 初始化和添加日记 3.2 查看日记 3.3 删除日记 ...
最新文章
- Map接口及其常用方法
- Python之实现一个简易计算器
- ASP.Net ListBox DropdownList 不同条目 设置 背景色 和 字体颜色
- 获取该字符串第N次出现的位置
- 说说程序员应该知道的术语(中文+英文)
- perl 正则表达式之匹配
- python 解析pb文件_将tensorflow模型打包成PB文件及PB文件读取方式
- Dubbo 的设计思想,真优秀!
- (day04)剑指 Offer 10- II. 青蛙跳台阶问题
- mysql数据库集群版_MySQL数据库集群实战
- c语言实验报告总结通用版,大学生实训心得体会(通用11篇)
- 从零开始学写脚本【第一天】
- Flink SQL 之 Calcite Volcano优化器(源码解析)
- Steam平台3款2D游戏开发软件对比(转)
- Tableau 网站流量分析案例之页面指标分析(一)
- 猜图达人小游戏V4.1小程序源码可开流量主
- 从零开始实现3D软光栅渲染器 (1) 简介
- 小想法 | 开源一个自己的Python小项目「Park at ease」停车场管理系统
- SwitchBox系列 - 介绍
- 新人福利——Cheat Engine功能之基础篇
热门文章
- 关于Open SSL高危漏洞整改操作 -- AIX 整改措施
- 2019.8.8 金华正睿集训总结Day12
- Linux运维常用命令汇总
- C语言计算时间差小程序
- 【原创】纳甲64卦象图
- JAVA之删除数组中某个元素值
- Ubuntu系统下网络连接不上的问题!!!
- 新生儿物品准备最详清单
- 喵喵子的python心得2021
- mysql中对一个表的id建立了唯一索引,那么查询的select count(*) ,select count(1) ,select count(id),select count(列名)