- 资产集市
- 教学
- 实践
- AI说
- 案例库
- 生态合作
- 专区
中国站
简体中文发布于30个月以前
本文将使用ModelBox
开发一个简单的视频应用:读取摄像头,解码出视频帧,再输出原始画面到本地屏幕。读者将了解到ModelBox
应用开发的基本流程和应用的基本结构。
ModelBox
采用Pipeline模式开发和运行AI应用,这与我们熟悉的开发方式是不同的。例如,对于上面介绍的应用:读取摄像头并输出原始画面,如果采用Python + OpenCV,代码如下:
import cv2
# 初始化摄像头,参数0表示设备的第一个摄像头
cap = cv2.VideoCapture(0)
# 判断初始化是否成功
if not cap.isOpened():
print('failed to open camera 0')
exit()
while True:
# 读取一帧视频图像,ret表示读取是否成功
ret, frame = cap.read()
# 打开一个名为camera_test的窗口,显示图像
cv2.imshow('camera_test', frame)
# 阻塞等待键盘响应1ms,如果按下q键则跳出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头资源
cap.release()
# 关闭所有窗口
cv2.destroyAllWindows()
这个应用在运行时包含下面几个步骤:
可以看到,在传统的开发方式中,应用的每个步骤对应一段代码块或者几个函数调用,开发者通过代码将所有步骤串联起来,自行控制应用的入口和完整流程。
这个应用如果使用ModelBox
进行开发,包括如下几个开发步骤:
也就是说,ModelBox
的Pipeline模式,首先需要将应用的流程图构建出来,再分别实现图中的每个模块(ModelBox
中称为“功能单元”),对于上面的视频应用:读取摄像头并输出原始画面,对应的ModelBox
流程图如下所示:
可以看到,Pipeline模式就像一个流水线,将复杂的数据处理过程分为多个功能单元,通过预先设定好的流程来处理输入的数据,每个功能单元的输出即是下一个功能单元的输入。开发者要做的是定义流程图和实现其中的每个功能单元,之后应用的运行将由框架来调度。在Pipeline模式下,每个功能单元支持并行处理,从而实现高效的数据处理。
接下来我们给出该应用在ModelBox
中的完整开发过程:
在ModelBox
sdk目录下使用create.bat
创建camera_test
工程
PS ███> .\create.bat -t server -n camera_test
sdk version is modelbox-xxx
success: create camera_test in ███\modelbox\workspace
create.bat
工具的参数中,-t
表示所创建实例的类型,包括server
(ModelBox
工程)、python
(Python功能单元)、c++
(C++功能单元)、infer
(推理功能单元)等;-n
表示所创建实例的名称,开发者自行命名。
如果是第一次创建工程,在ModelBox
sdk目录下,将会自动生成workspace
文件夹,此文件夹将作为ModelBox
应用的默认目录。workspace
目录下会创建出camera_test
工程,工程目录结构如下所示:
[project_name]
|--bin
| |--main.bat:应用执行入口(如果是Linux系统,入口是main.sh)
| |--mock_task.toml:应用在本地执行时的输入输出配置,目前支持本地视频文件、本地摄像头、网络摄像头等输入源,本地视频文件、本地屏幕、rtsp视频流等输出
|--CMake:存放一些自定义CMake函数
|--data:存放应用运行所需要的图片、视频、文本、配置等数据
|--dependence
| |--modelbox_requirements.txt:应用运行依赖的外部库在此文件定义
|--etc
| |--flowunit:应用所需的功能单元存放在此目录
| | |--cpp:存放自定义的C++功能单元编译后的动态链接库
| | |--[flowunit_name1]:自定义的Python功能单元目录
| | |--[flowunit_name2]:自定义的Python功能单元目录
| | |-- ...
|--flowunit_cpp:存放C++功能单元的源代码
| |--[flowunit_name3]:自定义的C++功能单元目录
| |--[flowunit_name4]:自定义的C++功能单元目录
| |-- ...
|--graph:存放流程图,其中默认流程图与工程同名
| |--[project_name].toml:与工程同名的默认流程图
| |--modelbox.conf:modelbox相关配置
|--hilens_data_dir:存放应用输出的结果文件、日志、性能统计信息
|--model:推理功能单元目录
| |--[flowunit_name5]:推理功能单元目录
| |--[flowunit_name6]:推理功能单元目录
| |-- ...
|--build_project.sh:应用构建脚本
|--CMakeLists.txt
|--rpm:打包rpm时生成的目录,将存放rpm包所需数据
|--rpm_copyothers.sh:rpm打包时的辅助脚本
camera_test
工程graph
目录下默认生成了一个与工程同名的camera_test.toml
流程图,将其内容修改为(以Windows版ModelBox
为例):
# Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
[driver]
# 功能单元的扫描路径,包含在[]中,多个路径使用,分隔
# ${HILENS_APP_ROOT} 表示当前应用的实际路径
# ${HILENS_MB_SDK_PATH} 表示ModelBox核心库的实际路径
dir = [
"${HILENS_APP_ROOT}/etc/flowunit",
"${HILENS_APP_ROOT}/etc/flowunit/cpp",
"${HILENS_APP_ROOT}/model",
"${HILENS_MB_SDK_PATH}/flowunit",
]
skip-default = true
[profile]
# 通过配置profile和trace开关启用应用的性能统计
profile = false # 是否记录profile信息,每隔60s记录一次统计信息
trace = false # 是否记录trace信息,在任务执行过程中和结束时,输出统计信息
dir = "${HILENS_DATA_DIR}/mb_profile" # profile/trace信息的保存位置
[flow]
desc = "camera example for modelbox" # 应用的简单描述
[graph]
format = "graphviz" # 流程图的格式,当前仅支持graphviz
graphconf = """digraph camera_test {
node [shape=Mrecord]
queue_size = 1
batch_size = 1
# 定义节点,即功能单元及其属性
input1[type=input, flowunit=input, device=cpu, deviceid=0]
data_source_parser2[type=flowunit, flowunit=data_source_parser, device=cpu, deviceid=0]
local_camera3[type=flowunit, flowunit=local_camera, device=cpu, deviceid=0, pix_fmt="bgr", cam_width=1280, cam_height=720]
video_out4[type=flowunit, flowunit=video_out, device=cpu, deviceid=0]
# 定义边,即功能间的数据传递关系
input1:input -> data_source_parser2:in_data
data_source_parser2:out_video_url -> local_camera3:in_camera_packet
local_camera3:out_camera_frame -> video_out4:in_video_frame
}"""
ModelBox
使用TOML语法编写各类配置文件,在流程图的toml文件中,包含如下部分:
ModelBox
核心库中内置的功能单元、该应用添加的Python功能单元、C++功能单元(动态链接库)、推理功能单元等ModelBox
流程图的描述采用Graphviz DOT语法表达,关于DOT语法,可以查看Graphviz DOT的指导。流程图的描述主要包括节点和边的定义,格式如下:
node_name[type=flowunit, flowunit=flowunit_name, key=value]
其中,node_name
为节点名称,可自行定义;key
为节点的配置属性,每个节点不同,value
为属性值,常用属性包括节点运行的设备和设备编号(device
/deviceid
)、batch_size
/queue_size
(也可以在图中定义全局batch_size
/queue_size
)等;type
参数指定节点类型,可以是input
(整个路程图的输入端口), output
(整个路程图的输出端口), flowunit
(功能单元,配合flowunit=xxx
指定该功能单元的执行实体),若未指定默认为flowunit
。可以理解为其中配置的flowunit_name
是功能单元类名称,node_name
是功能单元实例名称。
flowunit_name1:out_port -> flowunit_name2:in_port
其中,flowunit_name1
/flowunit_name2
为需要连接的两个节点的名称,out_port
为前一个节点的输出端口名称,in_port
为后一个节点的输入端口名称。
本应用的graph
描述即对应本章开头给出的流程图,其中使用了如下4个ModelBox
内置的输入端口/功能单元:
ModelBox
默认的流程图输入端口,用于接收图外部的输入配置,每个流程图都应该以该节点开始bin/mock_task.toml
文件中的输入配置,通过HiLens
部署运行时可解析HiLens
控制台上配置的输入源(后面教程中会介绍)pix_fmt
)、图像宽高(cam_width
/cam_height
)等bin/mock_task.toml
文件中的输出配置指定,通过HiLens
部署运行时通过HiLens
控制台上配置的输出指定(后面教程中会介绍)camera_test
应用只需要ModelBox
内置的功能单元,无需开发者另外开发其他功能单元,后面的教程将会介绍如何自定义功能单元。
本应用需要打开PC自带摄像头,解码出视频帧并输出到本地屏幕,我们打开工程目录下bin/mock_task.toml
文件,修改其中的任务输入和任务输出配置为如下内容:
# 任务输入配置,mock模拟目前仅支持一路rtsp或者本地url, 当前支持以下几种输入方式:
# 1. rtsp摄像头或rtsp视频流:type="rtsp", url="rtsp://xxx.xxx" (type为rtsp的时候,支持视频中断自动重连)
# 2. 设备自带摄像头或者USB摄像头:type="url",url="摄像头编号" (比如 0 或者 1 等,需配合local_camera功能单元使用)
# 3. 本地视频文件:type="url",url="视频文件路径" (请使用${HILENS_APP_ROOT}宏,表示当前应用的实际路径)
# 4. http服务:type="url", url="http://xxx.xxx"(指的是任务作为http服务启动,此处需填写对外暴露的http服务地址,需配合httpserver类的功能单元使用)
[input]
type = "url"
url = "0" # 表示0号摄像头,即PC自带摄像头,若PC无摄像头需外接USB摄像头
# 任务输出配置,当前支持以下几种输出方式:
# 1. rtsp视频流:type="local", url="rtsp://xxx.xxx"
# 2. 本地屏幕:type="local", url="0:xxx" (设备需要接显示器,系统需要安装桌面)
# 3. 本地视频文件:type="local",url="视频文件路径" (请使用${HILENS_APP_ROOT}宏,表示当前应用的实际路径)
# 4. http服务:type="webhook", url="http://xxx.xxx" (指的是任务产生的数据上报给某个http服务,此处需填写上传的http服务地址)
[output]
type = "local"
url = "0:camera_test" # 表示名为camera_test的窗口
该流程图在本地运行时的逻辑过程是:data_source_parser解析bin/mock_task.toml
文件中配置的0号摄像头,local_camera打开该编号的摄像头并解码出视频帧,video_out将图像输出到本地屏幕中名为camera_test
的窗口中。
启动应用前执行build_project.sh
进行工程构建,该脚本将编译自定义的C++功能单元(本应用不涉及)、将应用运行时会用到的配置文件转码为Unix格式(防止执行过程中的格式错误):
PS ███> .\build_project.sh
...
PS ███>
然后执行bin/main.bat
运行应用:
PS ███> .\bin\main.bat
...
将会自动弹出实时的摄像头视频画面:
如果想要关闭这个实时推理应用,关闭窗口是不行的,请点击右下角Terminal中的kill按钮结束此应用:
通过本教程,我们可以看到,使用ModelBox
框架开发应用,是一个类似搭积木的过程,如果应用所需的功能模块ModelBox
都已内置,开发者无需编写代码,就可以拖拽出应用流程图出来,非常方便。
根据本次课程学习的内容,在自己的环境进行复现,并将复现的程序运行界面,连同网页右上方的华为云账号截图发至打卡贴上,详细打卡规则参见活动页面或参考2022ModelBox实战营活动打卡 (huaweicloud.com)