Introduction
Python多个网络摄像头拉流
拉流后使用PyTorch实现的YOLO v3做对象检测
最后需要运行在ARM架构的Jetson TX 2平台上,并且以海康摄像头作为视频源。
HIKVISION multiple IP cameras: Yonv1943/Python
配合其他模型
同样的拉流代码同样可以复用在EfficientDet、YoloV5等模型上,不过模型需要二次封装。
YoloV5: YoloV5工作对性能的对比缺乏参照,但其实现依旧有启发性。推断前使用DataLoader,故而修改时去掉了拉流取图的进程。
测试环境
Intel CPU + NVIDA GPU
视频源:RTSP/RTMP网络摄像头
使用
多网络摄像头拉流 + YOLO v3对象检测
下载YOLO v3预训练模型yolov3.weights
将本项目文件覆盖放入pytorch-yolo-v3文件夹当中
修改settings.py,加入你的摄像头地址
运行:
python run.py # Default detect and display all cameras in one window
python run.py --single_window=False # OR Detect and display in separate windows
single_window默认为True,表示所有画面合并显示到同一个窗口当中
num_cameras默认值为settings.py中的IP列表大小,表示处理所有给定摄像头
仅多摄像头拉流
去掉predict()进程的调用,并且pop_image()显示raw_q中的原图像。也就是说拉流取得的图像直接取出进行显示。
processes = [
mp.Process(target=push_image, args=(raw_q, cam_addr)),
# display images in raw_q instead
mp.Process(target=pop_image, args=(raw_q, window_name)),
]
帧率
摄像头本身具有帧率,而模型检测也存在帧率。摄像头帧率可以通过cv2属性获取:
fps = cap.get(cv2.CAP_PROP_FPS)
另外此处我们采用的帧率计算方法是,直接使用predict()进程的推断时间来计算帧率,此方法包含的耗时,包含队列取图时阻塞的时间,以及模型推断时间。
文件结构
本程序文件当中主要如下:
settings.py:配置IP camera地址列表,画面大小
yolov3.py:pytorch-yolo-v3模型推断的二次封装,不需要变动
preprocess.py:与pytorch-yolo-v3相比,只是添加了prep_frame函数,将图片输入从文件改为cv2图像
其他细节
OpenCV后端选择
系统默认给出了GStreamer进行后端解码。这里我们改为FFMPEG作为后端:
cap = cv2.VideoCapture(cam_addr, cv2.CAP_FFMPEG)
多个网络摄像头如何拉流?
Yonv1943/Python项目当中已经给出了很棒的解答。我们在此基础上进行修改。
考虑对于一个摄像头,由于H.264编码的问题使用多进程实现,多进程间的同步采用共享队列(multiprocessing.Queue)。
push_image(): 拉流,将图片送入raw_queue(未经推断的图片队列)
predict(): 将raw_queue中的图片取出,经模型推断放进pred_queue()(处理后的图片队列)
pop_image(): 将pred_queue中的图片通过OpenCV显示
总结起来,导致程序崩溃的原因可能有:
推断速度慢,与拉流速度不一致: 即进程同步问题。raw_queue当中累积图片多,延时高,甚至队列溢出程序崩溃
网络原因: 断流导致程序崩溃
机器硬件性能不足: 导致创建某些进程失败
最初代码中,作者通过push_image()进程不断抛弃队首图片解决同步问题。
但是实验过程中,程序还会因为断流的原因产生崩溃,故而这里加入重连,得到最终能够长时间稳定运行的push_image()如下:
def push_image(raw_q, cam_addr):
cap = cv2.VideoCapture(cam_addr, cv2.CAP_FFMPEG)
while True:
is_opened, frame = cap.read()
if is_opened:
raw_q.put(frame)
else:
# reconnect
cap = cv2.VideoCapture(cam_addr, cv2.CAP_FFMPEG)
if raw_q.qsize() > 1:
# drop old images
raw_q.get()
else:
# wait for streaming
time.sleep(0.01)
经过上述修改可以长时间稳定运行,缺点是断流时重连耗时,画面卡顿1s左右。
此外,在NVIDIA Jetson TX2上运行时,出现了程序启动后,无法加载几个摄像头画面的问题,例如分开窗口显示时,有一两个摄像头的窗口一直没有创建。但是程序在本地却正常运行。
最后观察发现,由于Jetson TX2内存不足,导致进程无法创建。解决方法:创建内存交换区。目测4个海康摄像头进行YOLO对象检测时,6G交换区足够。
Jetson TX 2 ARM
运行环境
硬件平台: Jetson TX2 ARM
操作系统:Ubuntu 18.04
视频源: 多个海康网络摄像头(RTSP TCP)
Jetson TX2 ARM PyTorch环境的搭建
git clone --recursive以及compile太耗时了!而且板子上网速也慢,读写也慢。好在最终找到了可以用的whl安装包,直接pip install一次成功。
PyTorch .whl downloading & installation on Jetson TX2: Nvidia Forum