OpenCV-PyQT项目实战(11)项目案例07:摄像头操作与拍摄视频
创始人
2024-06-03 14:36:20
0

欢迎关注『OpenCV-PyQT项目实战 @ Youcans』系列,持续更新中
OpenCV-PyQT项目实战(1)安装与环境配置
OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门
OpenCV-PyQT项目实战(3)信号与槽机制
OpenCV-PyQT项目实战(4)OpenCV 与PyQt的图像转换
OpenCV-PyQT项目实战(5)项目案例01:图像模糊
OpenCV-PyQT项目实战(6)项目案例02:滚动条应用
OpenCV-PyQT项目实战(7)项目案例03:鼠标框选
OpenCV-PyQT项目实战(8)项目案例04:鼠标定位
OpenCV-PyQT项目实战(9)项目案例04:视频播放
OpenCV-PyQT项目实战(10)项目案例06:键盘事件与视频抓拍
OpenCV-PyQT项目实战(11)项目案例07:摄像头操作与拍摄视频
OpenCV-PyQT项目实战(12)项目案例08:多线程视频处理

文章目录

  • OpenCV-PyQT项目实战(11)项目案例07:实时拍摄视频
    • 1. 用OpenCV获取视频流
      • 1.1 OpenCV的VideoCapture类
      • 1.2 OpenCV拍摄视频例程
    • 2. 用PyQt5显示OpenCV拍摄的视频流
      • 2.1 用 QtDesigner 开发 PyQt5 图形界面
      • 2.2 用 QTime 定时器实现视频播放
      • 2.3 摄像头的打开与关闭控制
      • 2.4 摄像画面的移动控制
    • 3. 项目实战:PyQt 视频拍摄与摄像头控制
      • 3.1 UI 程序 uiDemo12.py
      • 3.2 主程序:视频拍摄与控制
      • 3.3 程序说明和运行结果

OpenCV-PyQT项目实战(11)项目案例07:实时拍摄视频

在上一个案例中我们介绍了OpenCV和PyQt 实现视频播放,本节介绍摄像头操作与拍摄实时视频。

本例使用 OpenCV处理摄像头设备进行解码获得图像帧,然后用 QTime 定时器控制 QLabel 中的图像更新,使用按钮控制摄像画面的移动。


1. 用OpenCV获取视频流

1.1 OpenCV的VideoCapture类

OpenCV提供了VideoCapture类和VideoWriter类处理视频流,既可以处理视频文件,也可以处理摄像头设备。

函数原型:

cv.VideoCapture( index[, apiPreference] ) →
cv.VideoWriter([filename, fourcc, fps, frameSize[, isColor]]) →

VideoCapture类用于读取视频文件、视频流或从摄像机捕获视频,VideoWriter类用于视频文件的写入和保存。

构造函数cv.VideoCapture和cv.VideoWrite用于实现类的初始化。

参数说明:

  • index:摄像头的 ID 编号,0 表示默认后端打开默认摄像机
  • filename:读取或保存的视频文件的路径,包括扩展名
  • apiPreference:读取视频流的属性设置
  • fourcc:用于压缩帧的编码器/解码器的字符代码,
    • CV_FOURCC(‘I’,‘4’,‘2’,‘0’),未压缩的YUV编码格式,扩展名为 .avi
    • CV_FOURCC(‘P’,‘I’,‘M’,‘1’),MPEG-1 编码格式,扩展名为 .avi
    • CV_FOURCC( ‘X’,‘V’,‘I’,‘D’),MPEG-4 编码格式,扩展名为 .avi
    • CV_FOURCC( ‘F’,‘L’,‘V’,‘I’),Flash 编码格式,件扩展名为 .flv
  • fps:视频流的帧速率
  • frameSize:元组 (w, h),视频帧的宽度和高度
  • isColor:是否彩色图像

成员函数:

  • cv.VideoCapture.isOpened(),检查视频捕获是否初始化成功
  • cv.VideoCapture.read(),捕获视频文件、视频流或捕获的视频设备
  • cv.VideoCapture.release(),关闭视频文件或设备,释放对象
  • cv.VideoCapture.get(propId) ,获取 VideoCapture 类对象的属性
  • cv.VideoCapture.set(propId, value),设置 VideoCapture 类对象的属性
  • cv.VideoWriter.fourcc(c1, c2, c3, c4[, ]),构造编码器/解码器的fourcc代码
  • cv.VideoWriter.write(image[, ]),写入下一帧视频
  • cv.VideoWriter.release(),关闭视频写入,释放对象

注意问题:

⒈读取视频文件、视频流中读取时,通过 filename 传递视频文件、视频流的路径。使用摄像头时,通过 index 传递摄像头的 ID 号。
⒉使用摄像头时,index=0 表示默认后端打开默认摄像机,例如笔记本内置摄像头。可以使用计算机的内置或外接的摄像头,也支持本地网络或公共网络的 IP 摄像机。
⒊视频写入类VideoWriter的参数frameSize是元组 (w, h),即视频帧的宽度和高度,而OpenCV图像的形状是 (h, w),注意二者的顺序是反的。
⒋视频处理过程较为复杂,一些程序设置与具体系统环境有关,本文只介绍基本的成员函数,通用的处理方法。更多内容详见:[https://docs.opencv.org/]。
⒌视频处理中的很多问题涉及摄像机和计算机的硬件设备,需要结合具体系统环境来分析。


1.2 OpenCV拍摄视频例程

OpenCV视频拍摄的基本步骤为:

(1)创建视频读取/捕获对象;
(2)获取视频的一帧图像;
(3)检查视频获取是否成功;
(4)释放视频读取/捕获对象。

【例程0107】调用摄像头拍照和录制视频

本例程示例调用笔记本内置摄像头抓拍图片和录制视频。根据计算机和摄像头的配置和接口的不同,可能需要修改API的设置。

#  OpenCV 调用摄像头拍照和录制视频
import cv2 as cvif __name__ == '__main__':# 创建视频捕获对象,调用笔记本摄像头# cam = cv.VideoCapture(0)  # 创建捕获对象,0 为笔记本摄像头cam = cv.VideoCapture(0, cv.CAP_DSHOW)  # 修改 API 设置为视频输入 DirectShow# 设置写入视频图像的高,宽,帧速率和总帧数fps = 20  # 设置帧速率width = int(cam.get(cv.CAP_PROP_FRAME_WIDTH))  # 640height = int(cam.get(cv.CAP_PROP_FRAME_HEIGHT))  # 480fourcc = cv.VideoWriter_fourcc(*'XVID')  # 编码器设置 XVID# 创建写入视频对象vedioPath = "../images/camera.avi"  # 写入视频文件的路径capWrite = cv.VideoWriter(vedioPath, fourcc, fps, (width, height))print(fourcc, fps, (width, height))sn = 0  # 抓拍图像编号while cam.isOpened():  # 检查视频捕获是否成功success, frame = cam.read()  # 读取下一帧视频图像if success is True:cv.imshow('vedio', frame)  # 播放视频图像capWrite.write(frame)  # 将当前帧写入视频文件key = cv.waitKey(1) & 0xFF  # 接收键盘输入if key == ord('c'):  # 按 'c' 键抓拍当前帧filePath = "../images/photo{:d}.png".format(sn)  # 保存文件名cv.imwrite(filePath, frame)  # 将当前帧保存为图片sn += 1  # 更新写入图像编号print(filePath)elif key == ord('q'):  # 按 'q' 键结束录制视频breakelse:print("Can't receive frame.")breakcam.release()  # 关闭视频捕获对象capWrite.release()  # 关闭视频写入对象cv.destroyAllWindows()  # 关闭显示窗口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rmDfexHk-1677464268030)(D:\OpenCVPyQt\images\OpenCV_35.png)]


2. 用PyQt5显示OpenCV拍摄的视频流

2.1 用 QtDesigner 开发 PyQt5 图形界面

(1)打开QtDesigner,新建窗体。在 “新建窗体” 窗口的左侧菜单选择 “MainWindow” 新建一个图形窗口。

(2)创建一个显示框控件QLabel,用于显示视频流。

  • 从左侧控件栏的 DisplayWidgets 中选择 Label,拖动到新建图形窗口,生成了一个 QLabel 对象。
  • 鼠标选中 QLabel 对象,在右侧的 “属性编辑器” 内可以对对象的属性进行编辑和修改。

(3)创建按钮控件:

  • 从左侧控件栏的 Button 中选择 PushButton 按钮,拖动到新建图形窗口,生成 PushButton 按钮对象。
  • 鼠标左键点击图形窗口中的这个 PushButton 按钮对象,拖动按钮可以调整控件的位置,对于其它控件也可以通过鼠标拖动来调整位置。
  • 鼠标选中 PushButton 按钮对象,控件周围的边界位置上就出现 8个蓝色的点,表示控件被选中,这时可以在右侧的 “属性编辑器” 内对对象的属性进行编辑和修改,例如:
    • 将 PushButton 对象的高度修改为 120,宽度修改为 40;
    • 将 PushButton 对象的 “QAbstractButton->text” 修改为 “开启”。

根据设计方案,用 QtDesigner 完成一个基本的图形界面。

(4) 将设计的图形界面保存为 .ui文件
文件默认保存在添加 QtDesigner 工具时 “Working directory” 所设置的路径,当然也可以另存到其它路径。
如果 PyChrm 或 QtDesigner 设置的文件保存路径不同,要注意导入图形界面文件时设置和使用正确的路径。

在这里插入图片描述

于是,我们就完成了本项目的图形界面设计,将其保存为 uiDemo9.ui文件。

在 PyCharm中,使用 PyUIC 将选中的 uiDemo9.ui 文件转换为 .py 文件,就得到了 uiDemo9.py 文件。


2.2 用 QTime 定时器实现视频播放

使用 OpenCV 对视频文件进行解码获得图像帧以后,可以使用 QTime 定时器来控制 QLabel 控件中的图像更新,实现视频播放。

PyQt5 中的 QTimer类提供了重复的和单次的定时器,为计时器提供了高级编程接口。要使用定时器,需要先创建一个QTimer实例,将定时器的timeout信号连接到相应的槽函数,并调用start(),定时器就会以设定的间隔发出timeout信号。

例程:使用 QTimer 在PyQt 控件中播放解码的图像帧

    self.timerCam = QtCore.QTimer()  # 定时器,毫秒self.timerCam.timeout.connect(self.refreshFrame)  # 计时器结束时调用槽函数刷新当前帧def refreshFrame(self):  # 刷新视频图像success, self.frame = self.cam.read()  # 读取下一帧视频图像image = self.frame[self.top:self.bottom, self.left:self.right].copy()qImg = self.cvToQImage(image)  # OpenCV 转为 PyQt 图像格式# qImg = self.cvToQImage(self.frame)  # OpenCV 转为 PyQt 图像格式self.label_1.setPixmap((QPixmap.fromImage(qImg)))  # 加载 PyQt 图像return


2.3 摄像头的打开与关闭控制

通过开启/关闭按键controlButton控制摄像头的打开与关闭。

(1)摄像头当前状态为打开时,按键显示的文本为“停止”,表示触发该按键时停止摄像;摄像头当前状态为关闭时,按钮显示的文本为“打开”,表示触发该按键时开始摄像。

(2)如果摄像头尚未初始化,则要初始化定义一个视频输入对象 self.cam。

    def controlCamera(self):  # 控制摄像头打开与关闭if self.timerCamera.isActive()==False:  # 摄像头关闭状态,打开动作print("正在打开摄像头")if self.cam.isOpened()==True:  # 检查视频捕获是否成功success, self.frame = self.cam.read()  # 读取下一帧视频图像self.height, self.width = self.frame.shape[:2]self.top, self.bottom = int(0.1*self.height), int(0.9*self.height)self.left, self.right = int(0.1*self.width), int(0.9*self.width)print(self.left, self.right, self.top, self.bottom)self.timerCamera.start(30)else:msg = QMessageBox.warning(self, "Warning", "开启摄像头失败,重试一次")self.cam = cv.VideoCapture(0, cv.CAP_DSHOW)  # 修改 API 设置为视频输入 DirectShoself.controlButton.setText("停止")else:  # 摄像头开启状态,关闭动作print("正在关闭摄像头")self.timerCamera.stop()  # 关闭定时器self.controlButton.setText("开启")

2.4 摄像画面的移动控制

本例程使用按钮控制摄像画面的移动.

由于摄像头移动控制比较复杂,而且通常涉及硬件接口,本文不做详细介绍。为了便于测试,本例从拍摄图像中裁剪不同区域进行显示,在显示窗口实现拍摄画面的移动,来模拟摄像头的移动控制。

默认显示拍摄图像的中间的 0.1~0.9 高度×宽度区域。操作向上按键,则显示 0.0~0.8 高度区域;操作向下按键,则显示 0.2~1.0 高度区域;操作向左按键,则显示 0.0~0.8 宽度区域;操作向右按键,则显示 0.2~1.0 宽度区域。

这样处理,一方面可以达到模拟移动摄像头的显示效果,另一方面简化程序便于读者理解整个程序的结构。

    # 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButtonself.pushButton_1.clicked.connect(self.upFrame)  # 向上self.pushButton_2.clicked.connect(self.downFrame)  # 向下self.pushButton_3.clicked.connect(self.leftFrame)  # 向左self.pushButton_4.clicked.connect(self.rightFrame)  # 向右self.height, self.width = self.frame.shape[:2]self.top, self.bottom = int(0.1*self.height), int(0.9*self.height)self.left, self.right = int(0.1*self.width), int(0.9*self.width)print(self.left, self.right, self.top, self.bottom)    def upFrame(self):print("视频 图像上移")self.top, self.bottom = 0, int(0.8*self.height)def downFrame(self):print("视频 图像下移")self.top, self.bottom = int(0.2*self.height), self.heightdef leftFrame(self):print("视频 图像左移")self.left, self.right = 0, int(0.8*self.width)def rightFrame(self):print("视频 图像右移")self.left, self.right = int(0.2*self.width), self.width

3. 项目实战:PyQt 视频拍摄与摄像头控制

本节介绍摄像头操作与拍摄实时视频。本例使用 OpenCV处理摄像头设备进行解码获得图像帧,然后用 QTime 定时器控制 QLabel 中的图像更新,使用按钮控制摄像画面的移动。


3.1 UI 程序 uiDemo12.py

为了便于测试,本节给出uiDemo12.py供读者参考,这是由uiDemo12.ui生成的。

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'uiDemo12.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(721, 493)MainWindow.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))icon = QtGui.QIcon()icon.addPixmap(QtGui.QPixmap("../images/youcansSmallLogo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)MainWindow.setWindowIcon(icon)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.label_1 = QtWidgets.QLabel(self.centralwidget)self.label_1.setGeometry(QtCore.QRect(0, 0, 480, 400))self.label_1.setText("")self.label_1.setPixmap(QtGui.QPixmap("../images/youcansSmallLogo.png"))self.label_1.setAlignment(QtCore.Qt.AlignCenter)self.label_1.setObjectName("label_1")self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_1.setGeometry(QtCore.QRect(560, 60, 60, 60))self.pushButton_1.setText("")icon1 = QtGui.QIcon()icon1.addPixmap(QtGui.QPixmap("../images/iconUp.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)self.pushButton_1.setIcon(icon1)self.pushButton_1.setIconSize(QtCore.QSize(60, 60))self.pushButton_1.setObjectName("pushButton_1")self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_2.setGeometry(QtCore.QRect(560, 180, 60, 60))self.pushButton_2.setText("")icon2 = QtGui.QIcon()icon2.addPixmap(QtGui.QPixmap("../images/iconDown.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)self.pushButton_2.setIcon(icon2)self.pushButton_2.setIconSize(QtCore.QSize(60, 60))self.pushButton_2.setObjectName("pushButton_2")self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_3.setGeometry(QtCore.QRect(500, 120, 60, 60))self.pushButton_3.setText("")icon3 = QtGui.QIcon()icon3.addPixmap(QtGui.QPixmap("../images/iconLeft.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)self.pushButton_3.setIcon(icon3)self.pushButton_3.setIconSize(QtCore.QSize(60, 60))self.pushButton_3.setObjectName("pushButton_3")self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_4.setGeometry(QtCore.QRect(620, 120, 60, 60))self.pushButton_4.setText("")icon4 = QtGui.QIcon()icon4.addPixmap(QtGui.QPixmap("../images/iconRight.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)self.pushButton_4.setIcon(icon4)self.pushButton_4.setIconSize(QtCore.QSize(60, 60))self.pushButton_4.setObjectName("pushButton_4")self.controlButton = QtWidgets.QPushButton(self.centralwidget)self.controlButton.setGeometry(QtCore.QRect(500, 300, 80, 55))font = QtGui.QFont()font.setFamily("微软雅黑")font.setPointSize(12)self.controlButton.setFont(font)self.controlButton.setIconSize(QtCore.QSize(60, 60))self.controlButton.setObjectName("controlButton")self.returnButton = QtWidgets.QPushButton(self.centralwidget)self.returnButton.setGeometry(QtCore.QRect(600, 300, 80, 55))font = QtGui.QFont()font.setFamily("微软雅黑")font.setPointSize(12)self.returnButton.setFont(font)self.returnButton.setIconSize(QtCore.QSize(60, 60))self.returnButton.setObjectName("returnButton")MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 721, 25))self.menubar.setBaseSize(QtCore.QSize(9, 0))font = QtGui.QFont()font.setPointSize(10)self.menubar.setFont(font)self.menubar.setObjectName("menubar")self.menuFile = QtWidgets.QMenu(self.menubar)self.menuFile.setObjectName("menuFile")self.menuQuit = QtWidgets.QMenu(self.menubar)self.menuQuit.setObjectName("menuQuit")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.toolBar = QtWidgets.QToolBar(MainWindow)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.toolBar.sizePolicy().hasHeightForWidth())self.toolBar.setSizePolicy(sizePolicy)self.toolBar.setMinimumSize(QtCore.QSize(0, 30))font = QtGui.QFont()font.setPointSize(10)self.toolBar.setFont(font)self.toolBar.setObjectName("toolBar")MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)self.actionOpen = QtWidgets.QAction(MainWindow)self.actionOpen.setEnabled(True)self.actionOpen.setIconVisibleInMenu(False)self.actionOpen.setObjectName("actionOpen")self.actionSave = QtWidgets.QAction(MainWindow)self.actionSave.setIconVisibleInMenu(False)self.actionSave.setObjectName("actionSave")self.actionClose = QtWidgets.QAction(MainWindow)self.actionClose.setIconVisibleInMenu(False)self.actionClose.setObjectName("actionClose")self.actionQuit = QtWidgets.QAction(MainWindow)self.actionQuit.setVisible(True)self.actionQuit.setIconVisibleInMenu(False)self.actionQuit.setObjectName("actionQuit")self.actionSetup = QtWidgets.QAction(MainWindow)self.actionSetup.setObjectName("actionSetup")self.actionHelp = QtWidgets.QAction(MainWindow)self.actionHelp.setObjectName("actionHelp")self.menuFile.addAction(self.actionOpen)self.menuFile.addAction(self.actionSave)self.menuFile.addAction(self.actionClose)self.menuQuit.addAction(self.actionQuit)self.menubar.addAction(self.menuFile.menuAction())self.menubar.addAction(self.menuQuit.menuAction())self.toolBar.addAction(self.actionOpen)self.toolBar.addAction(self.actionClose)self.toolBar.addAction(self.actionSave)self.toolBar.addAction(self.actionSetup)self.toolBar.addAction(self.actionHelp)self.toolBar.addAction(self.actionQuit)self.retranslateUi(MainWindow)self.actionQuit.triggered.connect(MainWindow.close)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "OpenCV-PyQt"))self.controlButton.setText(_translate("MainWindow", "开 启"))self.returnButton.setText(_translate("MainWindow", "返 回"))self.menuFile.setTitle(_translate("MainWindow", "文件"))self.menuQuit.setTitle(_translate("MainWindow", "退出"))self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))self.actionOpen.setText(_translate("MainWindow", "打开"))self.actionSave.setText(_translate("MainWindow", "保存"))self.actionClose.setText(_translate("MainWindow", "关闭"))self.actionQuit.setText(_translate("MainWindow", "退出"))self.actionSetup.setText(_translate("MainWindow", "设置"))self.actionHelp.setText(_translate("MainWindow", "帮助"))

3.2 主程序:视频拍摄与控制

# OpenCVPyqt12.py
# Demo05 of GUI by PyQt5
# Copyright 2023 Youcans, XUPT
# Crated:2023-02-24import sys
import cv2 as cv
import numpy as np
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from uiDemo12 import Ui_MainWindow  # 导入 uiDemo12.py 中的 Ui_MainWindow 界面类class MyMainWindow(QMainWindow, Ui_MainWindow):returnSignal = QtCore.pyqtSignal()def __init__(self, parent=None):super(MyMainWindow, self).__init__(parent)  # 初始化父类self.setupUi(self)  # 继承 Ui_MainWindow 界面类# 初始化摄像头,创建捕获对象# self.cam = cv.VideoCapture(0)  # 实例化 VideoCapture 类,0 为笔记本摄像头self.cam = cv.VideoCapture(0, cv.CAP_DSHOW)  # 修改 API 设置为视频输入 DirectShowself.timerCamera = QtCore.QTimer()  # 初始化定时器self.frameNum = 0# 初始化信号与槽的连接self.initSolt()  # 槽函数初始化self.timerCamera.timeout.connect(self.refreshFrame)  # 初始化计时器def initSolt(self):# 菜单栏的动作连接self.actionOpen.triggered.connect(self.openVideo)  # 连接并执行 openSlot 子程序self.actionHelp.triggered.connect(self.trigger_actHelp)  # 连接并执行 trigger_actHelp 子程序self.actionQuit.triggered.connect(self.close)  # 连接并执行 trigger_actHelp 子程序# 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButtonself.pushButton_1.clicked.connect(self.upFrame)  # 向上self.pushButton_2.clicked.connect(self.downFrame)  # 向下self.pushButton_3.clicked.connect(self.leftFrame)  # 向左self.pushButton_4.clicked.connect(self.rightFrame)  # 向右self.timerCamera.timeout.connect(self.refreshFrame)  # 计时器结束时调用槽函数刷新当前帧# # 信号和槽连接self.returnButton.clicked.connect(self.returnSignal)  # 返回 按键self.controlButton.clicked.connect(self.controlCamera)  # 开关摄像头 按键def controlCamera(self):  # 控制摄像头打开与关闭if self.timerCamera.isActive()==False:  # 摄像头关闭状态,打开动作print("正在打开摄像头")if self.cam.isOpened()==True:  # 检查视频捕获是否成功success, self.frame = self.cam.read()  # 读取下一帧视频图像self.height, self.width = self.frame.shape[:2]self.top, self.bottom = int(0.1*self.height), int(0.9*self.height)self.left, self.right = int(0.1*self.width), int(0.9*self.width)print(self.left, self.right, self.top, self.bottom)self.timerCamera.start(30)else:msg = QMessageBox.warning(self, "Warning", "开启摄像头失败,重试一次")self.cam = cv.VideoCapture(0, cv.CAP_DSHOW)  # 修改 API 设置为视频输入 DirectShoself.controlButton.setText("停止")else:  # 摄像头开启状态,关闭动作print("正在关闭摄像头")self.timerCamera.stop()  # 关闭定时器self.controlButton.setText("开启")def refreshFrame(self):success, self.frame = self.cam.read()  # 读取下一帧视频图像image = self.frame[self.top:self.bottom, self.left:self.right].copy()qImg = self.cvToQImage(image)  # OpenCV 转为 PyQt 图像格式# qImg = self.cvToQImage(self.frame)  # OpenCV 转为 PyQt 图像格式self.label_1.setPixmap((QPixmap.fromImage(qImg)))  # 加载 PyQt 图像returndef returnSignal(self):if self.cam.isOpened()==True:print("关闭视频捕获对象")self.cam.release()  # 关闭视频捕获对象# self.label_1.clear()  # 清空显示图像def upFrame(self):print("视频 图像上移")self.top, self.bottom = 0, int(0.8*self.height)def downFrame(self):print("视频 图像下移")self.top, self.bottom = int(0.2*self.height), self.heightdef leftFrame(self):print("视频 图像左移")self.left, self.right = 0, int(0.8*self.width)def rightFrame(self):print("视频 图像右移")self.left, self.right = int(0.2*self.width), self.widthdef cvToQImage(self, image):# 8-bits unsigned, NO. OF CHANNELS=1if image.dtype == np.uint8:channels = 1 if len(image.shape) == 2 else image.shape[2]if channels == 3:  # CV_8UC3# Create QImage with same dimensions as input MatqImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_RGB888)return qImg.rgbSwapped()elif channels == 1:# Create QImage with same dimensions as input MatqImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_Indexed8)return qImgelse:QtCore.qDebug("ERROR: numpy.ndarray could not be converted to QImage. Channels = %d" % image.shape[2])return QImage()def openVideo(self):  # 读取视频文件,点击 pushButton_1 触发self.videoPath, _ = QFileDialog.getOpenFileName(self, "Open Video", "../images/", "*.mp4 *.avi *.mov")print("Open Video: ", self.videoPath)returndef trigger_actHelp(self):  # 动作 actHelp 触发QMessageBox.about(self, "About","""数字图像处理工具箱 v1.0\nCopyright YouCans, XUPT 2023""")returnif __name__ == '__main__':app = QApplication(sys.argv)  # 在 QApplication 方法中使用,创建应用程序对象myWin = MyMainWindow()  # 实例化 MyMainWindow 类,创建主窗口myWin.show()  # 在桌面显示控件 myWinsys.exit(app.exec_())  # 结束进程,退出程序

3.3 程序说明和运行结果

(1)“打开”按钮用于从文件夹选择播放的视频文件。

(2)“播放”按钮用于播放打开的视频文件,播放结束后自动关闭。

(3)“暂停/继续”按钮用于暂停/继续播放视频文件。按钮初始显示为“暂停”,按下“暂停”按钮后暂停播放,按钮显示切换为“继续”;再次按下“继续”按钮后继续播放,按钮显示切换为“暂停”。

(4)在播放过程中,按下键盘回车键,则抓拍视频当前帧并显示在GUI 右侧窗口控件中。

运行结果:

启动程序,控制按键显示为“开启”。

在这里插入图片描述


开始拍摄,控制按键显示变为“停止”。

在这里插入图片描述


操作控制按钮”向上“,显示画面向上移动,可以显示沙发顶部。

在这里插入图片描述


操作控制按钮”向左“,显示画面向左移动,大黄狗躲起来了。

在这里插入图片描述


【本节完】


版权声明:

Copyright 2023 youcans, XUPT

Crated:2023-2-27


相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...