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

IP摄像头图像捕获:异常处理失效,摄像头断开后无法重连

实现IP摄像头断开自动重连的修改方案

原代码在摄像头断开后,读取线程会直接终止,主循环里的cap1.read()会一直阻塞在队列获取操作,既不会报错也不会尝试重连。以下是修改后的完整代码,加入了自动重连机制:

import csv
import cv2
import time
import queue
import threading
import requests.exceptions
from time import sleep
import requests

# 读取摄像头配置
with open('bin/Load/option_1.csv', encoding="utf-8") as option1:
    reader = csv.reader(option1)
    option1 = list(reader)
    ipcam1 = option1[0][0]
    camUser1 = option1[1][0]
    camPass1 = option1[2][0]

class VideoCapture:
    def __init__(self, name):
        self.url = name
        self.cap = None
        self.q = queue.Queue(maxsize=1)  # 限制队列大小,避免内存占用过高
        self.running = True
        self._connect()
        t = threading.Thread(target=self._reader)
        t.daemon = True
        t.start()

    def _connect(self):
        """尝试连接摄像头"""
        if self.cap is not None:
            self.cap.release()
        self.cap = cv2.VideoCapture(self.url)
        # 检查是否连接成功
        if not self.cap.isOpened():
            raise ConnectionError(f"无法连接到摄像头: {self.url}")
        print("摄像头连接成功")

    def _reader(self):
        while self.running:
            if self.cap is None or not self.cap.isOpened():
                # 尝试重连
                try:
                    print("尝试重新连接摄像头...")
                    self._connect()
                except Exception as e:
                    print(f"重连失败: {str(e)}")
                    sleep(4)  # 等待4秒后重试
                    continue
            
            ret, frame = self.cap.read()
            if not ret:
                print("摄像头读取失败,准备重连")
                self.cap.release()
                self.cap = None
                sleep(2)
                continue
            
            # 只保留最新一帧
            if not self.q.empty():
                try:
                    self.q.get_nowait()
                except queue.Empty:
                    pass
            self.q.put(frame)

    def read(self, timeout=5):
        """读取帧,带超时机制"""
        try:
            return self.q.get(timeout=timeout)
        except queue.Empty:
            raise TimeoutError("读取帧超时,摄像头可能断开")

# 初始化摄像头
url1 = f'rtsp://{camUser1}:{camPass1}@{ipcam1}:554/Streaming/channels/1/'
cap1 = None
try:
    cap1 = VideoCapture(url1)
except Exception as e:
    print(f"初始连接失败: {str(e)}")

# 主循环
while True:
    try:
        if cap1 is None:
            # 初始连接失败后尝试重连
            try:
                cap1 = VideoCapture(url1)
            except Exception as e:
                print(f"初始重连失败: {str(e)}")
                sleep(4)
                continue
        
        sleep(0.18)
        frame = cap1.read()
        
        # 读取裁剪配置(建议把这部分移到循环外,避免重复IO)
        with open("tools/croping_image_1.csv", newline="", encoding="utf-8") as cropi1:
            reader = csv.reader(cropi1)
            cropi1 = list(reader)
        frame = frame[int(cropi1[0][0]):int(cropi1[1][0]), int(cropi1[2][0]):int(cropi1[3][0])]
        
        cv2.imwrite("screen1.jpg", frame)

    except TimeoutError:
        print("摄像头读取超时")
        sleep(2)
    except ConnectionError as e:
        print(f"摄像头连接错误: {str(e)}")
        sleep(4)
    except Exception as e:
        print(f"其他错误: {str(e)}")
        sleep(2)

关键改动说明:

  • 添加重连逻辑:在_reader线程中,当摄像头读取失败或连接断开时,自动调用_connect方法尝试重新连接,失败后等待一段时间重试
  • 队列超时机制:read方法加入超时参数,避免摄像头断开后主循环一直阻塞在队列获取操作
  • 连接状态检查:每次读取前检查摄像头是否处于打开状态,确保连接有效性
  • 资源释放:断开连接时释放旧的VideoCapture实例,避免资源泄漏
  • 异常捕获优化:捕获更多类型的异常,包括读取超时、连接错误等,确保程序不会意外终止

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 14:29:09