1、为界面添加组件
这里为界面简单的添加一个PushButton
,其他不变,效果如下图。
2、编写主体函数
2.1、初始化
初始化部分主要分为两大块,一是初始化信号槽,二是初始化视频捕获函数和Qt定时器。
#使用控制播放和暂停
self.num =1
#初始化视频捕获函数
self.cap = cv2.VideoCapture()
#初始化定时器
self.timer = QtCore.QTimer(self)
#初始化信号槽
self.init_slot()
信号槽的内容如下
def init_slot(self):
#开始绑定信号和槽
#选择视频文件
self.ui.select.clicked.connect(self.open_video)
#播放视频
self.ui.begin.clicked.connect(self.play_video)
#清空
self.ui.clear.clicked.connect(self.clear)
#定时器计时结束,关联显示函数
self.timer.timeout.connect(self.show_img)
pass
2.2、选择视频文件
选择文件,做了简单的处理。
def open_video(self):
video_name=None
video_name,_ = QtWidgets.QFileDialog.getOpenFileName(self,"选择","./video/","*.mp4")
if video_name!=None:
self.video_name = video_name
else:
msg = QMessageBox.warning(self,'!','未选择文件,请重新选择!',QMessageBox.Yes)
2.3、播放视频
播放视频,详细解释看注释吧。
def play_video(self):
#关闭视频流阻塞信号
self.timer.blockSignals(False)
#第一次,定时器未激活,打开视频文件,设置定时器时间,播放标志 playing = True ,按钮设置为"暂停"
if self.timer.isActive() is False:
self.cap.open(self.video_name)
self.timer.start(30)
self.playing = True
self.change_btn_state()
#定时器已激活,视频已被读取,设置一个num标志判断视频状态是播放还是暂停
#self.num 为奇数,说明视频处于播放状态,再次点击则变为暂停状态
#那么,阻塞计时器,playing = False,num++,按钮设置为"开始"
elif self.timer.isActive() is True and self.num%2 ==1:
self.timer.blockSignals(True)
self.play = False
self.num +=1
self.change_btn_state()
#定时器已激活,视频已被读取,
#self.num 为偶数,说明视频处于暂停状态,再次点击则变为播放状态
#那么,阻塞信号为False,playing = True,num++,按钮设置为"暂停"
elif self.timer.isActive() is True and self.num%2 ==0:
self.num = self.num + 1
self.timer.blockSignals(False)
self.playing = True
self.change_btn_state()
#其他情况,报错
else:
QMessageBox.information(self, "警告", "视频播放错误!", QMessageBox.Ok)
2.4、释放资源
释放资源,关闭视频流;计时器停止,播放停止,按钮设置为"开始"。
#释放资源,关闭视频流
#计时器停止,播放停止,按钮设置为"开始"
def close_file(self):
self.cap.release()
self.timer.stop()
self.playing = False
self.change_btn_state()
2.5、展示视频帧
这里和显示图片的内容别无二致,视频的一帧也是图片。
def show_img(self):
#读取图片
#im = cv2.imread(img_name)
#获取高和宽
label = self.ui.label
ret,im = self.cap.read()
if ret:
try:
ih,iw ,_ = im.shape
#获取标签的长和高
w = label.geometry().width()
h = label.geometry().height()
#上述的目的是为了保持原始的纵横比
if iw/w >ih/h:
scal = w/iw
nw = w
nh = int(scal * ih)
im_new = cv2.resize(im,(nw,nh))
else:
scal = w/iw
nw = int(scal*iw)
nh = h
im_new = cv2.resize(im,(nw,nh))
frame = cv2.cvtColor(im_new,cv2.COLOR_BGR2RGB)
im = QImage(frame.data,frame.shape[1],frame.shape[0],frame.shape[2] * frame.shape[1],
QImage.Format_RGB888)
label.setPixmap(QPixmap.fromImage(im))
except Exception as e:
print(repr(e))
2.5、清空
清空QLabel上的内容,并释放资源
def clear(self):
self.ui.label.clear()
self.close_file()
pass
2.6、其他
这里来控制按钮的状态
def change_btn_state(self):
if self.playing:
self.ui.begin.setText("暂停")
else:
self.ui.begin.setText("开始")
2.7、完整代码
from PySide6.QtWidgets import QApplication,QMainWindow,QMessageBox
from PySide6 import QtWidgets,QtCore
from PySide6.QtGui import QImage,QPixmap
from ui.Ui_mainwin import Ui_MainWindow
import sys
import cv2
import warnings
warnings.filterwarnings('ignore')
class MainWin(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.show()
self.num =1
self.cap = cv2.VideoCapture()
self.timer = QtCore.QTimer(self)
self.init_slot()
def init_slot(self):
#开始绑定信号和槽
self.ui.select.clicked.connect(self.open_video)
self.ui.begin.clicked.connect(self.play_video)
self.ui.clear.clicked.connect(self.clear)
self.timer.timeout.connect(self.show_img)
pass
def open_video(self):
video_name=None
video_name,_ = QtWidgets.QFileDialog.getOpenFileName(self,"选择","./video/","*.mp4")
if video_name!=None:
self.video_name = video_name
else:
msg = QMessageBox.warning(self,'!','未选择文件,请重新选择!',QMessageBox.Yes)
def play_video(self):
#关闭视频流阻塞信号
self.timer.blockSignals(False)
#第一次,定时器未激活,打开视频文件,设置定时器时间,播放标志 playing = True ,按钮设置为"暂停"
if self.timer.isActive() is False:
self.cap.open(self.video_name)
self.timer.start(30)
self.playing = True
self.change_btn_state()
#定时器已激活,视频已被读取,设置一个num标志判断视频状态是播放还是暂停
#self.num 为奇数,说明视频处于播放状态,再次点击则变为暂停状态
#那么,阻塞计时器,playing = False,num++,按钮设置为"开始"
elif self.timer.isActive() is True and self.num%2 ==1:
self.timer.blockSignals(True)
self.play = False
self.num +=1
self.change_btn_state()
#定时器已激活,视频已被读取,
#self.num 为偶数,说明视频处于暂停状态,再次点击则变为播放状态
#那么,阻塞信号为False,playing = True,num++,按钮设置为"暂停"
elif self.timer.isActive() is True and self.num%2 ==0:
self.num = self.num + 1
self.timer.blockSignals(False)
self.playing = True
self.change_btn_state()
#其他情况,报错
else:
QMessageBox.information(self, "警告", "视频播放错误!", QMessageBox.Ok)
#释放资源,关闭视频流
#计时器停止,播放停止,按钮设置为"开始"
def close_file(self):
self.cap.release()
self.timer.stop()
self.playing = False
self.change_btn_state()
def change_btn_state(self):
if self.playing:
self.ui.begin.setText("暂停")
else:
self.ui.begin.setText("开始")
def show_img(self):
#读取图片
#im = cv2.imread(img_name)
#获取高和宽
label = self.ui.label
ret,im = self.cap.read()
if ret:
try:
ih,iw ,_ = im.shape
#获取标签的长和高
w = label.geometry().width()
h = label.geometry().height()
#上述的目的是为了保持原始的纵横比
if iw/w >ih/h:
scal = w/iw
nw = w
nh = int(scal * ih)
im_new = cv2.resize(im,(nw,nh))
else:
scal = w/iw
nw = int(scal*iw)
nh = h
im_new = cv2.resize(im,(nw,nh))
frame = cv2.cvtColor(im_new,cv2.COLOR_BGR2RGB)
im = QImage(frame.data,frame.shape[1],frame.shape[0],frame.shape[2] * frame.shape[1],
QImage.Format_RGB888)
label.setPixmap(QPixmap.fromImage(im))
except Exception as e:
print(repr(e))
def clear(self):
self.ui.label.clear()
self.close_file()
pass
if __name__=='__main__':
app = QApplication(sys.argv)
window = MainWin()
sys.exit(app.exec())
3、视频演示
4、相关博客
【PySide6】PySide6安装及VSCode配置PySide6环境
【PySide6】登录和注册信号绑定以及代码实现
【PySide6】实现登录界面向主界面跳转
【PySide6】在QLabel上显示一张图片