- Python多个网络摄像头拉流
- 拉流后使用PyTorch实现的YOLO v3做对象检测
最后需要运行在ARM架构的Jetson TX 2平台上,并且以海康摄像头作为视频源。
- YOLO v3 implementation: ayooshkathuria/pytorch-yolo-v3
- HIKVISION multiple IP cameras: Yonv1943/Python
同样的拉流代码同样可以复用在EfficientDet、YoloV5等模型上,不过模型需要二次封装。
- EfficientDet implementation: gaodechen/EfficientDet-Webcam
- YoloV5: YoloV5工作对性能的对比缺乏参照,但其实现依旧有启发性。推断前使用DataLoader,故而修改时去掉了拉流取图的进程。
- Intel CPU + NVIDA GPU
- 视频源:RTSP/RTMP网络摄像头
- clone ayooshkathuria/pytorch-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图像
系统默认给出了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 TX2 ARM
- 操作系统:Ubuntu 18.04
- 视频源: 多个海康网络摄像头(RTSP TCP)
git clone --recursive
以及compile太耗时了!而且板子上网速也慢,读写也慢。好在最终找到了可以用的whl安装包,直接pip install
一次成功。
- PyTorch .whl downloading & installation on Jetson TX2: Nvidia Forum