参考原文:读取多个(海康大华)网络摄像头的视频流 (使用opencv-python),解决实时读取延迟问题 - 2019.11.19

作者:曾伊言

作用:实时读取多个网络摄像头 rtsp 或 rtmp 流

Python 实现:

import time
import multiprocessing as mp
import cv2


def image_put(q, rtsp):
    #cap = cv2.VideoCapture("rtsp://xxxx")
    cap = cv2.VideoCapture(rtsp)
    if cap.isOpened():
        print('True')
    else:
        pass

    while True:
        q.put(cap.read()[1])
        q.get() if q.qsize() > 1 else time.sleep(0.01)


def image_get(q, window_name):
    cv2.namedWindow(window_name, flags=cv2.WINDOW_FREERATIO)
    while True:
        frame = q.get()
        cv2.imshow(window_name, frame)
        cv2.waitKey(1)


def run_opencv_camera():
    cap_path = 0  # local camera
    # cap_path = 'video.avi'  # the path of video file
    # cap_path = "rtsp://xxx"

    cap = cv2.VideoCapture(cap_path)

    while cap.isOpened():
        is_opened, frame = cap.read()
        cv2.imshow('frame', frame)
        cv2.waitKey(1000)
    cap.release()


def run_single_camera(rtsp, camera_ip='192.168.1.111'):
    mp.set_start_method(method='spawn')  # init
    queue = mp.Queue(maxsize=2)
    processes = [
        mp.Process(target=image_put, args=(queue, rtsp)),
        mp.Process(target=image_get, args=(queue, camera_ip))]

    [process.start() for process in processes]
    [process.join() for process in processes]


def run_multi_camera():
    camera_ip_l = ["rtsp://1_xxxx",
                   "rtsp://2_xxxx"]

    mp.set_start_method(method='spawn')  # init
    queues = [mp.Queue(maxsize=4) for _ in camera_ip_l]

    processes = []
    for queue, rtsp in zip(queues, camera_ip_l):
        processes.append(mp.Process(target=image_put, args=(queue, rtsp)))
        processes.append(mp.Process(target=image_get, args=(queue, rtsp)))

    for process in processes:
        process.daemon = True
        process.start()
    for process in processes:
        process.join()


def image_collect(queue_list, camera_ip_l):
    import numpy as np

    """
    show in single opencv-imshow window
    """
    window_name = "single_opencv_imshow_window"
    cv2.namedWindow(window_name, flags=cv2.WINDOW_FREERATIO)
    while True:
        imgs = [q.get() for q in queue_list]
        imgs = np.concatenate(imgs, axis=1)
        cv2.imshow(window_name, imgs)
        cv2.waitKey(1)

    # """show in multiple opencv-imshow windows"""
    # [cv2.namedWindow(window_name, flags=cv2.WINDOW_FREERATIO)
    #  for window_name in camera_ip_l]
    # while True:
    #     for window_name, q in zip(camera_ip_l, queue_list):
    #         cv2.imshow(window_name, q.get())
    #         cv2.waitKey(1)


def run_multi_camera_in_a_window():
    camera_ip_l = ["rtsp://1_xxxx",
                   "rtsp://2_xxxx"]

    mp.set_start_method(method='spawn')  # init
    queues = [mp.Queue(maxsize=4) for _ in camera_ip_l]

    processes = [mp.Process(target=image_collect, args=(queues, camera_ip_l))]
    for queue, rtsp in zip(queues, camera_ip_l):
        processes.append(mp.Process(target=image_put, args=(queue, rtsp)))

    for process in processes:
        process.daemon = True  # setattr(process, 'deamon', True)
        process.start()
    for process in processes:
        process.join()


def run():
    # run_opencv_camera()  # slow, with only 1 thread
    run_single_camera(rtsp)  # quick, with 2 threads
    # run_multi_camera() # with 1 + n threads
    # run_multi_camera_in_a_window()  # with 1 + n threads
    pass


if __name__ == '__main__':
    run()

其中,解决实时读取延迟卡顿的关键代码如下,采用 python 自带的多线程队列:

import multiprocessing as mp


img_queues = [mp.Queue(maxsize=2) for _ in camera_ip_l]  #queue

q.put(frame) if is_opened else None  # 线程A不仅将图片放入队列
q.get() if q.qsize() > 1 else time.sleep(0.01) #线程A还负责移除队列中的旧图
Last modification:October 20th, 2020 at 05:08 pm