You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中将多个IP摄像头RTSP流窗口合并为一个?

合并多RTSP摄像头流到单个窗口

问题描述

我正在编写一个安防控制台程序,用来展示多个IP摄像头的RTSP流。目前通过多线程实现了每个流在独立窗口正常播放,但添加多个摄像头后窗口杂乱,希望合并到同一个大窗口。之前尝试用np.hstack合并导致流卡顿,用multiprocessing也因为while循环没成功。

原代码如下:

import cv2
import threading

class camThread(threading.Thread):
    def __init__(self, previewName, camID):
        threading.Thread.__init__(self)
        self.previewName = previewName
        self.camID = camID
    def run(self):
        camPreview(self.previewName, self.camID)

def camPreview(previewName, camID):
    # global frame
    cv2.namedWindow(previewName)
    cam = cv2.VideoCapture(camID)
    if cam.isOpened():  # try to get the first frame
     rval, frame = cam.read()

    else:
        rval = False

    while rval:
        frame = cv2.resize(frame, (620,400))
        cv2.imshow(previewName, frame)
        rval, frame = cam.read()
        cv2.waitKey(20)


thread1 = camThread("Camera 1", 'my-rtsp-link')
thread2 = camThread("Camera 2", "my-second-rtsp-link")
thread1.start()
thread2.start()

解决方案

核心思路是让子线程仅负责捕获摄像头帧,将帧存储到线程安全的共享容器中;主线程负责统一读取所有帧、拼接成网格并显示。这样拆分职责后,既能避免子线程的显示冲突,也能把拼接的负载集中处理,解决之前的卡顿问题。

修改后的代码如下:

import cv2
import threading
import numpy as np

# 存储各摄像头的最新帧,线程安全需要锁保护
camera_frames = {}
frame_lock = threading.Lock()

class camThread(threading.Thread):
    def __init__(self, cam_name, rtsp_url, frame_size=(620, 400)):
        super().__init__()
        self.cam_name = cam_name
        self.rtsp_url = rtsp_url
        self.frame_size = frame_size
        self.running = True

    def run(self):
        cam = cv2.VideoCapture(self.rtsp_url)
        if not cam.isOpened():
            print(f"无法打开摄像头: {self.cam_name}")
            return

        while self.running:
            rval, frame = cam.read()
            if not rval:
                print(f"{self.cam_name} 读取帧失败,尝试重连...")
                cam.release()
                cam = cv2.VideoCapture(self.rtsp_url)
                continue
            
            # 调整帧大小
            frame_resized = cv2.resize(frame, self.frame_size)
            # 线程安全地更新共享帧字典
            with frame_lock:
                camera_frames[self.cam_name] = frame_resized
            
            # 给摄像头读取留一点缓冲时间,避免占用过多CPU
            cv2.waitKey(10)
        
        cam.release()

def main():
    # 配置摄像头列表
    cameras = [
        ("Camera 1", "my-rtsp-link"),
        ("Camera 2", "my-second-rtsp-link")
        # 可以继续添加更多摄像头
    ]

    # 启动所有摄像头线程
    threads = []
    for cam_name, rtsp_url in cameras:
        thread = camThread(cam_name, rtsp_url)
        threads.append(thread)
        thread.start()

    # 主线程负责拼接和显示
    window_name = "安防控制台"
    cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
    cv2.resizeWindow(window_name, 1280, 480)  # 根据摄像头数量调整窗口大小

    try:
        while True:
            with frame_lock:
                # 复制当前所有摄像头的帧,避免读取时被修改
                current_frames = list(camera_frames.values())
            
            if not current_frames:
                cv2.waitKey(20)
                continue
            
            # 拼接帧:这里以横向拼接为例,多摄像头可以改成网格(比如2行2列)
            # 横向拼接
            combined_frame = np.hstack(current_frames)
            # 如果是多行网格,比如2行1列,用np.vstack;如果是2x2,先横向拼每行再纵向拼
            # row1 = np.hstack(current_frames[:2])
            # row2 = np.hstack(current_frames[2:])
            # combined_frame = np.vstack([row1, row2])

            cv2.imshow(window_name, combined_frame)
            
            # 按下q键退出
            if cv2.waitKey(20) & 0xFF == ord('q'):
                break
    finally:
        # 停止所有线程
        for thread in threads:
            thread.running = False
        for thread in threads:
            thread.join()
        
        cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

关键修改说明

  • 线程安全的帧存储:用threading.Lock保护共享字典camera_frames,避免多线程同时读写导致的帧损坏。
  • 职责拆分:子线程只做摄像头帧捕获和更新,不处理显示和拼接;主线程统一处理拼接和显示,避免子线程资源竞争。
  • 重连机制:添加了摄像头读取失败时的重连逻辑,提升稳定性。
  • 灵活拼接:可以根据摄像头数量调整拼接方式(横向、纵向、网格),只需修改combined_frame的生成代码。

内容的提问来源于stack exchange,提问作者saatvik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:31:01