前言:最近在做YOLO项目到时候,读取网络摄像头流的时候,由于网络的原因,总是发生断流的现象,导致程序奔溃,认真分析源码后,发现作者在开始读取摄像头的时候用的是LoadStreams,用于多路视频同时检测;但在utils包下,发现LoadWebcam类,是用于读取单路的摄像头,但启动不了,经过认知分析修改了一下,成功的启用LoadWebcam类来检测rtsp流,并为其添加了防止断流的机制,具体的教程如下:
class LoadWebcam: # for inference
def __init__(self, pipe='0', img_size=640, stride=32):
self.img_size = img_size
self.stride = stride
if pipe.isnumeric():
pipe = eval(pipe) # local camera
# pipe = 'rtsp://192.168.1.64/1' # IP camera
# pipe = 'rtsp://username:[email protected]/1' # IP camera with login
# pipe = 'http://wmccpinetop.axiscam.net/mjpg/video.mjpg' # IP golf camera
self.pipe = pipe
self.cap = cv2.VideoCapture(pipe) # video capture object
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # set buffer size
def __iter__(self):
self.count = -1
return self
def __next__(self):
self.count += 1
if cv2.waitKey(1) == ord('q'): # q to quit
self.cap.release()
cv2.destroyAllWindows()
raise StopIteration
# Read frame
if self.pipe == 0: # local camera
ret_val, img0 = self.cap.read()
img0 = cv2.flip(img0, 1) # flip left-right
else: # IP camera
n = 0
while True:
n += 1
self.cap.grab()
if n % 30 == 0: # skip frames
ret_val, img0 = self.cap.retrieve()
if ret_val:
break
# Print
assert ret_val, f'Camera Error {self.pipe}'
img_path = 'webcam.jpg'
print(f'webcam {self.count}: ', end='')
# Padded resize
img = letterbox(img0, self.img_size, stride=self.stride)[0]
# Convert
img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
img = np.ascontiguousarray(img)
return img_path, img, img0, None
def __len__(self):
return 0
class LoadWebcam_web: # for inference
def __init__(self, pipe='0', img_size=640, stride=32):
self.mode = 'video' # 配合5.0的loadwebcam新加的东西
self.img_size = img_size
self.stride = stride
if pipe.isnumeric():
pipe = eval(pipe) # local camera
# pipe = 'rtsp://192.168.1.64/1' # IP camera
# pipe = 'rtsp://username:[email protected]/1' # IP camera with login
# pipe = 'http://wmccpinetop.axiscam.net/mjpg/video.mjpg' # IP golf camera
self.pipe = pipe
self.cap = cv2.VideoCapture(pipe) # video capture object
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # set buffer size
def __iter__(self):
self.count = -1
return self
def __next__(self):
self.count += 1
if cv2.waitKey(1) == ord('q'): # q to quit
self.cap.release()
cv2.destroyAllWindows()
raise StopIteration
# Read frame
if self.pipe == 0: # local camera
ret_val, img0 = self.cap.read()
img0 = cv2.flip(img0, 1) # flip left-right
else: # IP camera
n = 0
while True:
n += 1
self.cap.grab()
if n % 4 == 0: # skip frames 抽帧检测,每1帧或者每4帧检测一次!
ret_val, img0 = self.cap.retrieve()
# ret_val 是控制图片的标志,图片如果正确的放回来的话,是true,如果没有获取图片则是false
if not ret_val:
# print("aaaaaaaaaaaa")
print("发生了断流")
self.cap.release() # 发生断流以后,释放掉摄像头
self.cap = cv2.VideoCapture(self.pipe) # 重新连接摄像头
ret_val, img0 = self.cap.retrieve() # 重新读取视频帧
print("重新进行了连接")
else:
break
# Print
assert ret_val, f'Camera Error {self.pipe}'
img_path = 'webcam.jpg'
print(f'webcam {self.count}: ', end='')
# Padded resize
img = letterbox(img0, self.img_size, stride=self.stride)[0]
# Convert
img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
img = np.ascontiguousarray(img)
return img_path, img, img0, None
def __len__(self):
return 0
对比LoadWebcam类和LoadWebcam_web类可以发现修改了2处:
from utils.datasets import LoadStreams, LoadImages,LoadWebcam,LoadWebcam_web
总结:
使用前需要在detect1.2.py文件中导入LoadWebcam_web类;并在Process detections的时候修改一下代码:
将 p, s, im0, frame = path[i], '%g: ’ % i, im0s[i].copy(), dataset.count
换成:(目的是为了保证LoadWebcam_web的正常运行,不然是花屏)
p, s, im0, frame = path, ‘’, im0s, getattr(dataset, ‘frame’, 0):