多线程读取IP摄像头(Python版)

本文介绍如何使用Python的threading模块和队列处理IP摄像头的高帧率数据流,避免程序卡死。通过创建线程类并重写run方法实现多线程,利用deque作为双端队列缓存数据,确保实时处理当前帧。加入锁机制防止线程冲突,并展示了实时读取和间隔处理的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章和资源同步发布于微信公众号:算法工程师之路

在深度学习时代(这么说也不为过)的今天,我们做各种视觉任务时候都会想到使用深度学习,但是大家也都知道深度学习的模型如果想要使用的话,设备必须得有,虽然各种各样的量化策略和剪枝策略大大加速了模型的推理能力,但是实时的话在低配电脑还是不可用!
但是实际中有些视觉任务不怎么依赖实时性,我们只需要保证1s处理一帧图片就可以了,或者几十秒处理一帧也可以。那么这种处理策略怎么处理呢?**特别对于IP摄像头,它是以数据流的形式传输,因此当其帧率较高时,本地处理程序会处理不过来,导致卡帧(延时)和程序卡死!**我们一起来看看吧!

threading模块(线程)

在Python中多线程模块有两个,分别是thread(Python3中改名为_thread)和threading模块,其中_thread模块只是提供了基本的线程和线程锁的功能,**而threading模块提供的是更加高级和安全的线程管理!**那什么是线程呢?

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程是一个execution context(执行上下文),即一个cpu执行时所需要的一串指令。就类似于操作系统的多任务工作模式,我们可以形象的认为,CPU将一秒的执行时间分配给各个任务,在一个任务执行后,保存信息并切换到下一个任务,然后循环往复,这样就会增加CPU的执行效率,即使一个任务需要一直等待,那么CPU也会在等待的这段时间切换到其他任务执行!

当我们使用Threading模块创建线程时或者自定义线程任务时,最好的方法就是建立一个线程类,并继承于threading.Thead,然后重写run方法,这是最推荐大家使用的方法(最优雅)。当然也可以使用其他方式创建!主要有以下几个常用函数:

  • threading.currentThread(): 返回当前的线程变量
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
  • run(): 线程活动的函数,自定义时需要重写
  • start():启动线程活动,必须使用
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止,正常退出或者抛出未处理的异常,或者是可选的超时发生,只有子线程都运行完了,主线程(main)才会退出!
  • isAlive(): 返回线程是否活动的
  • getName(): 返回线程名
  • setName(): 设置线程名

代码示例

import threading
import time
class MyThread(threading.Thread):
    def __init__(self, n):
        super(MyThread, self).__init__()  # 重构run函数必须要写
        self.n = n

    def run(self):
        print("task", self.n)
        time.sleep(1)
        print('2s')
        time.sleep(1)
        print('1s')
        time.sleep(1)
        print('0s')
       
要使用多线程队列读取RTSP摄像头并在另外的线程显示,你可以使用Python的`opencv-python`库和`threading`模块。以下是一个示例代码: ```python import cv2 import threading from queue import Queue # RTSP摄像头URL列表 rtsp_urls = [ "rtsp://username:password@ip_address:port/path_to_stream", "rtsp://username:password@ip_address:port/path_to_stream", "rtsp://username:password@ip_address:port/path_to_stream", "rtsp://username:password@ip_address:port/path_to_stream" ] # 摄像头读取线程类 class CameraThread(threading.Thread): def __init__(self, rtsp_url, queue): threading.Thread.__init__(self) self.rtsp_url = rtsp_url self.queue = queue def run(self): cap = cv2.VideoCapture(self.rtsp_url) while True: ret, frame = cap.read() if not ret: break self.queue.put(frame) cap.release() # 显示摄像头线程类 class DisplayThread(threading.Thread): def __init__(self, queue): threading.Thread.__init__(self) self.queue = queue def run(self): # 创建一个窗口来显示摄像头图像 cv2.namedWindow("Camera", cv2.WINDOW_NORMAL) while True: # 获取队列中的帧 frame = self.queue.get() # 在窗口中显示图像 cv2.imshow("Camera", frame) # 按下 'q' 键退出循环 if cv2.waitKey(1) & 0xFF == ord('q'): break cv2.destroyAllWindows() # 创建队列 queue = Queue(maxsize=1) # 创建摄像头读取线程 camera_threads = [] for rtsp_url in rtsp_urls: thread = CameraThread(rtsp_url, queue) camera_threads.append(thread) # 创建显示摄像头线程 display_thread = DisplayThread(queue) # 启动线程 for thread in camera_threads: thread.start() display_thread.start() # 等待线程结束 for thread in camera_threads: thread.join() display_thread.join() ``` 在代码中,我们创建了`CameraThread`类和`DisplayThread`类来分别处理摄像头读取显示。`CameraThread`类负责从RTSP摄像头读取帧并将其放入队列中,而`DisplayThread`类负责从队列中获取帧并显示。我们使用了多线程来同时读取显示多个RTSP摄像头的帧。 你需要根据实际情况修改`rtsp_urls`列表中的RTSP摄像头URL,确保URL与你的摄像头对应。运行代码后,将会打开一个窗口,显示从RTSP摄像头中实时获取的图像。按下 'q' 键以退出程序。 请注意,在同时处理多个摄像头时,可能会遇到性能问题。如果需要更高的性能,你可以尝试使用多线程加速或减少处理的摄像头数量。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值