首页 > 解决方案 > tkinter 视频的闪烁视频

问题描述

我正在尝试在 tkinter 中制作一个简单的播放/暂停应用程序。基本上我想显示一个视频并在下面有一个播放/暂停按钮。

因此,经过一些研究,我发现这篇适合使用 tkinter 和 opencv 显示视频的帖子: 在 tkinter 中显示帧内的视频流

使用已接受答案中给出的代码显示视频时,没有问题,我看不到任何闪烁。这是代码:

# import the necessary packages
from __future__ import print_function
import tkinter as tk
from PIL import ImageTk, Image
import cv2


root = tk.Tk()
# Create a frame
app = tk.Frame(root, bg="white")
app.grid()
# Create a label in the frame
lmain = tk.Label(app)
lmain.grid()

# Capture from camera
cap = cv2.VideoCapture(r'PATH_TO_VIDEO_FILE')

# function for video streaming
frame_number = 0
def video_stream(): 
    global frame_number
    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)
    success, frame = cap.read()
    cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
    img = Image.fromarray(cv2image)
    imgtk = ImageTk.PhotoImage(image=img)
    lmain.imgtk = imgtk
    lmain.configure(image=imgtk)
    lmain.after(1, video_stream) 

    frame_number += 1

video_stream()
root.mainloop()

现在,我稍微修改了代码,以便能够使用网格管理器并添加一个播放按钮:

# import the necessary packages

from __future__ import print_function
import tkinter as tk
from PIL import ImageTk, Image

import cv2


class PhotoBoothApp:
    def __init__(self, path_to_video):
        # initialize the root window
        self.window = tk.Tk()
        self.window.title("Video_Player")
        self.videocap = cv2.VideoCapture(path_to_video)
        self.frame_number = 0

        # Initalize
        self.videocap.set(cv2.CAP_PROP_POS_FRAMES, self.frame_number)
        success, self.frame = self.videocap.read()
        cv2image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGBA)
        self.img = Image.fromarray(cv2image)
        self.imgtk = ImageTk.PhotoImage(image=self.img)
        # Show frames
        self.picture_label = tk.Label(self.window, image=self.imgtk, relief=tk.RIDGE).grid(row=0, column=0)
        self.btn_next_image=tk.Button(self.window, text="Play", width=50, bg ="green",command=self.video_stream).grid(row=1,column=0)

        self.window.mainloop()





    def video_stream(self):

        self.videocap.set(cv2.CAP_PROP_POS_FRAMES, self.frame_number)
        sucess, frame = self.videocap.read()
        cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
        img = Image.fromarray(cv2image)
        self.imgtk = ImageTk.PhotoImage(image=img)
        self.picture_label = tk.Label(self.window, image=self.imgtk, relief=tk.RIDGE).grid(row=0, column=0)
        # Update Frame Number to display
        self.frame_number = self.frame_number + 1
        self.window.after(1, self.video_stream) 


ph = PhotoBoothApp(r'PATH_TO_FILE')

问题是当我执行上面的代码时,视频会闪烁,好像 tkinter 需要在帧之间重新加载一些东西。我不知道为什么会这样。

PS This post here Flickering video in opencv-tkinter integration对我没有帮助。

标签: python-3.xopencvtkinter

解决方案


您需要进行两项更改:拆分self.picture_label线以创建对Label对象的正确引用,然后用于self.picure_label.config(...)更改图像。

class PhotoBoothApp:
    def __init__(self, path_to_video):
        # initialize the root window
        ...
        self.picture_label = tk.Label(self.window, image=self.imgtk, relief=tk.RIDGE)
        self.picture_label.grid(row=0, column=0)
        ...

    def video_stream(self):
        ...
        img = Image.fromarray(cv2image)
        self.imgtk = ImageTk.PhotoImage(image=img)
        self.picture_label.config(image=self.imgtk)
        # Update Frame Number to display
        self.frame_number = self.frame_number + 1
        self.window.after(1, self.video_stream)

ph = PhotoBoothApp(r'PATH_TO_FILE')

推荐阅读