多线程实现摄像头读取和显示

发布时间 2023-08-07 17:04:48作者: bldong

实现多线程的摄像头的视频读取和显示,两个线程同步并行处理

from multiprocessing import Process,Queue,shared_memory,Value
import cv2
import numpy as np

class CameraBroadcaster:
    def __init__(self, camera_info):
        self.height = camera_info.get('height', 720)
        self.width = camera_info.get('width', 1280)
        self.fps = camera_info.get('fps', 30)
        self.id = camera_info.get("id",0)
        self.stop_sign = Value(c_bool, False)
        #关键代码,在对象内存中开辟一个空间用于存储图像
        self.frame = shared_memory.SharedMemory(create=True, size=np.zeros(shape=(self.height, self.width, 3),
                                                                           dtype=np.uint8).nbytes)
        self.memory_name = self.frame.name

    def run(self,data_value):
        cap = cv2.VideoCapture(0)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
        sender = np.ndarray((self.height, self.width, 3), dtype=np.uint8, buffer=self.frame.buf)
        print("finish open the camera")

        try:
            while True:
                if self.stop_sign.value:
                    self.frame.close()
                    self.frame.unlink()
                    break               
                ret, frame = cap.read()    
                #将获得的图像,保存在共享内存中
                np.copyto(sender,frame)               
                data_value.value = True
                end2 = datetime.now()               
        except (KeyboardInterrupt, SystemExit):
            # log.info('Cam broadcaster closing')
            self.frame.close()
            self.frame.unlink()

代码测试

def test_multi_camera(camera_info):
    msg_queue = Queue()
    camera = CameraBroadcaster(camera_info)
    data_value = Value('b',False)
    camera_process = Process(target=camera.run,args=(data_value,))    
    camera_process.start()
    print(camera_info)

    while cv2.waitKey(1) == -1:
        # if not data_value.value:
        #     continue
        #
        #必须从camera对象中获取内存,如果有内容,则直接访问,之后边自助释放
        frame = np.ndarray((camera.height, camera.width, 3), dtype=np.uint8, buffer=camera.frame.buf)        
        img = frame.copy()        
        data_value.value = False
    camera_process.join()

下面进行升级,需要将读取的图像放入到缓存buffer中,然后另一个线程就行处理。

import cv2
import numpy as np
from multiprocessing import Queue
from threading import Thread


class BaseThreadedProcess(Thread):
    def __init__(self, queue):
        super(BaseThreadedProcess, self).__init__()
        self.queue = queue

    def run(self):
        raise NotImplementedError("Subclasses must implement the 'run' method.")

class CameraReader(BaseThreadedProcess):
    def __init__(self, queue):
        super(CameraReader, self).__init__(queue)

    def run(self):
        cap = cv2.VideoCapture(0)

        while True:
            ret, frame = cap.read()
            if not ret:
                break
            # 将图像数据放入队列
            self.queue.put(frame)

        cap.release()

class FrameProcessor(BaseThreadedProcess):
    def __init__(self, queue):
        super(FrameProcessor, self).__init__(queue)

    def run(self):
        while True:
            # 从队列中获取图像数据
            frame = self.queue.get()

            # 在这里可以进行任意图像处理操作
            # 这里只是简单地将图像转换为灰度图像
            gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

            # 在这里显示处理后的图像
            cv2.imshow("Processed Frame", gray_frame)

            # 检测键盘输入,按下"q"键退出循环
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        cv2.destroyAllWindows()

if __name__ == "__main__":
    # 创建队列
    frame_queue = Queue()

    # 创建线程,并将共享队列传递给两个线程实例
    camera_reader = CameraReader(frame_queue)
    frame_processor = FrameProcessor(frame_queue)

    # 启动线程
    camera_reader.start()
    frame_processor.start()

    # 等待线程结束
    camera_reader.join()
    frame_processor.join()

重点讲解了线程的继承和队列的使用。