界面开发(4)--- PyQt5实现打开图像及视频播放功能

PyQt5创建打开图像及播放视频页面

上篇文章主要介绍了如何实现登录界面的账号密码注册及登录功能,还简单介绍了有关数据库的连接方法。这篇文章我们介绍一下如何在设计的页面中打开本地的图像,以及实现视频播放功能。

实现打开图像功能

为了便于记录实现细节,我们尽量一步步地来。之前的文章已经介绍过如何将新的页面与之前的页面建立连接了,这里就不再赘述,从建立新页面开始。

  1. 首先将label拖到屏幕中央,并在左侧设计成合适的宽和高,用于显示图像和视频。

在这里插入图片描述

  1. 这个label是透明的,为了方便展示,我们为它填充个黑色,呈现出一种幕布的感觉。
  • 使用鼠标右击 label 中心,点击改变样式表;
  • 点击添加颜色,background-color;
  • 选择黑色,点击ok;
  • 然后再点击Apply,最后点击ok。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  1. 之后,在下面拖入 Push Button 按钮和 Text Browser 按钮,分别用于打开本文文件,以及显示打开的路径。

在这里插入图片描述

做到这里基础界面就算完成了,将其保存,并使用PyUIC工具转化为.py文件,剩下的部分就剩编写逻辑代码了。

在显示图像方面,我们主要的思想就是通过点击“打开文件”按钮,来选取本地库中的图像,并把路径显示到文本框中。self.image的取值用来判断选取的不是图像的情况。核心代码如下:

class Image_open(QMainWindow, image.Ui_MainWindow):
    def __init__(self, parent=None):
        super(Image_open, self).__init__(parent)
        # UI界面
        self.setupUi(self)
        self.pushButton.clicked.connect(self.open_image)
        
	def open_image(self):
		self.image = None
		# 获取图像的路径
        self.img_path = QFileDialog.getOpenFileName()[0]
        # 将路径存储到对话框中
        self.textBrowser.setText(self.img_path)
        # 可选的图像格式
        img_type = [".bmp", ".jpg", ".png", ".gif"]
        for ig in img_type:
            if ig not in self.img_path:
                continue
            else:
            	self.image = True
            	# 如果是图像文件名的话,读取图像
                img = QPixmap(self.img_path)
                # 获取图像的宽和高
                w = img.width()
                h = img.height()
                # 根据图像与label的比例,最大化图像在label中的显示
                ratio = max(w / self.label.width(), h / self.label.height())
                img.setDevicePixelRatio(ratio)
                # 图像在label中居中显示
                self.label.setAlignment(Qt.AlignCenter)
                self.label.setPixmap(img)
        if self.image is None:
            QMessageBox.information(self, "警告", "我们暂时不支持此格式的文件!", QMessageBox.Ok)

上面单独介绍了打开图像的代码,是为了方便阅读和理解。

而视频播放和打开图像的部分代码是可以共同使用的,因此下面的视频播放也会将打开图像的代码进行介绍。

实现视频播放功能

为了实现视频播放,暂停和关闭功能,我们额外增加了两个 Push Button 按钮,其中左边的那个按钮要实现本地视频的播放与暂停,右边的按钮用于实现视频的关闭。

在这里插入图片描述

接下来是逻辑代码部分。

可以发现我们的两个按钮上面并没有写汉字,这是为了我们在逻辑代码中给他加入标准图标。第一个按钮是播放的图标,第二个按钮是关闭的图标。

为了方便展示,我们把这些连接的设置都放在一个函数里。

 def background(self):
 		# 文件选择按钮
        self.pushButton.clicked.connect(self.open_image)
        # 视频播放图标
        self.pushButton_2.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))  # 播放图标
        self.pushButton_3.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))  # 停止图标
        
        # 用于开始播放视频的按钮
        self.pushButton_2.clicked.connect(self.play_file) # 这是对应的函数
        # 用于关闭播放视频的按钮
        self.pushButton_3.clicked.connect(self.close_file) # 这是对应的函数
        
		# 当播放的为图像时,设计这两个按钮不能点击,只有当播放的是视频时,才能点击
        self.pushButton_2.setEnabled(False)
        self.pushButton_3.setEnabled(False

重复上面的判断文件类型函数,这里我们考虑了视频及图像。

当所选文件为视频时,将播放按钮置为可使用。

def pre_judge(self):
   # 创建文件对话框,如果是视频,令self.video = True,如果是图像,令self.video = False,
   # 当self.video = None时,报错。
    self.video = None
    self.img_path = QFileDialog.getOpenFileName()[0]
    self.textBrowser.setText(self.img_path)
    video_type = [".mp4", ".mkv", ".MOV", "avi"]
    img_type = [".bmp", ".jpg", ".png", ".gif"]
    for vdi in video_type:
        if vdi not in self.img_path:
            continue
        else:
            self.video = True
            # 当是视频时,将开始按钮置为可点击状态
            self.pushButton_2.setEnabled(True)
    for ig in img_type:
        if ig not in self.img_path:
            continue
        else:
            self.video = False
            img = QPixmap(self.img_path)
            w = img.width()
            h = img.height()
            ratio = max(w / self.label.width(), h / self.label.height())
            img.setDevicePixelRatio(ratio)
            self.label.setAlignment(Qt.AlignCenter)
            self.label.setPixmap(img)
    if self.video is None:
        QMessageBox.information(self, "警告", "我们暂时不支持此格式的文件!", QMessageBox.Ok)

这里介绍如何播放视频,这里是整个的重点,也是难点。

播放视频,主要是使用其中的 QTimer 计时器,如果计时器被激活,就每隔一段时间读取一个视频帧,并显示。

我们根据计时器是否激活,是否被阻塞,将开始播放按钮置为暂停或播放,主要由 self.playing 参数控制。

self.timer.isActive() 用来判断是否有视频流,用于开始播放视频

self.timer.blockSignals(True) 用于暂停视频流。

self.timer.blockSignals(False) 用于重新播放视频流。

import sys
from PyQt5.QtWidgets import QMessageBox, QFileDialog, QLineEdit
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import mainwindow, image
import cv2
import sqlite3

### 主页面设计,略
class MainWindow(QMainWindow, mainwindow.Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.image_open = Image_open()
        self.pushButton.clicked.connect(self.image_open.show)
### 未详细说明,请参考前三篇博客
        
class Image_open(QMainWindow, image.Ui_MainWindow):
    def __init__(self, parent=None):
        super(Image_open, self).__init__(parent)
        # UI界面
        self.setupUi(self)
        self.background()
        self.cap = cv2.VideoCapture()
        self.num = 1
        self.playing = False
        # 在label中播放视频
        self.init_timer()
        
	def background(self):
 		# 文件选择按钮
        self.pushButton.clicked.connect(self.pre_judge)
        # 视频播放图标
        self.pushButton_2.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))  # 播放图标
        self.pushButton_3.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))  # 停止图标
        
        # 用于开始播放视频的按钮
        self.pushButton_2.clicked.connect(self.play_file) # 这是对应的函数
        # 用于关闭播放视频的按钮
        self.pushButton_3.clicked.connect(self.close_file) # 这是对应的函数
        
		# 当播放的为图像时,设计这两个按钮不能点击,只有当播放的是视频时,才能点击
        self.pushButton_2.setEnabled(False)
        self.pushButton_3.setEnabled(Falsedef pre_judge(self):
	   	# 创建文件对话框,如果是视频,令self.video = True,如果是图像,令self.video = False,
	  	# 当self.video = None时,报错。
	    self.video = None
	    self.img_path = QFileDialog.getOpenFileName()[0]
	    self.textBrowser.setText(self.img_path)
	    video_type = [".mp4", ".mkv", ".MOV", "avi"]
	    img_type = [".bmp", ".jpg", ".png", ".gif"]
	    for vdi in video_type:
	        if vdi not in self.img_path:
	            continue
	        else:
	            self.video = True
	            # 当是视频时,将开始按钮置为可点击状态
	            self.pushButton_2.setEnabled(True)
	    for ig in img_type:
	        if ig not in self.img_path:
	            continue
	        else:
	            self.video = False
	            img = QPixmap(self.img_path)
	            w = img.width()
	            h = img.height()
	            ratio = max(w / self.label.width(), h / self.label.height())
	            img.setDevicePixelRatio(ratio)
	            self.label.setAlignment(Qt.AlignCenter)
	            self.label.setPixmap(img)
	    if self.video is None:
	        QMessageBox.information(self, "警告", "我们暂时不支持此格式的文件!", QMessageBox.Ok)
	        
 	# 打开本地视频文件
    def play_file(self):
        self.label.setEnabled(True)
        # 如果播放视频,则使得关闭视频按钮可用
        self.pushButton_3.setEnabled(True)
        # 视频流阻塞信号关闭
        self.timer.blockSignals(False)
        # 如果计时器没激活,证明是暂停阶段,需要重新播放,并把self.playing = True。
        if self.timer.isActive() is False:
            self.cap.open(self.img_path)
            self.timer.start(30)
            self.playing = True
            # 更换播放按钮为暂停按钮
            self.set_state()
        # 如果计时器激活了,并且num为奇数,证明是播放阶段,需要暂停播放,并把self.playing = False。
        elif self.timer.isActive() is True and self.num % 2 == 1:
            self.timer.blockSignals(True)
            self.playing = False
            self.num = self.num + 1
            self.set_state()
        # 如果计时器激活了,并且num为偶数,证明经过播放阶段,现在是暂停阶段,需要重新开始播放,并把self.playing = True。
        elif self.timer.isActive() is True and self.num % 2 == 0:
            self.num = self.num + 1
            self.timer.blockSignals(False)
            self.playing = True
            self.set_state()
        else:
            QMessageBox.information(self, "警告", "视频播放错误!", QMessageBox.Ok)

    # 关闭本地视频
    def close_file(self):
        self.cap.release()
        self.pushButton_2.setEnabled(True)
        self.pushButton_3.setEnabled(False)
        self.timer.stop()
        self.playing = False
        # 关闭视频将按钮置为可以播放
        self.set_state()

    # 本地视频播放暂停转换图标按钮
    def set_state(self):
        if self.playing:
        	# 暂停图标
            self.pushButton_2.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))

        else:
            self.pushButton_2.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
  
    # 播放视频画面
    def init_timer(self):
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.show_pic)

    # 显示视频图像
    def show_pic(self):
        ret, img = self.cap.read()
        if ret:
            cur_frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            # 视频流的长和宽
            height, width = cur_frame.shape[:2]
            pixmap = QImage(cur_frame, width, height, QImage.Format_RGB888)
            pixmap = QPixmap.fromImage(pixmap)
            # 获取是视频流和label窗口的长宽比值的最大值,适应label窗口播放,不然显示不全
            ratio = max(width/self.label.width(), height/self.label.height())
            pixmap.setDevicePixelRatio(ratio)
            # 视频流置于label中间部分播放
            self.label.setAlignment(Qt.AlignCenter)
            self.label.setPixmap(pixmap)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())

完成出来的结果大概就是这样的!

在这里插入图片描述
日常学习记录,一起交流讨论吧!侵权联系~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/784.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OCPC系列 - OCPC介绍扫盲贴来啦

本文对oCPC做个介绍,它是一种智能投放模式,系统通过对广告主转化数据的对接和深度理解,实时预估每一次点击的转化率并基于竞争环境智能出价,通过强化高转化率曝光机会的获取,弱化低转化率曝光机会的展现,以…

力扣-进店却未进行过交易的顾客

大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:1581. 进店却未进行过交易的顾客二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行…

文心一言正式对标GPT-4,是青铜还是王者?

昨天,OpenAI正式发布GPT-4模型 号称史上最先进的AI系统 今天,百度文心一言在万众瞩目中闪亮登场 这款产品被视为中国版ChatGPT 在这一个多月内备受关注 文心一言某种程度上具有了对人类意图的理解能力 回答的准确性、逻辑性、流畅性都逐渐接近人类…

Go 微服务开发框架 DMicro 的设计思路

Go 微服务开发框架 DMicro 的设计思路 DMicro 源码地址: Gitee:dmicro: dmicro是一个高效、可扩展且简单易用的微服务框架。包含drpc,dserver等 背景 DMicro 诞生的背景,是因为我写了 10 来年的 PHP,想在公司内部推广 Go, 公司内部的组件及 rpc 协议都…

多模态特征融合:图像、语音、文本如何转为特征向量并进行分类

多模态特征融合前言输入层,数据集转为特征向量图像语音什么是时域信号,什么是频域信号语音信号转换 - 1.傅立叶变换语音信号转换 - 2.梅尔频率倒谱系数文本词袋模型词嵌入模型输出层,多模态模型合并前言 学习多模态的话题可以从深度学习的分…

【YOLOv8/YOLOv7/YOLOv5/YOLOv4/Faster-rcnn系列算法改进NO.57】引入可形变卷积

文章目录前言一、解决问题二、基本原理三、​添加方法四、总结前言 作为当前先进的深度学习目标检测算法YOLOv8,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列…

[JS与链表]普通链表

为什么要用链表要储存一系列数据,最常用的数据结构是数组。数组有个缺点就是在中间插入或删除元素需要移动元素,成本很高。什么是链表链表也是有序元素的集合结构。链表中的元素在内存中并不是连续放置的。每个元素都可以理解为一个对象。包含了本身元素…

简单了解JSP

JSP概念与原理概念: Java Server Pages,Java服务端页面一种动态的网页技术,其中既可以定义 HTML、JS、CSS等静态内容,还可以定义Java代码的动态内容JSP HTML Java, 用于简化开发JSP的本质上就是一个ServletJSP 在被访问时,由JSP容…

博途PLC开放式以太网通信TRCV_C指令应用编程(运动传感器UDP通信)

博途PLC开放式以太网通信TSENG_C指令应用,请参看下面的文章链接: 博途PLC 1200/1500PLC开放式以太网通信TSEND_C通信(UDP)_plc的udp通信_RXXW_Dor的博客-CSDN博客开放式TSEND_C通信支持TCP 、UDP等,关于TSEND_C的TCP通信可以参看下面这篇文章:博途PLC 1200/1500PLC开放式…

opencv识别车道线(霍夫线变换)

目录1、前言2、霍夫线变换2.1、霍夫线变换是什么?2.2、在opencv中的基本用法2.2.1、HoughLinesP函数定义2.2.2、用法3、识别车道3.1、优化3.1.1、降噪3.1.2、过滤方向3.1.3、截选区域3.2、测试其它图片3.2.1、代码3.2.2、图片13.2.3、图片23.2.4、图片31、前言 最近…

C++模拟实现红黑树

目录 介绍----什么是红黑树 甲鱼的臀部----规定 分析思考 绘图解析代码实现 节点部分 插入部分分步解析 ●父亲在祖父的左,叔叔在祖父的右: ●父亲在祖父的右,叔叔在祖父的左: 测试部分 整体代码 介绍----什么是红黑树 红…

2023年江苏省职业院校技能大赛中职网络安全赛项试卷-教师组任务书

2023年江苏省职业院校技能大赛中职网络安全赛项试卷-教师组任务书 一、竞赛时间 9:00-12:00,12:00-15:00,15:00-17:00共计8小时。 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段 基础设施设置与安全加固、网络安全事件响应、数…

链表相关oj题

1.Leetcode203 移除链表元素 解题思路:从头节点开始进行元素删除,每删除一个元素,需要重新链接节点 struct ListNode* removeElements(struct ListNode* head, int val){struct ListNode*dummyheadmalloc(sizeof(struct ListNode));dummyhea…

spring5(四):IOC 操作 Bean 管理(基于注解方式)

IOC操作Bean管理(基于xml方式)前言一、注解1、概述二、入门案例1、Bean 的创建2、Bean的自动装配2.1 Autowired2、Qualifie3、Resource4、Value3、扫描组件3.1 配置文件版3.2 注解版4、测试前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心…

Mysql常用命令

mysql连接: [roothost]# mysql -u root -p Enter password:******创建数据库: CREATE DATABASE 数据库名; 删除数据库: drop database 数据库名; 使用mysqladmin删除数据库: [roothost]# mysqladmin -u root -p dr…

【数据结构】链表OJ(二)

Yan-英杰的博客 悟已往之不谏 知来者之可追 目录 一、反转链表 二、合并两个有序链表 三、链表分割 四、链表的回文结构 一、反转链表 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 输入:head [1,2] 输出:[2,1] 示例 3&#xf…

Vulnhub靶场----10、LazySysadmin

文章目录一、环境搭建二、渗透流程一、环境搭建 DC-7下载地址:https://download.vulnhub.com/dc/DC-9.zip kali:192.168.144.148 DC-9:192.168.144.157 二、渗透流程 1、信息收集nmap -sV -sT -p- -T4 192.168.144.157思路: 1、80…

基于vivado(语言Verilog)的FPGA学习(3)——FPGA理论知识

基于vivado(语言Verilog)的FPGA学习(3)——FPGA理论知识 文章目录基于vivado(语言Verilog)的FPGA学习(3)——FPGA理论知识1. FPGA介绍1.1.FPGA内部结构(1). 可…

【云原生|Docker】01-docker简介

目录 前言 Docker简介 1. 什么是docker 2. Docker和vm有什么区别 3. Docker架构 4. Docker特性 Docker安装 1. Docker版本介绍 2. Centos7安装docker 3. Docker校验 4. Docker启动 5. Docker配置文件 前言 接下来准备记录云原生系列的相关知识&#x…

Linux防火墙的关闭

查看防火墙的状态打开终端输入如下命令systemctl status firewalld如图所示:running表示防火墙目前处于打开状态输入命令进行关闭防火墙:systemctl stop firewalld如图所示正常的用户是没有权限的,需要输入管理员的密码才能够进行关闭防火墙。…