pyqt5开发(2-1)界面+显示视频+多线程

 

功能:

使用多线程采集视频刷新主窗口,完成跨线程通信。

 采用队列传图

 

说明:

1为什么不用qt本身的信号和槽函数实现或者Qthread?

这个也是可以实现的,但是考虑学习的通用性,例如将来不用qt写界面或者其他嵌入式设备部署(树莓派+英伟达开发板),这套机制也是可以复用的。这样将会很灵活不用局限于QT本身拥有的东西,使用队列可以自己灵活增加数据类型。2线程配合队列完成跨线程通信。

2注意线程锁的使用。

3尝试使用进程代替线程,失败了,入口错误?

  为什么要用进程,像树莓派好像使用多线程是无效的,实际还是在一个线程跑,使用多进程才是分开了加速。

  进程也会带来问题,队列跨进程之后里所表示的数据将无法识别问题。

实现过程

1首先搭建环境

https://www.cnblogs.com/kekeoutlook/p/13964523.html

2创建工程

目录文件只有3个

2-1激活环境

activate py37_tfgpu1131_keras215_opencv341

2-2创建界面

  运行

designer

 生成一个新界面.ui

一个 lable显示视频和两个按钮

布局 整体栅格布局  两个局部水平布局

默认布局-是初始化给多大就是多大,不会随着窗口自适应变大

 保存成 .ui文件

转换成py文件

python -m PyQt5.uic.pyuic .输入名字.ui -o .输出名字.py

生成的界面布局结果

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file '.UI_vedio.ui'
#
# Created by: PyQt5 UI code generator 5.15.1
#
# 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, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(50, 20, 691, 441))
        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label = QtWidgets.QLabel(self.horizontalLayoutWidget)
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.label)
        self.horizontalLayoutWidget_2 = QtWidgets.QWidget(self.centralwidget)
        self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(50, 470, 691, 80))
        self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.pushButton_1 = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
        self.pushButton_1.setObjectName("pushButton_1")
        self.horizontalLayout_2.addWidget(self.pushButton_1)
        self.pushButton_2 = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_2.addWidget(self.pushButton_2)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "视频流"))
        self.pushButton_1.setText(_translate("MainWindow", "开始播放"))
        self.pushButton_2.setText(_translate("MainWindow", "结束播放"))

  

 

主程序

import sys
from PyQt5.QtWidgets import QApplication,QMainWindow,QFileDialog
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import QtWidgets, QtCore, QtGui

#导入图像库
import cv2

#进程测试
#import multiprocessing

#线程测试
import threading
from queue import Queue

#导入自己创建的图形类
from UI_vedio import *

        

#一个是这个类本身的,一个是这个类继承
class Example(QMainWindow,Ui_MainWindow):

    def __init__(self):
        #类的初始化
        super(Example, self).__init__()
        self.setupUi(self)#界面控件初始化
 
        #相机线程初始化
        self.CAM_Int()
       
        #按钮绑定函数
        self.pushButton_1.clicked.connect(self.on_video)  #开始按键
       
       
    #按键函数
    def on_video(self):      
        if self.open_flag:
            self.pushButton_1.setText('关闭视频')
            self.open_flag=bool(0)
        
            
            
        else:       
            self.pushButton_1.setText('开始播放')
            self.open_flag=bool(1)        
        #self.open_flag = bool(1-self.open_flag)#
        self.lock.acquire()#获得锁
        if self.qcontrol.full():
            self.qcontrol.get()
        self.qcontrol.put(self.open_flag)
        self.lock.release()#释放锁

         
        
    def CAM_Int(self):
        #控制信号量
        self.open_flag=1
        self.qcontrol = Queue(1)         #用于主线程控制播放线程控制信号
        self.qcontrol.put(self.open_flag)
        self.qframe =Queue(2)           #用于主线程读取次线程图像数据
        
        #创建播放线程
        self.CAM_Play()
    

    def CAM_Play(self):

        
        #开启线程
        self.lock = threading.Lock()
        self.t1_video = threading.Thread(target=self.videogo, args=(self.qcontrol,self.qframe,self.lock))
        self.t1_video.start()
        

        #多进程报错
        '''
        self.lock=multiprocessing.Lock()
        p1=multiprocessing.Process(target=self.videogo,args=(self.qcontrol,self.qframe,self.lock,))
        p1.daemon = True
        p1.start()
        '''
         
        
        #定时器20毫秒更新画板
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.CAM_SetImage)  
        self.timer.start(20) #单位为毫秒
        
    #配合定时器刷新图像显示
    def CAM_SetImage(self):
        if self.qframe.empty():
            pass
        else:
            image=self.qframe.get()
            self.label.setPixmap(QPixmap.fromImage(image))
        
    def videogo(self,qcontrol,qframe,lock):
        cap = cv2.VideoCapture(0)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH,800)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT,600)
        cap.set (cv2.CAP_PROP_FPS,25)
       
        while (cap.isOpened()==True):

            
            #判断是否需要开启或者关闭
            if bool(1-qcontrol.empty()):         
                go=qcontrol.get()
                print(go)
                if go:
                    pass
                else:
                    break
                    pass
               
            
            
            ret, frame = cap.read()  
            if ret:
                rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                convertToQtFormat = QtGui.QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QImage.Format_RGB888)#在这里可以对每帧图像进行处理,
                qtimg = convertToQtFormat.scaled(600, 600, Qt.KeepAspectRatio)
              
                lock.acquire()#获取锁
                if qframe.full():#如果满了就清空一帧
                    qframe.get()                 
                qframe.put(qtimg)
                lock.release()# 释放锁 
              
            else:
                continue





if __name__ == '__main__':

    app = QApplication(sys.argv)     
    ui=Example()  
    ui.show()
    sys.exit(app.exec_())

    

  

运行程序

 python .4UI_Video_thread_queue.py

  

原文地址:https://www.cnblogs.com/kekeoutlook/p/13995568.html