「图像处理」opencv(python)获取摄像头画面(使用队列Queue实现显示)

最开始使用opencv_python捕获摄像头的时候,都是简单粗暴的while死循环,然后在同一个线程里面进行图像处理。这种方法有点莽。

后来使用线程,这样实现:

import threading
import cv2


class OpcvCapture(threading.Thread):
    def __init__(self, win_name, cam_name):
        super().__init__()
        self.cam_name = cam_name
        self.win_name = win_name

    def run(self):
        capture = cv2.VideoCapture(self.cam_name)
        while (True):
            # 获取一帧
            ret, frame = capture.read()
            cv2.imshow(self.win_name, frame)
            cv2.waitKey(1)


if __name__ == "__main__":
    camera0 = OpcvCapture("camera0", 0)
    camera0.start()
    camera1 = OpcvCapture("camera1", 1)
    camera1.start()
    run_code = 0

对于每一帧图像的处理,都是把处理方法方式注入到摄像头捕获的线程中执行,跨线程的时候就很麻烦,有些时候会无法运行。

所以现在改用队列的方式,将图像的获取与处理完全分开,各干各的,这样摄像头捕获程序就可以作为一个类,可以不用再去修改它了。

对于每一帧的处理作为独立的线程从图像队列中去取图像就好,至于如何处理,都不用修改摄像头帧捕获的相关代码。

整理以下,方便以后取用。

import time
import cv2
from queue import Queue
from threading import Thread


"""
Camera类只负责从摄像头获取图像
对图像的处理(包括显示)由外部定义
"""
class Camera:
    def __init__(self, device_id, frame_queue):
        self.device_id = device_id  # 摄像头id
        self.cam = cv2.VideoCapture(self.device_id)  # 获取摄像头
        self.frame_queue = frame_queue  # 帧队列
        self.is_running = False  # 状态标签
        self.fps = 0.0  # 实时帧率
        self._t_last = time.time() * 1000
        self._data = {} 

    def capture_queue(self):
        # 捕获图像
        self._t_last = time.time() * 1000
        while self.is_running and self.cam.isOpened():
            ret, frame = self.cam.read()
            if not ret:
                break
            if self.frame_queue.qsize() < 1: 
                # 当队列中的图像都被消耗完后,再压如新的图像              
                t  = time.time() * 1000
                t_span = t - self._t_last                
                self.fps = int(1000.0 / t_span)
                self._data["image"] = frame.copy()
                self._data["fps"] = self.fps
                self.frame_queue.put(self._data)
                self._t_last = t

    def run(self):
        self.is_running = True
        self.thread_capture = Thread(target=self.capture_queue)
        self.thread_capture.start()

    def stop(self):
        self.is_running = False
        self.cam.release()


# 对于图像的处理方法
def show_frame(frame):
        while True:
            # 根据实际需求,设置跳出循环(结束线程)的方法
            data = frame.get()
            image = data["image"]
            cv2.putText(image, "fps:{fps}".format(fps=data["fps"]), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0 ,0))
            cv2.namedWindow("camera", cv2.WINDOW_AUTOSIZE)    
            cv2.imshow("camera", image)
            if cv2.waitKey(1)& 0xFF == ord('q'): 
                break
            frame_queue.task_done()


if __name__ == "__main__":
    # 启动 获取摄像头画面的 线程
    frame_queue = Queue()
    cam = Camera(0, frame_queue)
    cam.run()
    # 启动处理(显示)摄像头画面的线程
    thread_show = Thread(target=show_frame, args=(frame_queue,))
    thread_show.start()
    time.sleep(60)
    cam.stop()
    # TO DO 修改图像处理的死循环(while True)确保可正常结束。

 

  • 9
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
使用多线程队列读取四个USB摄像头显示,你可以使用Python的`opencv-python`库和`threading`模块。以下是一个示例代码: ```python import cv2 import threading from queue import Queue # 摄像头索引列表 camera_indexes = [0, 1, 2, 3] # 摄像头读取线程类 class CameraThread(threading.Thread): def __init__(self, camera_index, queue): threading.Thread.__init__(self) self.camera_index = camera_index self.queue = queue def run(self): cap = cv2.VideoCapture(self.camera_index) 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): while True: if self.queue.empty(): continue frame = self.queue.get() cv2.imshow(f"Camera {frame['camera_index']}", frame['frame']) if cv2.waitKey(1) & 0xFF == ord('q'): break cv2.destroyAllWindows() # 创建队列 queue = Queue(maxsize=4) # 创建摄像头读取线程 camera_threads = [] for index in camera_indexes: thread = CameraThread(index, 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`类负责从摄像头读取帧并将其放入队列中,而`DisplayThread`类负责从队列获取帧并显示。我们使用多线程来同时读取和显示四个摄像头的帧。 你可以根据实际情况修改`camera_indexes`列表中的摄像头索引,确保索引与你的USB摄像头对应。运行代码后,将会打开四个窗口,分别显示四个摄像头的实时图像。按下 'q' 键以退出程序。 请注意,在同时处理多个摄像头时,可能会遇到性能问题。如果需要更高的性能,你可以尝试使用多线程加速或使用更高性能的设备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值