ModelBox开发指南 - 使用展开/合并功能单元实现多人人体关键点检测

举报
HWCloudAI 发表于 2022/12/21 16:27:57 2022/12/21
【摘要】 ModelBox开发指南 - 展开/合并功能单元本文将使用一个多人人体关键点检测的案例,介绍ModelBox中展开/合并功能单元的特性,案例效果如下所示:本案例所需资源(代码、模型、测试数据等)均可从multi_person_pose_yolox_alpha_pose下载(提取码为modbox),该目录中的资源列表说明如下:desc.toml # 资源描述common.zip #...

ModelBox开发指南 - 展开/合并功能单元

本文将使用一个多人人体关键点检测的案例,介绍ModelBox中展开/合并功能单元的特性,案例效果如下所示:

本案例所需资源(代码、模型、测试数据等)已做成模板放到华为云上,查看和下载模板可以使用如下命令:

  • Windows PC版本请使用solution.bat工具:
PS ███\modelbox>: .\solution.bat -l
...

Solutions name:
...
multi_person_pose_yolox_alpha_pose
...

结果中的multi_person_pose_yolox_alpha_pose即为多人人体关键点检测模板,可使用如下命令下载模板:

PS ███\modelbox>: .\solution.bat -s multi_person_pose_yolox_alpha_pose
...
  • Linux开发板版本请使用solution.py脚本:
rock@rock-3a:~/███/modelbox$ ./solution.py -l
...

Solutions name:
...
multi_person_pose_yolox_alpha_pose
...

结果中的multi_person_pose_yolox_alpha_pose即为多人人体关键点检测模板,可使用如下命令下载模板:

rock@rock-3a:~/███/modelbox$ ./solution.py -s multi_person_pose_yolox_alpha_pose
...

solution.bat/solution.py工具的参数中,-l 代表list,即列出当前已有的模板名称;-s 代表solution-name,即下载对应名称的模板。下载下来的模板资源,将存放在ModelBox核心库的solution目录下。

如果对ModelBox AI应用开发还不熟悉,请先阅读ModelBox 端云协同AI开发套件(RK3568)上手指南,或者ModelBox 端云协同AI开发套件(博时特EC02)上手指南

模型准备

本案例使用了两个模型:一是人体关键点检测模型AlphaPose,这是一个两阶段的模型(或者叫自上而下的人体关键点检测模型),需要搭配人体检测模型使用;另一个就是人体检测模型YOLOX,与ModelBox sdk中自带的car_det模板使用的模型相同。在下载的资源包中,已经包含了转换好的rknn模型或者onnx模型,可以在对应的平台上直接使用。当然,开发者也可以直接使用car_det模板中的YOLOX模型。
YOLOX原始模型的训练工程可参考此项目AlphaPose的训练工程可参考此项目,感兴趣的开发者可使用这些项目自行训练模型。
如果想体验rknn模型的转换过程,rknpu版本可参考RK1808模型转换验证案例,rknpu2版本可参考RK3568模型转换验证案例

应用开发

打开VS Code,连接到ModelBox sdk所在目录或者远程开发板,开始进行多人人体关键点检测应用开发。下面以RK3568(rknpu2)版本为例进行说明,其他版本与之类似。

1)创建工程

使用create.py创建multi_person_pose_alpha工程(Windows PC版本请使用create.bat):

rock@rock-3a:~/███/modelbox$ ./create.py -t server -n multi_person_pose_alpha -s multi_person_pose_yolox_alpha_pose
sdk version is modelbox-rk-aarch64
success: create multi_person_pose_alpha in /home/rock/███/modelbox/workspace

将会用多人人体关键点检测模板创建出一个multi_person_pose_alpha工程。

2)查看条件功能单元

本案例也需要条件功能单元,它根据当前帧的检测结果中是否包含人体检测框,在etc/flowunit/ped_condition文件夹中:

关于条件功能ped_condition的介绍,可以参考ModelBox开发指南 - 条件功能单元

3)查看展开功能单元

展开功能单元,它将当前帧中包含的多个人体检测框,展开成多个流分别处理。它在etc/flowunit/expand_ped_images文件夹中:

打开expand_ped_images.toml配置文件,可以看到功能单元属性部分:

# 工作模式,以下配置项默认全为false,表示通用功能单元;且配置项之间互斥,即最多只能设置其中一个为true
stream = false    # 是否是Stream类型功能单元
condition = false # 是否是条件功能单元
collapse = false  # 是否是合并功能单元
expand = true     # 是否是展开功能单元,此处设置为true,即表示expand_ped_images是一个展开功能单元

这些属性全部为false时表示通用功能单元,通用功能单元输出的数据与输入的数据属于同一层级,例如图像缩放功能单元Resize,输入的是图片流,产生的也是图片流。

expand_ped_images功能单元属性部分的expand属性设置成了true,即expand_ped_images被设置成一个展开功能单元。打开expand_ped_images.py,查看其process函数,可以看到展开功能单元的输出是如何编码的:

    def process(self, data_context):
        # 从DataContext中获取输入输出BufferList对象
        in_data = data_context.input("in_data")
        out_image = data_context.output("roi_image")

        # 循环处理每一个输入Buffer数据
        for buffer_img in in_data:
            # 获取输入Buffer的属性信息
            width = buffer_img.get('width')
            height = buffer_img.get('height')
            channel = buffer_img.get('channel')

            # 将输入Buffer转换为numpy对象
            img_data = np.array(buffer_img.as_object(), dtype=np.uint8, copy=False)
            img_data = img_data.reshape(height, width, channel)

            bboxes = buffer_img.get("bboxes")
            bboxes = np.array(bboxes).reshape(-1,4)

            # 业务处理,根据检测框裁剪出多个人体图像,展开成一个子数据流
            # 展开功能单元的输出处理在for循环中,即展开为多个输出Buffer
            for bbox in bboxes:
                img_roi = self.crop_bbox_img(bbox, img_data)

                h, w, c = img_roi.shape
                img_roi = img_roi.flatten()

                # 将业务处理返回的结果数据转换为Buffer,这里可以使用modelbox.Buffer构造函数
                img_buffer = modelbox.Buffer(self.get_bind_device(), img_roi)

                # 设置输出Buffer的Meta信息,此处拷贝输入Buffer的部分Meta信息,其余差异的部分再进行设置
                img_buffer.copy_meta(buffer_img)
                img_buffer.set("pix_fmt", "rgb")
                img_buffer.set("width", w)
                img_buffer.set("height", h)
                img_buffer.set("channel", c)
                img_buffer.set("width_stride", w)
                img_buffer.set("height_stride", h)

                # 将输出Buffer放入输出BufferList中
                out_image.push_back(img_buffer)

        # 返回成功标志,ModelBox框架会将数据发送到后续的功能单元
        return modelbox.Status.StatusCode.STATUS_SUCCESS

可以看到对于每一个Buffer(第一层for循环内),展开功能单元将其展开为多个Buffer进行输出(第二层for循环),即单张图片中的多个人体检测框,裁剪出多张人体图片,作为多条数据分别输出,这样后面的人体关键点检测等功能单元就可以针对每个Buffer分别处理。
关于展开功能单元的更细致介绍,详见ModelBox介绍

4)关键点检测推理功能单元

人体关键点检测的模型推理功能单元,在工程目录的model文件夹下:

5)合并功能单元

合并功能单元,它将当前帧中多个人体的关键点数据,合并到一起输出。它在etc/flowunit/collapse_multi_pose文件夹中:

打开collapse_multi_pose.toml配置文件,可以看到功能单元属性部分:

# 工作模式,以下配置项默认全为false,表示通用功能单元;且配置项之间互斥,即最多只能设置其中一个为true
stream = false    # 是否是Stream类型功能单元
condition = false # 是否是条件功能单元
collapse = true   # 是否是合并功能单元,此处设置为true,即表示collapse_multi_pose是一个合并功能单元
expand = false    # 是否是展开功能单元

可以看到功能单元属性部分的collapse属性设置成了true,即collapse_multi_pose被设置成一个合并功能单元。打开collapse_multi_pose.py,查看其process函数:

    def process(self, data_context):
        # 从DataContext中获取输入输出BufferList对象
        in_feat = data_context.input("in_feat")
        out_data = data_context.output("out_data")

        # 循环处理每一个输入Buffer数据,但输出合并到一个对象中(multi_pose)
        multi_pose = []
        for buffer_feat in in_feat:
            # 将输入Buffer转换为Python对象
            feat_data = np.array(buffer_feat.as_object(), copy=False)

            # 业务处理:将一帧图像中多人的关键点数据合并在一起
            hm_shape = (self.pose_net_h // self.stride, self.pose_net_w // self.stride)
            feat_data = feat_data.reshape((self.num_joints, hm_shape[0], hm_shape[1]))
            pose_data = self.heatmap_to_coord_simple(feat_data)
            multi_pose.append(pose_data)

        # 将业务处理返回的结果数据转换为Buffer
        multi_pose = np.array(multi_pose)
        out_buffer = modelbox.Buffer(self.get_bind_device(), multi_pose)

        # 将输出Buffer放入输出BufferList中
        out_data.push_back(out_buffer)

        # 返回成功标志,ModelBox框架会将数据发送到后续的功能单元
        return modelbox.Status.StatusCode.STATUS_SUCCESS

可以看到它将接收到的所有Buffer合并到一起,只产生一个Buffer的输出,这样collapse_multi_pose就将单张图片中的多个人体关键点信息合并到一条数据中,后面的画图功能单元就可以画出所有人的关键点。
关于合并功能单元的更细致介绍,详见ModelBox介绍

6)画图功能单元

多人人体关键点画图功能单元在etc/flowunit/draw_multi_pose文件夹中:

7)查看流程图

工程的默认流程图为graph/multi_person_pose_alpha.toml(以RK3568开发板版本为例):

# 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 = "multi-person pose estimation example using yolox and alpha-pose for local video or rtsp video stream" # 应用的简单描述

[graph]
format = "graphviz" # 流程图的格式,当前仅支持graphviz
graphconf = """digraph multi_person_pose_alpha {
    node [shape=Mrecord]
    queue_size = 4
    batch_size = 1

    # 定义节点,即功能单元及其属性
    input1[type=input, flowunit=input, device=cpu, deviceid=0]
    data_source_parser[type=flowunit, flowunit=data_source_parser, device=cpu, deviceid=0]
    video_demuxer[type=flowunit, flowunit=video_demuxer, device=cpu, deviceid=0]
    video_decoder[type=flowunit, flowunit=video_decoder, device=rknpu, deviceid=0, pix_fmt="bgr"]
    image_resize[type=flowunit, flowunit=resize, device=rknpu, deviceid=0, image_width=512, image_height=288]
    ped_detection[type=flowunit, flowunit=yolox_infer, device=rknpu, deviceid=0]
    yolox_post[type=flowunit, flowunit=yolox_post, device=cpu, deviceid=0]
    ped_condition[type=flowunit, flowunit=ped_condition, device=cpu, deviceid=0]
    expand_ped_images[type=flowunit, flowunit=expand_ped_images, device=cpu, deviceid=0]
    pose_detection[type=flowunit, flowunit=pose_infer, device=rknpu, deviceid=0]
    collapse_multi_pose[type=flowunit, flowunit=collapse_multi_pose, device=cpu, deviceid=0]
    draw_multi_pose[type=flowunit, flowunit=draw_multi_pose, device=cpu, deviceid=0]
    video_out[type=flowunit, flowunit=video_out, device=rknpu, deviceid=0]

    # 定义边,即功能间的数据传递关系
    input1:input -> data_source_parser:in_data
    data_source_parser:out_video_url -> video_demuxer:in_video_url
    video_demuxer:out_video_packet -> video_decoder:in_video_packet
    video_decoder:out_video_frame -> image_resize:in_image
    image_resize:out_image -> ped_detection:input
    ped_detection:output -> yolox_post:in_feat
    yolox_post:out_data -> ped_condition:in_bbox
    video_decoder:out_video_frame -> ped_condition:in_image
    ped_condition:no_pedestrian -> video_out:in_video_frame
    ped_condition:has_pedestrian -> expand_ped_images:in_data
    expand_ped_images:roi_image -> pose_detection:input
    pose_detection:output -> collapse_multi_pose:in_feat
    ped_condition:has_pedestrian -> draw_multi_pose:in_image
    collapse_multi_pose:out_data -> draw_multi_pose:in_pose
    draw_multi_pose:out_image -> video_out:in_video_frame
}"""

该流程图对于某个视频流,经过视频解码、图像缩放、人体检测与后处理、人体检测结果判定、人体图像裁剪、多人人体关键点检测与后处理、关键点画图等一系列操作后,将结果保存下来。图中可以看到展开/合并功能单元在与其他功能单元连接时并没有不同,它们的输入输出不在同一层级,但这些都在框架内部处理。

工程的任务配置文件bin/mock_task.toml中设置了输入输出源,内容为:

# 任务输入配置,当前支持以下几种输入方式:
# 1. rtsp摄像头或rtsp视频流:type="rtsp", url="rtsp://xxx.xxx"
# 2. 设备自带摄像头或者USB摄像头:type="url",url="${摄像头编号}" (需配合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"
url = "${HILENS_APP_ROOT}/data/multi_person_pose.mp4"

# 任务输出配置,当前支持以下几种输出方式:
# 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:multi_person_pose"
url = "${HILENS_APP_ROOT}/hilens_data_dir/multi_person_pose_result.mp4"

测试视频为data/multi_person_pose.mp4,流程图使用这一视频进多人人体关键点检测,检测结果绘制后保存为hilens_data_dir/multi_person_pose_result.mp4文件。

8)运行应用

在工程路径下执行build_project.sh进行工程构建(以RK3568开发板版本为例):

rock@rock-3a:~/███/modelbox/workspace/multi_person_pose_alpha$ ./build_project.sh

build success: you can run main.sh in ./bin folder

rock@rock-3a:~/███/modelbox/workspace/multi_person_pose_alpha$

执行bin/main.sh(Windows PC版本请使用bin\main.bat)运行应用,运行结束后在hilens_data_dir目录下生成了multi_person_pose_result.mp4文件,可以下载到PC端查看。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。