一般情况下,我们会在主线程中直接使用opencv打开摄像头然后读取的视频帧进行操作,这种方式是阻塞的,如果我们想要在主线程读取摄像头视频帧的时候还进行其他的操作会非常不方便。这个时候有必要将读取摄像头视频帧的这一部分代码移动到子线程中,然后通过队列使得主线程可以获取摄像头的视频帧,同时也不会阻塞主线程。

1 子线程使用OpenCV读取摄像头视频帧

import cv2
import threading
from queue import Queue

class ReadCameraThread(threading.Thread):
    def __init__(self, video_queue):
        super(ReadCameraThread).__init__()
        threading.Thread.__init__(self)

        self.read_capture = cv2.VideoCapture(0)
        self.video_queue = video_queue
        self.running = True


    def run(self):
        if not self.read_capture.isOpened():
            print('未检测到摄像头')
            exit(0)

        while self.read_capture.isOpened() and self.running:
            ret, frame = self.read_capture.read()

            if not ret:
                break

            self.video_queue.put(frame)
            print('put the frame')

        self.read_capture.release()
        cv2.destroyAllWindows()

    def stop_read_camera(self):
        self.running = False

2 主线程中从缓存队列读取视频帧

class StreamingOnlineRecognize:
    def __init__(self):
        self.video_queue = Queue()

        self.video_stream_in = ReadCameraThread(self.video_queue)
        self.video_stream_in.start()

    def start(self):
        self._running = True

        while self._running:
            if not self.video_queue.empty():
                frame = self.video_queue.get()
                print('get the frame')

                if frame is not None:
                    cv2.imshow('test', frame)
                    cv2.waitKey(1)
            else:
                print('the size of self.video_queue is <= 0')


        cv2.destroyAllWindows()
        self.video_stream_in.join()

3 完整示例

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

import cv2
import threading
from queue import Queue

class ReadCameraThread(threading.Thread):
    def __init__(self, video_queue):
        super(ReadCameraThread).__init__()
        threading.Thread.__init__(self)

        self.read_capture = cv2.VideoCapture(0)
        self.video_queue = video_queue
        self.running = True


    def run(self):
        if not self.read_capture.isOpened():
            print('未检测到摄像头')
            exit(0)

        while self.read_capture.isOpened() and self.running:
            ret, frame = self.read_capture.read()

            if not ret:
                break

            self.video_queue.put(frame)
            print('put the frame')

        self.read_capture.release()
        cv2.destroyAllWindows()

    def stop_read_camera(self):
        self.running = False

class StreamingOnlineRecognize:
    def __init__(self):
        self.video_queue = Queue()

        self.video_stream_in = ReadCameraThread(self.video_queue)
        self.video_stream_in.start()

    def start(self):
        self._running = True

        while self._running:
            if not self.video_queue.empty():
                frame = self.video_queue.get()
                print('get the frame')

                if frame is not None:
                    cv2.imshow('test', frame)
                    cv2.waitKey(1)
            else:
                print('the size of self.video_queue is <= 0')


        cv2.destroyAllWindows()
        self.video_stream_in.join()

if __name__ == '__main__':
    streaming_online_recognize = StreamingOnlineRecognize()
    streaming_online_recognize.start()