开发实录

  • 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码的软件相关推荐

  1. 用Python写了一个上课点名系统(附源码)

    今天刷到了一个这样的短视频,我寻思我是不是也可以写一个类似的上课点名程序,想法经不起等待,说写就写~ 一.准备工作 1.Tkinter Tkinter 是 python 内置的 TK GUI 工具集. ...

  2. 用 Python 写了一个天天酷跑(附源码)

    写出来的效果图就是这样了: 下面就更新一下全部的代码吧 还是老样子先定义 import pygame,sys import random 写一下游戏配置 width = 1200 #窗口宽度 heig ...

  3. 用Python写了一个网易云音乐(附源码、视频教程)

    今天给大家分享一个实战项目,用Python整个网易云出来,实现音乐自由!文末附本项目源码以及视频教程! 这一次,咱们来玩点花活,整个网易云出来,实现音乐自由! 环境 Python3.6.8 PyCha ...

  4. 拜托,有一个python画的生日蛋糕超酷的好吧~

    前言: 相信大家对生日蛋糕不陌生吧! 今天给大家分享一下用代码写个生日蛋糕出来,拜托,有一个python画的生日蛋糕超酷的好吧~ 代码: import turtle as t import math ...

  5. python课程报告模板_用Python做一次超酷的项目进度汇报,你值得拥有

    大家有没有为项目进度的汇报而发愁,到处寻找模板,发挥十二分的想象力来达到BOSS的效果,今天就结合Python来做一次炫丽的软件项目进度汇报. 项目进度的汇报关注的是项目的总体进度,项目的延迟情况,项 ...

  6. 用人工智能取一个超酷的名字(一)

    用人工智能取一个超酷的名字(一) 在我年轻的时候,我总是讨厌别人叫我春阳.这主要是因为我觉得这个名字有点土,听起来不够有格调.但是没有办法,按照我们中国人的传统,我这辈按照族谱中的规定,第二个字是春, ...

  7. 一个超酷的横向多列响应式布局效果

    日期:2013-1-26  来源:GBin1.com 在线演示 还记得上周介绍的一个超酷的星际争霸2视差滚动效果吧,如果你希望生成一个类似ipad效果的漂亮横向多列响应式滚动效果的话,那么你可以考虑使 ...

  8. python写机器人程序_用Python写的一个多线程机器人聊天程序

    本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows).后来发现实现起来特别麻烦, 就想到python.听说这家伙在什么地方都能发挥作用.所以想用python来做通讯模块...所 ...

  9. 用 python 写了一个日记本

    写一个随机任务抽取器 一.前言 二.逻辑构思 2.1 目标实现 2.2 搭建开发环境 2.3 Pyinstaller 打包 三.效果展示 3.1 初始化和添加日记 3.2 查看日记 3.3 删除日记 ...

最新文章

  1. Map接口及其常用方法
  2. Python之实现一个简易计算器
  3. ASP.Net ListBox DropdownList 不同条目 设置 背景色 和 字体颜色
  4. 获取该字符串第N次出现的位置
  5. 说说程序员应该知道的术语(中文+英文)
  6. perl 正则表达式之匹配
  7. python 解析pb文件_将tensorflow模型打包成PB文件及PB文件读取方式
  8. Dubbo 的设计思想,真优秀!
  9. (day04)剑指 Offer 10- II. 青蛙跳台阶问题
  10. mysql数据库集群版_MySQL数据库集群实战
  11. c语言实验报告总结通用版,大学生实训心得体会(通用11篇)
  12. 从零开始学写脚本【第一天】
  13. Flink SQL 之 Calcite Volcano优化器(源码解析)
  14. Steam平台3款2D游戏开发软件对比(转)
  15. Tableau 网站流量分析案例之页面指标分析(一)
  16. 猜图达人小游戏V4.1小程序源码可开流量主
  17. 从零开始实现3D软光栅渲染器 (1) 简介
  18. 小想法 | 开源一个自己的Python小项目「Park at ease」停车场管理系统
  19. SwitchBox系列 - 介绍
  20. 新人福利——Cheat Engine功能之基础篇

热门文章

  1. 关于Open SSL高危漏洞整改操作 -- AIX 整改措施
  2. 2019.8.8 金华正睿集训总结Day12
  3. Linux运维常用命令汇总
  4. C语言计算时间差小程序
  5. 【原创】纳甲64卦象图
  6. JAVA之删除数组中某个元素值
  7. Ubuntu系统下网络连接不上的问题!!!
  8. 新生儿物品准备最详清单
  9. 喵喵子的python心得2021
  10. mysql中对一个表的id建立了唯一索引,那么查询的select count(*) ,select count(1) ,select count(id),select count(列名)