利用 Video infer 服务实现摄像头图像采集与 AI 模型推断
声明:
- 本文测试所用设备系统为 Ubuntu 18.04
- 本文测试所用摄像头为海康威视 IP 网络摄像头,其型号为 DS-IPC-B12-1
- 本文测试的 AI 推断跑在 CPU 使用官方的 video-infer 模块
- 本文测试采用的 AI 模型为 ssd_mobilenet_v1_coco_2017_11_17
- 模拟 MQTT client 向本地 Hub 服务发送消息的客户端为 MQTTBox
操作流程
- 步骤 1:在 Ubuntu18.04 上安装 Baetyl,相关内容可参考 快速安装 Baetyl
- 步骤 2:依据本文测试需求,撰写各服务的配置文件,然后执行
sudo systemctl start baetyl
命令启动 Baetyl 服务,可以通过sudo systemctl status baetyl
命令查看 Baetyl 服务的运行情况,关于各服务的配置情况请参考下文 各服务配置 - 步骤 3:根据 Hub 服务的配置信息对 MQTTBox 进行连接配置,确保 MQTTBox 与 Hub 服务建立连接,更多可参考 与 Hub 服务建立连接
- 步骤 4:MQTTBox 订阅主题
video/infer/result
,观察其是否能够正常接收到模型的推断结果消息。上述步骤的操作流程示意图如下图所示。
利用 video-infer 服务进行视频采集和 AI 模型推断
各服务配置
Baetyl 主程序的配置文件位置 var/db/baetyl/application.yml
,配置信息如下:
- version: V0
- services:
- - name: localhub
- image: 'hub.baidubce.com/baetyl/baetyl-hub:latest'
- replica: 1
- ports:
- - '1883:1883'
- mounts:
- - name: localhub-conf
- path: etc/baetyl
- readonly: true
- - name: localhub-persist-data
- path: var/db/baetyl/data
- - name: demo-log
- path: var/log/baetyl
- - name: function-manager
- image: 'hub.baidubce.com/baetyl/baetyl-function-manager:latest'
- replica: 1
- mounts:
- - name: function-manager-conf
- path: etc/baetyl
- readonly: true
- - name: demo-log
- path: var/log/baetyl
- - name: function-python
- image: 'hub.baidubce.com/baetyl/baetyl-function-python36:0.1.6-opencv41'
- replica: 0
- mounts:
- - name: function-python-conf
- path: etc/baetyl
- readonly: true
- - name: function-python-code
- path: var/db/baetyl/code
- readonly: true
- - name: image-data
- path: var/db/baetyl/image
- - name: video-infer
- image: 'hub.baidubce.com/baetyl-beta/baetyl-video-infer:latest'
- replica: 1
- mounts:
- - name: infer-person-model
- path: var/db/baetyl/model
- readonly: true
- - name: image-data
- path: var/db/baetyl/image
- - name: demo-log
- path: var/log/baetyl
- - name: video-infer-conf
- path: etc/baetyl
- readonly: true
- volumes:
- - name: localhub-conf
- path: var/db/baetyl/localhub-conf
- - name: localhub-persist-data
- path: var/db/baetyl/localhub-persist-data
- - name: demo-log
- path: var/db/baetyl/demo-log
- - name: function-manager-conf
- path: var/db/baetyl/function-manager-conf
- - name: function-python-conf
- path: var/db/baetyl/function-python-conf
- - name: function-python-code
- path: var/db/baetyl/function-python-code
- - name: image-data
- path: var/db/baetyl/image-data
- - name: remote-mqtt-conf
- path: var/db/baetyl/remote-mqtt-conf
- - name: infer-person-model
- path: var/db/baetyl/infer-person-model
- - name: video-infer-conf
- path: var/db/baetyl/video-infer-conf
Hub 服务配置文件位置 var/db/baetyl/localhub-conf/service.yml
,配置信息如下:
- listen:
- - tcp://0.0.0.0:1883
- principals:
- - username: test
- password: hahaha
- permissions:
- - action: 'pub'
- permit: ['#']
- - action: 'sub'
- permit: ['#']
- logger:
- path: var/log/baetyl/localhub-service.log
- level: "debug"
Function manager 服务配置文件位置 var/db/baetyl/function-manager-conf/service.yml
,配置信息如下:
- server:
- address: 0.0.0.0:50051
- hub:
- address: tcp://localhub:1883
- username: test
- password: hahaha
- functions:
- - name: analyse
- service: function-python
- instance:
- max: 10
- logger:
- path: var/log/baetyl/func-service.log
- level: "debug"
Function python 服务配置文件位置 var/db/baetyl/function-python-conf/service.yml
,配置信息如下:
- functions:
- - name: 'analyse'
- handler: 'analyse.handler'
- codedir: 'var/db/baetyl/code'
- logger:
- path: "var/log/baetyl/python-service.log"
- level: "debug"
Video infer 服务配置文件位置 var/db/baetyl/video-infer-conf/service.yml
,配置信息如下:
- hub:
- address: tcp://localhub:1883
- username: test
- password: hahaha
- video:
- uri: "rtsp://admin:admin@192.168.1.2:554/Streaming/channels/1/"
- limit:
- fps: 1
- infer:
- model: var/db/baetyl/model/frozen_inference_graph.pb
- config: var/db/baetyl/model/ssd_mobilenet_v1_coco_2017_11_17.pbtxt
- process:
- before:
- swaprb: true
- width: 300
- hight: 300
- after:
- function:
- name: analyse
- functions:
- - name: analyse
- address: function-manager:50051
- logger:
- path: var/log/baetyl/infer-service.log
- level: "debug"
需要注意的是,这里 uri
配置代表的是 IP 网络摄像头的地址,其通用格式为 rtsp://<username>:<password>@<ip>:<port>/Streaming/channels/<stream_number>
,其中,<username>
和 <password>
为激活成功后的 IP 摄像头的登录认证口令,<ip>
为该摄像头的IP地址,<port>
为 RTSP 协议的端口号,默认为 554,后面内容为信道,其中 <stream_number>
为 1 代表抓取主码流,为 2 代表抓取次码流。
此外,Video infer 服务除支持抓取 IP 网络摄像头图片信息外,还支持抓取 USB 摄像头采集图像信息和读取视频文件进行抽帧。相应地,若为 USB 摄像头,则 uri
配置为设备编号,通用性配置为 “0”,同时需要将设备地址 /dev/video0
映射进容器;若配置读取视频文件进行抽帧,则直接配置 uri
内容为视频文件的地址,同时将该视频文件以(自定义)存储卷形式挂载到 Video infer 服务即可,更多关于存储卷的内容可以参考 如何正确地引入存储卷。
Video infer 服务捕获 USB 摄像头采集图像配置可参考:
- video:
- uri: "0"
- limit:
- fps: 1
同时在 application.yml
配置中将 /dev/video0
设备地址映射到容器中,相关配置可参考:
- version: V0
- services:
- - name: video-infer
- image: 'hub.baidubce.com/baetyl-beta/baetyl-video-infer:latest'
- replica: 1
- devices:
- - /dev/video0 # 将 USB 设备映射进容器
- mounts:
- - name: infer-person-model
- path: var/db/baetyl/model
- readonly: true
- - name: image-data
- path: var/db/baetyl/image
- - name: demo-log
- path: var/log/baetyl
- - name: video-infer-conf
- path: etc/baetyl
- readonly: true
不难发现,从容器内读取宿主机的 USB 、串口等设备,均可采用上述设备映射的方式配置。
测试及验证
如本文开头所述,本次测试我们采用 ssd_mobilenet_v1_coco_2017_11_17
模型,该模型可用于检测人、水果等多达 90 项物品。这里,我们给出用于检测人的 Python 脚本仅供参考,具体如下:
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- """
- function to analyse video infer result in python
- """
- import numpy as np
- location = "var/db/baetyl/image/{}.jpg"
- classes = {
- 1: 'person'
- }
- def handler(event, context):
- """
- function handler
- """
- data = np.fromstring(event, np.float32)
- mat = np.reshape(data, (-1, 7))
- objects = []
- scores = {}
- for obj in mat:
- clazz = int(obj[1])
- if clazz in classes:
- score = float(obj[2])
- if classes[clazz] not in scores or scores[classes[clazz]] < score:
- scores[classes[clazz]] = score
- if score < 0.6:
- continue
- objects.append({
- 'class': classes[clazz],
- 'score': score,
- 'left': float(obj[3]),
- 'top': float(obj[4]),
- 'right': float(obj[5]),
- 'bottom': float(obj[6])
- })
- res = {}
- res["imageDiscard"] = len(objects) == 0
- res["imageObjects"] = objects
- res["imageScores"] = scores
- res["publishTopic"] = "video/infer/result"
- res["messageTimestamp"] = int(context["messageTimestamp"]/1000000)
- if len(objects) != 0:
- res["imageLocation"] = location.format(context["messageTimestamp"])
- return res
若检测其他物品,直接在这里添加或修改即可,可支持检测物品列表参考 mscoco_label_map。
一切就绪后,启动 Baetyl 服务,然后通过 sudo systemctl status baetyl
或 docker ps
命令查看 Baetyl 服务的运行状态及正在运行的容器列表。
Baetyl 服务运行情况
正在运行的容器列表
可以发现,Baetyl 服务处于 active (running)
状态,系统现在正在运行了 baetyl-hub
、baetyl-video-infer
、baetyl-function-manager
及 baetyl-function-python36
四个容器。
然后,我们启动 MQTTBox,根据 Hub 服务配置完连接信息后,可以发现 MQTTBox 已经与 Hub 服务建立连接。
MQTTBox 与 Hub 服务建立连接
然后,通过 MQTTBox 订阅主题 video/infer/result
,若服务运行正常,则 MQTTBox 会收到消息。
MQTTBox 接收消息,未检测到人
MQTTBox 接收消息,检测到人
如上所示,MQTTBox 通过订阅主题 video/infer/result
正确收到了消息。对比上述两条消息,可以发现一个检测到了人,一个未检测到人,如果模型检测到了人,则会在接收到的信息中给出类别 class
类别信息,同时给出检测到的人在捕获图片中的位置信息,可以用于后续的画框标记操作,感兴趣的可以参考 代码。
至此,我们已经基于 Video infer 服务实现了 IP 网络摄像头图像的采集和 AI 模型的推断。