OpenCV

您所在的位置:网站首页 卡卡继续播放 OpenCV

OpenCV

2024-06-25 12:45| 来源: 网络整理| 查看: 265

欢迎关注『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项目实战(12)项目案例08:多线程视频播放1. 线程处理1.1 线程与进程1.2 为什么使用多线程1.3 单线程与多线程的基本例程 2. Python自定义线程2.1 线程的创建步骤2.2 通过线程类 threading.Thread() 创建线程对象2.4 继承 threading.Thread 来自定义线程类2.5 使用 moveToThread 方法 3. 多线程视频解码和视频播放3.1 自定义线程类3.2 视频解码子程序3.3 视频播放子程序3.4 主程序3.5 UI 界面 uiDemo13.ui 4. 项目实战:PyQt多线程视频处理4.1 程序说明4.2 完整例程

OpenCV-PyQT项目实战(12)项目案例08:多线程视频播放

在之前的案例中,我们使用 QTime 定时器和 QThread 的方式来控制 QLabel 中的图像更新,实现视频播放或实时监控。但是,如果需要同时播放多路视频,或者在视频播放的同时进行图像处理,这种处理方法容易产生卡顿或阻塞,因此需要使用多线程解决这个问题。

1. 线程处理 1.1 线程与进程

进程(Process)是操作系统进行资源分配和调度运行的基本单位,可以理解为操作系统中正在执行的程序。每个应用程序都有一个自己的进程。

线程是一个基本的CPU执行单元,是程序执行的最小单元。 线程自己不拥有系统资源,必须依托于进程存活。一个线程是一个execution context,即一个CPU执行时所需要的一串指令。

每一个进程启动时都会最先产生一个线程,即主线程。然后主线程会再创建其他的子线程。

线程与进程的区别: 线程必须在某个进程中执行。一个进程可包含多个线程,其中有且只有一个主线程。多线程共享同个地址空间、打开的文件以及其他资源。多进程共享物理内存、磁盘、打印机以及其他资源。 1.2 为什么使用多线程

线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄和其他进程应有的状态。

因为线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程之中拥有独立的内存单元,而多个线程共享内存,从而极大的提升了程序的运行效率。

线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性,多个线程共享一个进程的虚拟空间。线程的共享环境包括进程代码段、进程的共有数据等,利用这些共享的数据,线程之间很容易实现通信。

操作系统在创建进程时,必须为改进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此,使用多线程来实现并发比使用多进程的性能高得要多。

多线程(multithreading)是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。

线程从创建到消亡的过程为:

new(新建):新创建的线程经过初始化后,进入Runnable状态。Runnable(就绪):等待线程调度。调度后进入运行状态。Running(运行)。Blocked(阻塞):暂停运行,解除阻塞后进入Runnable状态重新等待调度。Dead(消亡):线程方法执行完毕返回或者异常终止。

从运行状态(Running)进入阻塞状态(Blocked)有三种情况:

同步:线程中获取同步锁,但是资源已经被其他线程锁定时,进入Locked状态,直到该资源可获取(获取的顺序由Lock队列控制)睡眠:线程运行sleep()或join()方法后,线程进入Sleeping状态。区别在于sleep等待固定的时间,而join是等待子线程执行完。当然join也可以指定一个“超时时间”。从语义上来说,如果两个线程a,b, 在a中调用b.join(),相当于合并(join)成一个线程。最常见的情况是在主线程中join所有的子线程。等待:线程中执行wait()方法后,线程进入Waiting状态,等待其他线程的通知(notify)。 1.3 单线程与多线程的基本例程

例程1:单线程

import time def sayHello(): print("Hello") time.sleep(1) if __name__ == '__main__': for i in range(10): sayHello()

运行时间为:10秒。

例程2:多线程

通过多线程可以完成多任务。

import time,threading def sayHello(): print("Hello") time.sleep(1) if __name__ == '__main__': for i in range(10): # 创建子线程对象 thread_obj = threading.Thread(target=sayHello) # 启动子线程对象 thread_obj.start()

运行时间为:1秒。

例程3:线程的执行顺序

import time,threading def sing(): for i in range(3): print("is singing... %d" % i) time.sleep(1) def dance(): for i in range(3): print("is dancing... %d" % i) time.sleep(1) if __name__ == '__main__': print("The main thread starts to execute") t1 = threading.Thread(target=sing) t2 = threading.Thread(target=dance) t1.start() t2.start() print("Main thread execution completed")

运行结果:

The main thread starts to execute is singing... 0 is dancing... 0 Main thread execution completed is dancing... 1is singing... 1 is singing... 2 is dancing... 2 Process finished with exit code 0

主线程执行完毕后,还要等待所有子线程执行完毕后才结束程序运行。

2. Python自定义线程 2.1 线程的创建步骤 (1) 导入线程模块 import threading (2) 通过线程类创建进程对象 线程对象 = threading.Thread(target = 任务名) (3) 启动线程执行任务 线程对象.start() 2.2 通过线程类 threading.Thread() 创建线程对象

语法:

thread.Thread(group=Nore,targt=None,args=(),kwargs={},*,daemon=None)

参数说明:

group:必须为None,于ThreadGroup类相关,一般不使用。target:线程调用的对象,就是目标函数。name:为线程起这个名字。默认是Tread-x,x是序号,由1开始,第一个创建的线程名字就是Tread-1。args:为目标函数传递关键字参数,元组。kwargs:为目标函数传递关键字参数,字典。daemon:用来设置线程是否随主线程退出而退出。

例程4:子线程的创建与开启

线程对象 = threading.Thread(target=任务名)

import threading def run1(n): print("current task:run1") def run2(n): print("current task:run2") if __name__ == "__main__": t1 = threading.Thread(target=run1) # 创建子线程1 t2 = threading.Thread(target=run2) # 创建子线程2 t1.start() # 开启线程 t1 t2.start() # 开启线程 t2

例程5:给线程执行的任务传递参数

线程可以以元组args 的方式或字典 kwargs 的方式给执行的任务传递参数。

线程对象 = threading.Thread(target=任务名, args=(arg1,…)) 线程对象 = threading.Thread(target=任务名, kwargs={k1:num1,…})

import threading def run1(n): print("current task:", n) def run2(n): print("current task:", n) if __name__ == "__main__": t1 = threading.Thread(target=run1, args=("thread 1",)) # 创建子线程1 t2 = threading.Thread(target=run2, args=("thread 2",)) # 创建子线程2 t1.start() # 开启线程 t1 t2.start() # 开启线程 t2 print("end") 2.4 继承 threading.Thread 来自定义线程类

例程6:自定义线程类 MyThread

import threading import time class MyThread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): print("current task:", self.num) time.sleep(self.num) if __name__ == "__main__": t1 = MyThread(100) # 创建子线程1 t2 = MyThread(200) # 创建子线程2 t1.start() # 开启线程 t1 t2.start() # 开启线程 t2 print("end") 2.5 使用 moveToThread 方法

moveToThread 函数给多个任务(如显示多个界面)各分配一个线程去执行,避免自定义多个类继承自 QThread类,从而可以避免冗余。

使用moveToThread函数的流程:

创建一个类继承自QObject类或其子类,在其中定义所要执行的多个任务。任务通过moveToThread指定所要执行的线程。线程通过start启动。通过信号与槽机制触发线程的执行。

该方法通过创建一个线程,将创建的线程与类方法进行绑定来实现,相当于在线程中操作类方法。

例程6:自定义线程类 MyThread

# coding:UTF-8 from PyQt5 import QtWidgets, QtCore import sys from PyQt5.QtCore import * import time # 继承 QObject class Runthread(QtCore.QObject): # 通过类成员对象定义信号对象 signal = pyqtSignal(str) def __init__(self): super(Runthread, self).__init__() self.flag = True def __del__(self): print ">>> __del__" def run(self): i = 0 while self.flag: time.sleep(1) if i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3