当前位置:   article > 正文

PYQT5笔记 010:视频显示+多线程_python pyqt 线程 显示 采集 视频

python pyqt 线程 显示 采集 视频

      在之前的PYQT5笔记 008 :图片读出界面程序,如果想对界面进行视频的帧进行处理然后显示,最简单的想法可能是,将多个显示内容依次写出来:

dir = r"C:\Users\Administrator\Desktop\car.jpg"
self.label.setPixmap(showImage)
time.sleep(3)
dir = r"C:\Users\Administrator\Desktop\cat.jpg"
self.label.setPixmap(showImage)
  • 1
  • 2
  • 3
  • 4
  • 5

线程的解决方案

      但这样写运行的效果为,显示灰色无内容的界面,然后几秒之后直接显示cat图像,而没有car图像。解决方法是使用线程实现:

    def readframe(self):
        th = Thread(target=self.myreadframe) # 需要 from threading import *
        th.start()

    def myreadframe(self):
        dir = r"C:\Users\Administrator\Desktop\car.jpg"
        self.SetPic(dir)
        dir = r"C:\Users\Administrator\Desktop\cat.jpg"
        self.SetPic(dir)

    def SetPic(self,dir):
        pixmap = QPixmap(dir)
        self.label2.setPixmap(pixmap)
        time.sleep(3)
        print(123)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Python 标准库提供了threading,要启动一个单独的线程,需创建一个Thread实例,然后启动它。

x = threading.Thread(target=thread_function, args=(1,))
x.start()
  • 1
  • 2

到此位置,可以思考一下线程的停止了,如果创建了一个服务线程,主线程已经停止,但服务线程还能工作,如以下例子:

import threading
import time

def server():
    while True:
        print("服务线程运行中")
        time.sleep(1)

if __name__ == '__main__':
    ser = threading.Thread(target=server)
    ser.start()
    print('主线程开始')
    time.sleep(6)
    print('主线程结束')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

使用以下设置为守护线程,设置为守护线程后,在主线程退出后,守护线程也会退出(即当pyqt推出后,守护)。

ser.daemon = True
或者
ser = threading.Thread(target=server, args=(index,), daemon=True)
  • 1
  • 2
  • 3

这样就能正常运行了:

import threading
import time

def server():
    while True:
        print("服务线程运行中")
        time.sleep(1)

if __name__ == '__main__':
    ser = threading.Thread(target=server)
    ser.daemon = True
    ser.start()
    print('主线程开始')
    time.sleep(6)
    print('主线程结束')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

还可以进行等待的设置比如ser.join(),当ser的方法运行完之后,在进行下一步的运行。

    ser = threading.Thread(target=server)
    ser.daemon = True
    ser.start()
    ser.join()
    print('主线程开始')
    time.sleep(6)
    print('主线程结束')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

还可以创建多线程:

threads = list() # 用一个容器盛放线程,join时可以在启动完成之后进行join
for index in range(3):
    x = threading.Thread(target=thread_function)
    threads.append(x)
    x.start()
  • 1
  • 2
  • 3
  • 4
  • 5

ThreadPoolExecutor 线程池

# submit提交
import threading
import time
import concurrent.futures
from concurrent.futures.thread import ThreadPoolExecutor


def server(a,b):
    print(a+b)
    time.sleep(1)
    return a
    # while True:
    #     print("服务线程运行中")
    #     time.sleep(1)

if __name__ == '__main__':
    # ser = threading.Thread(target=server)
    # ser.daemon = True
    # ser.start()
    # ser.join()
    with ThreadPoolExecutor(max_workers=1) as executor:
        future = executor.submit(server, 1, 2)# 返回future对象
        print(future.result()) # 获取函数的返回值 并打印
    print('主线程开始')
    time.sleep(6)
    print('主线程结束')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
# map方法提交,执行可迭代的对象
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    executor.map(thread_function, range(3))# range(3)为 iterable object
    # 更多内容详见官方文档
    # 视频教程 https://www.bilibili.com/video/BV1wb4y1S7d6?
  • 1
  • 2
  • 3
  • 4
  • 5
https://realpython.com/intro-to-python-threading/
https://docs.python.org/zh-cn/3/library/threading.html
  • 1
  • 2

继续视频帧的处理

import cv2
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from threading import *
import time


class mywindow(QWidget):
    def __init__(self):
        super().__init__()
        return self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle("showcamera")
        self.lable = QLabel("showcamera", self)
        self.lable.setGeometry(0, 0, 800, 600)
        self.lable.setScaledContents(True)
        self.show()

    def SetPic(self, img):
        self.lable.setPixmap(QPixmap.fromImage(img))

def showcamre():
    imgName, imgType = QFileDialog.getOpenFileName(None, "打开mp4", "", "*.mp4;;*.png;;All Files(*)")  
    cap = cv2.VideoCapture(imgName) # 或读取相机cap = cv2.VideoCapture(0)

    # 视频流设置 参数详见https://github.com/opencv/opencv/blob/master/modules/videoio/include/opencv2/videoio.hpp
    cap.set(cv2.CAP_PROP_FPS, 60) //帧率 帧/秒 https://www.javaroad.cn/questions/288491
    while cap.isOpened():
		success, frame = cap.read()
        if success == False:
            continue
        a = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
        mywindow.SetPic(a)
        time.sleep(0.01) # https://stackoverflow.com/questions/52068277/change-frame-rate-in-opencv-3-4-2

app = QApplication(sys.argv)
window = mywindow()
th = Thread(target=showcamre)# https://www.bbsmax.com/A/kmzLkAjKdG/
th.start()
app.exec_()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
“不断清除相机的帧缓冲区” - 这是关键,我想知道为什么所有初学者教程都忽略了这一点,只是盲目地循环轮询相机并导致 CPU 利用率过高。或者,我可以只 sleep() 循环一段时间以等待下一帧以避免处理同一帧。
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/114960
推荐阅读
相关标签
  

闽ICP备14008679号