欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

opencv+tkinter录像程序

程序员文章站 2022-05-16 15:42:16
...

opencv+tkinter 实现录屏控制

环境:

  • opencv
  • python3
  • PIL (pillow)

编辑器:

  • vscode

模块导入 为了方便之后的打包,统一使用from导包

from tkinter import Label, Button, Tk, Frame, ttk, Entry, StringVar
from cv2 import VideoCapture, waitKey, VideoWriter, VideoWriter_fourcc, putText, cvtColor, destroyAllWindows
from cv2 import FONT_HERSHEY_COMPLEX_SMALL, LINE_AA, CAP_PROP_FRAME_WIDTH, CAP_PROP_FRAME_HEIGHT, COLOR_BGR2RGBA
from PIL import Image,ImageTk
from time import time, strftime, localtime
from tkinter.filedialog import askdirectory
from os.path import basename

设置全局变量

Record = False  # 默认不开启录制
StartTime = 0  # 开始录制时间,存储时间戳
filename = ''  # 用来存储录制的视频的名字
filePathChoice = False  # 文件路径是否选择
startSave = False  # 判断是否开始保存文件,用来创建保存的文件名以及开启写入的文件流对象
videoWriter = None  # 创建全局的文件流对象,用来传递
filename_ = None  # 文件名,和上面的一样,创建全局的,方便值的传递

加载视频以及保存视频

    def loadVideo():  # 加载视频以及保存视频
    global Record, StartTime, startSave, videoWriter, filename_
    ret, frame = cap.read()  # 读取摄像头的数据
    if ret:
        waitKey(1000)  # 这个不加也可以
        if Record:
            savePath = filepath.get()  # 获取文件的保存路径
            if savePath:  
                # print(filename_)
                if startSave:
                    filename_ = savePath + f"/recordSaveAs{int(time() * 1000)}" + combox.get()
                    # 这里写入
                    nameLabel.config(text=f"文件名:{basename(filename_)}")
                    print(f"创建保存的文件对象 {filename_}")
                    videoWriter = VideoWriter(filename_, VideoWriter_fourcc('I', '4', '2', '0'), FPS, SIZE)
                    startSave = False  # 更改录制的状态,不执行再次创建对象流的语句
                if videoWriter:  # 存在文件流就写入对象
                    print(f'开始循环写入:{filename_}')
                    videoWriter.write(frame)  # 保存视频
            else:  # 没有获取到文件的保存路径,就调用文件选择函数
                choicePath(None)
            # font = cv2.FONT_HERSHEY_PLAIN  # 小字体,蛮不错的
            font = FONT_HERSHEY_COMPLEX_SMALL  # 小字体,比上面那个字体显得大一点
            thisTime = calcTime(time())  # 获取计时的时间戳
            # TODO 下面两个显示提示信息,这里还可以添加人脸识别系统,检测到人脸的时候保存,没有的时候就不保存
            putText(frame, f"Is recording : {basename(filename_)}", (10, 30), font, 1, (255, 255, 187), 1, LINE_AA)
            putText(frame, f'Record Time: {thisTime}', (10, 60), font, 1, (255, 184, 99), 1, LINE_AA)
        
        cv2Image = cvtColor(frame, COLOR_BGR2RGBA)  # 转换成灰度图
        current_img = Image.fromarray(cv2Image)  # 灰度图转换成Image对象
        imgtk = ImageTk.PhotoImage(image=current_img)  # 创建可以添加到tk上面的对象

        pannel.imgtk = imgtk
        pannel.config(image=imgtk)  # 设置图像
    root.after(1, loadVideo)  # 循环函数,每1毫秒

点击按钮的事件

def StartOrStopRecord(event):  # 开始或停止的按钮
    global Record, StartTime, filePathChoice, startSave, videoWriter
    if filePathChoice:  # 如果选择过文件的路径就开始录制
        if not Record:
            Record = True  # 开始录制
            startSave = True  # 开始保存
            # videoWriter = None  # 释放这个对象
            record.config(text="点击停止录制")
            StartTime = time()  # 存储时间戳
            filend = combox.get()  # 获取多选框中的内容
            print(f'文件后缀为{filend}')
        else:
            Record = False  
            startSave = False
            videoWriter = None  # 释放文件流对象
            record.config(text="点击开始录制") 
    else:  # 没有选择路径就调用路径选择函数
        choicePath(None)

选择文件函数,还有一个计时小方法

def choicePath(event):  # TODO 选择文件的保存路径,这个窗口不咋滴好看,之后再找找好看的
    global filePathChoice
    filedirectory = askdirectory(title="选择视频保存的路径", initialdir=__file__.replace(basename(__file__), ""))
    text.set(filedirectory)  # 设置单行文本框中的内容
    filePathChoice = True

def calcTime(thisTime):  # 还有一种计算时间戳转时间的库 datetime  
    global StartTime
    diffTime = thisTime - StartTime  # 时间差
    calTime = strftime("%H:%M:%S", localtime(diffTime))  # 当前时间  # 比正常时间多8个小时,下面进行时间调整
    calTime = calTime.split(':')  # 分隔为列表
    calTime[0] = f'0{int(calTime[0]) - 8}'
    return ":".join(calTime)  # 返回时间差  时:分:秒

主函数控制区


# 控制区
FPS = 30
cap = VideoCapture(0)  # 捕获摄像头
SIZE = (int(cap.get(CAP_PROP_FRAME_WIDTH)), int(cap.get(CAP_PROP_FRAME_HEIGHT)))  # 获取摄像头捕获的画面的大小

root = Tk()  # 创建一个窗口
root.title('录屏噻!')  # 设置标题

# TODO 布局还不是很好看,组件的颜色形状啥的也不是很好
frame1 = Frame(root)  # 创建一个子组件
frame1.pack(side='top')  # 构建出来,位置为top
frame2 = Frame(root)  # 创建第二个组件
frame2.pack(side='bottom')  # 也构建出来,位置为bottom  # 说明:bottom和top表示组件独占一行,left和right表示组件独占一列
# 子组件的部件
pannel = Label(frame1, padx=10, pady=10)  # 继承于frame1组件,用来存放图像
pannel.pack()
# 录制按钮
record = Button(frame1, text="点击开始录制")  # 创建按钮对象,继承于frame1,并设置按钮的文本内容
record.pack(side='left')  # 独占一列,靠左
# 提示选择文件后缀名
tipLabel = Label(frame1, text="保存类型")   # 创建一个标签对象
tipLabel.pack(side='left')
# 显示保存的文件的名称
nameLabel = Label(frame1)
nameLabel.pack(side='left')
# 多选框
combox = ttk.Combobox(frame1, width=10)  # 创建一个复选框,设置宽度为10
combox.pack(side='right')  # 独占一列,靠右
combox['value'] = ('.avi', '.mp4')  # TODO 设置保存的文件的后缀名,opencv应该还有支持的文件后缀,再添加添加
combox.current(0)  # 选择默认的文件后缀名
# 选择文件的保存路径
filepathshow = Button(frame2, text="选择文件保存路径")
filepathshow.pack(side='left', expand=True)
# 文件路径显示
text = StringVar()
filepath = Entry(frame2, textvariable=text, width=70) 
filepath.pack(side='left') 
# print(combox.get())
# 函数循环,事件绑定
loadVideo()
record.bind("<Button-1>", StartOrStopRecord)  # 按钮绑定鼠标左键,点击运行StartOrStopRecord函数
filepathshow.bind('<Button-1>', choicePath)  # 选择文件保存路径按钮,点击运行choicePath函数
root.mainloop()  # 主循环
cap.release()  # 释放掉摄像头捕获对象
destroyAllWindows()  # 销毁所有的窗口

下载链接是蚂蚁笔记的链接

使用tkinter控制.py代码文件下载