python - OpenCV视频播放:重新打开视频时不显示图像
问题描述
我在使用 Python (3.8.6) Tkinter 和 OpenCV 时遇到了一个奇怪的问题。我正在尝试循环播放视频,直到选择另一个视频。
当我第一次打开视频时,它会正常开始播放。然后当我打开另一个视频(相同的视频或其他视频)时,第一个视频停止,但第二个视频的图像不显示(它似乎在后台播放)。奇怪的是,当 tkinter 文件对话框显示打开另一个视频时,它确实显示了视频。但是当对话框被取消时,显示再次停止。
如果我手动关闭播放('p')并重新打开视频('o'),它可以正常工作。如果视频在打开新视频之前完成(没有循环播放),它也可以正常工作。
import os
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
import cv2
VIDEO_RATE = int(1000.0/30.0)
class VideoPlayback:
def __init__(self):
self.cv2Video = None
def __del__(self):
if self.cv2Video and self.cv2Video.isOpened():
self.cv2Video.release()
def openVideo(self, src, width=405, height=720):
self.cv2Video = cv2.VideoCapture(src)
if not self.cv2Video.isOpened():
raise ValueError("Unable to open video source", src)
self.resizeDim = (width,height)
def closeVideo(self):
if self.cv2Video:
self.cv2Video.release()
def readVideoFrame(self, retry=5):
if self.cv2Video and self.cv2Video.isOpened():
ret, frame = self.cv2Video.read()
if ret:
return (ret, cv2.cvtColor(cv2.resize(frame, self.resizeDim), cv2.COLOR_BGR2RGB))
else:
if retry:
self.cv2Video.set(cv2.CAP_PROP_POS_FRAMES, 0)
return self.readVideoFrame(retry=retry-1)
else:
return (False, None)
else:
return (False, None)
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self,"Minimal working example")
self.geometry("1280x740+2+2")
self.attributes("-fullscreen",True)
frTop = tk.Frame(master=self, width=1280, height=720)
frTop.pack(side='top', fill='both', expand=1)
# Playback canvas
self.cnvVideo = tk.Canvas(master=frTop, width=405, height=720)
self.cnvVideoImg = self.cnvVideo.create_image(0,0, anchor='nw')
self.cnvVideo.pack(side='right', fill='both', expand=1)
# Buttons
self.bind("o",self.openVideoPlayback)
self.bind("p",self.closeVideoPlayback)
# reference video playback
self.video = VideoPlayback()
self.afterVideo = None
def openVideoPlayback(self, *args):
# show file dialog
videoSrc = filedialog.askopenfilename(title = 'Open video', filetypes=(("Video files (*.mp4)","*.mp4"),("All files (*.*)","*.*")))
if videoSrc:
# open selected video for playback
self.video.openVideo(videoSrc, width=405, height=720)
# start update loop
self.afterVideo = self.after(VIDEO_RATE, self.updateVideoPlayback)
def updateVideoPlayback(self):
(ret, frame) = self.video.readVideoFrame()
if ret:
image = Image.fromarray(frame)
image = ImageTk.PhotoImage(image, master=self)
self.cnvVideo.itemconfig(self.cnvVideoImg, image=image)
self.cnvVideo.image = image
self.cnvVideo.after(VIDEO_RATE, self.updateVideoPlayback)
else:
print("Stop rescheduling")
def closeVideoPlayback(self, *args):
# stop video playback
if self.video:
self.video.closeVideo()
app = MainWindow()
app.mainloop()
我尝试self.video.closeVideo()
在打开新视频之前添加。我尝试self.after_cancel(self.afterVideo)
在打开新视频之前添加。
该代码是更大的 Tkinter 接口的一部分,但被剥离为最小(非)工作示例。
解决方案
推荐阅读
- altair - 如何在 Google Colab 中渲染 Vega-lite 可视化
- rest - 在主干关系模型中组合 RESTful 数据
- php - 如何通过 htaccess 将 http 请求重定向到另一个目录
- flutter - Flutter:范围值归零
- html - 引导网格 | 标签文本被包裹并占用更多空间
- javascript - 无法使用 Angular Material 分页进行分页
- python - Autokeras 多输入预测失败
- html - 如何使用硒从下拉列表中选择选项?
- c# - 我可以防止删除特定的 RSA 密钥吗?
- angular - 如何从primeng multiSelect中删除复选框?