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
相关产品推荐
相关产品推荐

