yhc · 2019年09月01日

【EAIDK-310】在EAIDK上用Tengine跑OpenPose

0x0 EAIDK310板子初上手

前两周收到EAIDK310板子,板子做工不错,设计紧凑。主控芯片使用Rockchip的RK3228H,四核Cortext-A53,Mali 450MP2,还支持USB3.0、2.4g/5g双频Wifi等强大的连接能力。

alt 图片

板子结构尺寸和树莓派3是完全兼容的,使用之前树莓派3的盒子装上去灰常的合适,哈哈哈~

经过两周的使用感觉很不错,运行稳定。用Tengine框架尝试跑了几个模型,根据官方提供文档和代码示例上手还是比较容易的,这次先发OpenPose项目分享给大家。

代码已经上传到github上,获取地址在这里

0x1 环境准备

Tengine版本

本项目直接使用Tengine 1.7.1内测版本,想要试用的同学可以向官方申请。

有试了一下直接使用从官网下载的1.0版本,也是可以转换成功的,openpose模型的算子Tengine1.0应该就能支持。

模型下载

OpenPose原始模型可以从这里下载:
prototxt
caffemodel

其中,本项目将prototxt的输入层修改为160x160。

模型转换

使用以下命令将OpenPose原始的Caffe模型转换为Tengine模型:

./convert_model_to_tm -f caffe -p pose_deploy_linevec.prototxt -m pose_iter_440000.caffemodel -o openpose.tm

0x2 代码编写

初始化和加载模型

Tengine初始化和加载模型的代码基本和classification示例程序一样,代码片段如下所示:

    // init tengine
    init_tengine();

    if(request_tengine_version("0.9") < 0)
        return false;

    // load model
    graph_t graph = nullptr;
    graph = create_graph(nullptr, model_format, model_file);
    if(!graph)
    {
        std::cerr << "Create graph0 failed.\n";
        std::cout << "errno:" << get_tengine_errno() << "\n";
        return false;
    }

    // input
    int img_size = img_h * img_w * 3;
    int dims[] = {1, 3, img_h, img_w};
    float* input_data = ( float* )malloc(sizeof(float) * img_size);

    tensor_t input_tensor = get_graph_input_tensor(graph, 0, 0);
    set_tensor_shape(input_tensor, dims, 4);

    // prerun
    int ret = prerun_graph(graph);
    if(-1 == ret)
    {
        std::cout << " prerun graph failed \n";
        return false;
    }

其中create_graph传入的参数model_formattenginemodel_file为openpose.tm模型文件路径。

输入数据前处理

数据前处理包括图像缩放、bgr->rgb转换以及mean和scale的处理。处理函数和classification示例一样。

void get_input_data(const char* image_file, float* input_data, const int img_h, const int img_w, const float* mean,
                    const float scale)
{
    image img_o = imread(image_file);
    if(img_o.data == NULL)
    {
        std::cerr << "Failed to read image file " << image_file << ".\n";
        return;
    }

    image img = resize_image(img_o, img_w, img_h);    
    img = rgb2bgr_premute(img);    

    int hw = img_h * img_w;
    for(int h = 0; h < img_h; h++)
    {
        for(int w = 0; w < img_w; w++)
        {
            for(int c = 0; c < 3; c++)
            {
                input_data[c * hw + h * img_w + w] = 
                                    (img.data[c * hw + h * img_w + w] - mean[c]) * scale;
            }
        }
    }
}

其中传入的目标缩放宽高设为160,mean和scale需要分别设置成0 0 01.0/255

模型推理

接下来就是设置模型输入Tensor、进行模型推理和获取输出Tensor数据了,代码如下所示:

       get_input_data(image_file, input_data, img_h, img_w, mean, scale);
       set_tensor_buffer(input_tensor, input_data, img_size * 4);

       run_graph(graph, 1);

       tensor_t output_tensor = get_graph_output_tensor(graph, 0, 0);
       float* data = ( float* )get_tensor_buffer(output_tensor);

输出后处理

OpenPose模型推理的输出Tensor数据只是一个热图(heatmap),还需要进行缩放、滤波、关键点检测和获取有效连接等处理才能最后得到输出的点。

后处理代码根据网上开源的opencv版本(地址)进行修改,网上有和该代码相应的资料,感兴趣的同学可以去学习(地址),这里就不详细介绍后处理的流程。

0x3 运行效果

下面是对一些图片的运行效果,目前在EAIDK310上用float32跑速度会有点慢,下一步打算对模型进行量化来提升速度。

alt 图片

alt 图片

推荐阅读
关注数
3510
内容数
57
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息