tkinter+cv2+PIL 得到文字型视频,用文字播放视频,python有意思的小工具

将图片的每个点转为文字

1,选择视频展示:


2,最终效果展示:

import cv2                               # cv2用于将视频按帧导出(pip install opencv-python)
import tkinter as tk
from tkinter import filedialog
from tkinter import simpledialog
import tkinter.colorchooser
import ttkbootstrap as ttk               # tkinter部分,主模块/选择文件模块/获取输入模块/调色盘/美化界面(主要是美化按钮,完全可以不用,后面程序略微有变化)
from PIL import Image                    # 将图片转化为文字的核心模块,cv2也可以做到,pil更方便
import time
import os
from os import listdir                   # python内置模块 这里用来建立/读取文件夹


video_name = None                        # 全局变量:所选择的视频名称
txt_s = []                               # 全局变量:最后用来展示的所有的文字
count = 0
count_ed = 0                             # 计数:已经循环次数
ida = None                               # 全局变量:tkinter的循环使用after_cancel结束,需要一个id
c_name = None                            # 全局变量:新建文件夹的名称,为避免重复,后面使用time.time()作为名称
times = 0                                # 计数:已经循环次数
per_frame = 25                           # 帧率

# 可更改的变量 分别是:帧数比例,即原视频多少帧截取1次,默认2,不能小于1,帧比过大,最后的视频不流畅,帧比过小,会使得裁取很多图,耗时间耗内存
# 最后的播放速度
# 展示出来的前景色
# 展示出来的背景色
freq = 2
speed = 1
tag_fg = "#000026"
tag_bg = "#ff770f"

# # # 1111111111111111111111111111111111111111111111111111111111111111111111111111
# 这里是4个函数,列在主界面的菜单栏,用于更改上述4个变量


def change_freq():
    global freq
    input_s = simpledialog.askstring("帧比", "输入2-10整数")
    if input_s:                     # 直接关闭输入框,没有输入值会报错,加上这里就不会
        q = eval(input_s)
        if type(q) == int:          # 如果没有这个条件,那么不管输入的什么值,都会改变帧比,如果是文字就会出错。  加上此甄别可避免
            freq = q


def change_speed():
    global speed
    input_s = simpledialog.askstring("倍速", "输入2(只支持2倍速)")
    if input_s:
        q = eval(input_s)
        if type(q) == 2:
            speed = q


def change_fg():
    global tag_fg
    color = tkinter.colorchooser.askcolor()       # 打开tkinter的调色盘
    tag_fg = str(color)[-9:-2]                    # 切片rgb


def change_bg():
    global tag_bg
    color = tkinter.colorchooser.askcolor()
    tag_bg = str(color)[-9:-2]


# # # 1111111111111111111111111111111111111111111111111111111111111111111111111111
# 这里是第一个按钮功能:即读取视频进行分帧


def cut_video():
    global video_name, c_name, times, per_frame
    video_name = filedialog.askopenfilename(title="选择一个视频进行读取", initialdir=r'D:\a', filetypes=[("", ".mp4")])
    c_name = str(time.time()).replace(".", "")
    os.mkdir("{}".format(c_name))
    if video_name:                          # 不加这个条件的话,在前面选择视频文件时,如果直接关闭,后面就会报错
        video_cap = cv2.VideoCapture(video_name)     # cv2读取视频
        frame_count = video_cap.get(7)  # 帧数计数
        per_frame = video_cap.get(5)
        while True:
            times += 1
            ret, frame = video_cap.read()
            tag1.config(text="{} 进度:{}/{}".format(video_name, times, frame_count))   # 进度值 缓解焦虑
            window1.update()                                    # 如果没有这里,会因为while的循环过快导致上一句config没反应
            if not ret:                                         # 当帧数取完时跳出循环
                break
            if times % freq == 0:                               # 当帧数/帧比为0时保存图片,说明白点就是当帧比为2时,每两帧保存一次
                cv2.imwrite("{0:}/{1:0>8}.jpg".format(c_name, times), frame)

        video_cap.release()                                     # 释放视频
        tag1.config(text="{}分帧完成".format(video_name))         # 改变标签信息 这句话少一个缩进的话即使没有选择视频也会出现
        bu2.config(text="开始读取")
        # 提示:上面的config只是为了缓解焦虑,仅供好看。但是会增加耗时


# # # 1111111111111111111111111111111111111111111111111111111111111111111111111111
# 这个是核心功能,可以 单独拿出来将图片转化为txt文档
def picture_to_txt(picture):
    img = Image.open("{}/{}".format(c_name, picture))     # 使用Image模块,打开我们刚刚新建的文件夹(里的图片)或者我们选取的文件夹
    s = "一二三中目丢丽事秉厜亀隔鄢匔鄹龖"                      # 用16个字代替灰度值为0-255的像素点,即   像素越黑   所替换的字越丰盈
    img = img.convert("L")                                # 转化为灰度图
    x, y = int(19 * img.width / 48), int(7 * img.height / 18)
    img = img.resize((x, y))                             # 将图片进行缩放,不要太大不然屏幕挤。并且文字有行间距,所以横竖缩放不一样
    pix = img.load()                                     # 加载(灰度)
    ss = ""
    for n in range(y):
        for m in range(x):
            nt = pix[m, n]
            nnt = nt // 16
            ss += s[nnt]
        ss += "\n"
    return ss

# # # 1111111111111111111111111111111111111111111111111111111111111111111111111111
# 有了所有的文字,展示即可


def end():
    global ida, count
    if ida:
        window1.after_cancel(ida)
        tag2.place_forget()
        bu4.place_forget()
        count = 0
        window1.geometry("300x200")
        ida = None


def show(per_t):
    global count, ida
    if count == len(txt_s):
        window1.after_cancel(ida)
        tag2.place_forget()
        bu4.place_forget()
        window1.geometry("300x200")
        count = 0
        ida = None
    else:
        print(count)
        tag2.config(text=txt_s[count], font=("等线", 1), bg=tag_bg, fg=tag_fg)
        window1.update()
        ida = window1.after(per_t, lambda: show(per_t))
        count += 1


def start():
    window1.geometry("1800x1000+0+0")
    bu4.place(x=50, y=600)
    tag2.place(x=0, y=0)
    per_t = int(1000 * freq / per_frame / speed)
    show(per_t)


# # # 1111111111111111111111111111111111111111111111111111111111111111111111111111
# 有了所有的图片,现在用上述的核心功能,把所有的图片转化为文字


def read_files():
    global txt_s, c_name
    images = None
    if video_name and c_name:
        images = listdir(c_name)
    else:
        images_choose = filedialog.askdirectory(title="选择文件夹")     # 如果进行了分帧就打开新件文件夹  否则直接选取文件夹
        c_name = images_choose
        if images_choose:
            images = listdir(images_choose)

    if images:
        for i in range(len(images)):
            picture_name = images[i]
            txt = picture_to_txt(picture_name)
            txt_s.append(txt)                                             # 装起来
            tag1.config(text="加载进度{}/{}".format(i+1, len(images)))
            window1.update()
        tag1.config(text="加载完成")
        time.sleep(1)
        bu3.pack(pady=5)


# # # 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
window1 = tk.Tk()
window1.geometry('300x200+0+0')
window1.attributes("-topmost", 1)
window1.title("T")
try:
    window1.iconbitmap("001.ico")
except:
    pass
window1.resizable(False, False)

tag1 = tk.Label(window1, text="{}NO FILE!{}".format(10*" ", 10*" "), font=("等线", 10))
tag1.pack(pady=5)

bu1 = ttk.Button(window1, text="视频分帧", bootstyle=('INFO', 'OUTLINE'), command=cut_video)
bu1.pack(pady=5)
bu2 = ttk.Button(window1, text="读取文件夹", bootstyle=('INFO', 'OUTLINE'), command=read_files)
bu2.pack(pady=5)
bu3 = ttk.Button(window1, text="开始播放", bootstyle=('INFO', 'OUTLINE'), command=start)
tag2 = tk.Label(window1, font=1)
bu4 = tk.Button(window1, text=" S T O P ", font=("DS-Digital", 30), command=end)

# # # 111111111111111111111111111111111111111111111111111111111111111111111111111111111111
# 菜单
meu = tk.Menu(window1)
meu_group = tk.Menu(meu)
meu.add_cascade(label="修改", menu=meu_group, font=10)
meu_group.add_command(label="【帧率比】", font=("times", 10), command=change_freq)
meu_group.add_separator()
meu_group.add_command(label="【播放速度】", font=("times", 10), command=change_speed)
meu_group.add_separator()
meu_group.add_command(label="【前景色】", font=("times", 10), command=change_fg)
meu_group.add_separator()
meu_group.add_command(label="【后景色】", font=("times", 10), command=change_bg)
window1.config(menu=meu)

window1.update()
window1.mainloop()


菜鸡分享,大佬勿喷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Tkinter播放视频,您可以使用PILPython Imaging Library)和OpenCV库。PIL用于处理图像,而OpenCV用于处理视频。 首先,确保您已安装了PIL和OpenCV库。您可以使用pip命令来安装它们: ``` pip install pillow opencv-python ``` 安装完成后,您可以使用PIL来打开视频文件,并使用OpenCV来读取和显示视频帧。下面是一个使用PIL和OpenCV在Tkinter播放视频的简单示例: ```python from PIL import Image, ImageTk import tkinter as tk import cv2 # 创建窗口 window = tk.Tk() # 打开视频文件 video = cv2.VideoCapture("video.mp4") # 获取视频的宽度和高度 width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 创建Canvas小部件 canvas = tk.Canvas(window, width=width, height=height) canvas.pack() # 读取并显示视频帧 def show_frame(): ret, frame = video.read() if ret: # 将OpenCV图像转换为PIL图像 image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # 创建Tkinter图像对象 tk_image = ImageTk.PhotoImage(image) # 在Canvas上显示图像 canvas.create_image(0, 0, anchor="nw", image=tk_image) # 循环调用show_frame函数 window.after(1, show_frame) # 开始播放视频 show_frame() # 运行窗口主循环 window.mainloop() ``` 这个示例中,我们使用OpenCV来读取视频帧,并将每一帧转换为PIL图像。然后,我们将PIL图像转换为Tkinter图像对象,并在Canvas上显示它。通过循环调用show_frame函数,我们可以不断更新视频帧,实现视频的播放效果。 请确保将示例中的 "video.mp4" 替换为您自己的视频文件路径。希望对您有帮助!如有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值