11

矽速科技 · 2021年07月26日

R329开发板教程之三|视觉模型实时运行

关于R329开发板给大家介绍了周易 AIPU 部署及仿真教程实机运行aipu程序,大家应该都完成了在实机上跑单帧图片预测的任务,本节教程将带领大家进行实机上的模型实时运行。

本章节网盘资料:

链接: https://pan.baidu.com/s/1f4JOqOrVdBIaZ3X5c37ULA 提取码: vs1t
如链接失效,请联系极术小姐姐(微信:aijishu20)

工程介绍

本节内容旨在实现抓取摄像头图像,显示在屏幕上,并实机运行模型,显示预测结果。

对于linux上的图像处理,我们优先选用了openCV来进行处理。
简单介绍下网盘上的文件:

  • tina_r329-evb5_uart0_0723.img 镜像是包含了openCV的linux系统镜像,烧录时候可能会出错,但是不影响系统启动。
  • zhouyi_cam.zip是本项目的工程源码,使用cmake构建
  • zhouyi_cam 是最终构建的可执行文件
  • rootfs.tar.gz 是构建zhouyi_cam所需要的系统目录,构建脚本会自行在该目录寻找库文件
  • toolchain.tar.gz 是构建所需的工具链

代码介绍

zhouyi_cam 为 演示imagenet分类模型的demo工程,代码简单介绍如下。

0. 解析参数

  • 第一个参数为需要运行的模型文件
  • 第二个参数为模型文件最终输出的prob是int8还是uint8的设置
  • 第三个是可选参数,表示输出的下标需要减的偏移量,默认是减一

1.摄像头配置

MaixSense标配1280x720分辨率的摄像头,但是屏幕是240x240, 模型输入为224x224, 所以我们需要先设置下摄像头。

摄像头最低可以输出320x240的图像,我们就按此分辨率输出。

实测在该分辨率下得到了被压缩了4/3的图像,所以我们先截取180x240的图像,再拉伸回240x240给屏幕显示。

同时注意openCV是BGR格式,需要进行BGR2RGB的转换。

在屏幕图像的基础上,我们再进行裁切,得到模型运算所需的224x224图像
最后还要减去各通道的偏置,需要与训练时的处理一致,得到int8的输入数据。

代码如下:

int cap_img(Mat* lcd_frame, Mat* ai_frame)
{    
    Rect roi(40, 0, 240/4*3, 240);  //16/9 -> 4/3  
    Rect input_roi(8, 8, 224, 224);
    Size dsize = Size(240, 240);
    if(!capture.read(*lcd_frame))
    {
        printf("no video frame\r\n");
        return -1;
    }
    *lcd_frame = (*lcd_frame)(roi).clone();
    rotate(*lcd_frame, *lcd_frame, ROTATE_180);
    resize(*lcd_frame, *lcd_frame, dsize);
    cvtColor(*lcd_frame, *lcd_frame, COLOR_BGR2RGB);
    *ai_frame = (*lcd_frame)(input_roi).clone() + Scalar(-123, -117,-104);
    return 0;
}

2. 初始化运算图

int init_graph(char* file_model, aipu_ctx_handle_t ** ctx, aipu_graph_desc_t* gdesc, aipu_buffer_alloc_info_t* info)
{
    const char* status_msg =NULL;
    aipu_status_t status = AIPU_STATUS_SUCCESS;
    int ret = 0;
    //Step1: init ctx handle
    status = AIPU_init_ctx(ctx);       
    if (status != AIPU_STATUS_SUCCESS) {
        AIPU_get_status_msg(status, &status_msg);
        printf("[DEMO ERROR] AIPU_init_ctx: %s\n", status_msg);
        ret = -1;
        //goto out;
    }

    //Step2: load graph
    status = AIPU_load_graph_helper(*ctx, file_model, gdesc);
    if (status != AIPU_STATUS_SUCCESS) {
        AIPU_get_status_msg(status, &status_msg);
        printf("[DEMO ERROR] AIPU_load_graph_helper: %s\n", status_msg);
        ret = -2;
        //goto deinit_ctx;
    }
    printf("[DEMO INFO] AIPU load graph successfully.\n");

    //Step3: alloc tensor buffers
    status = AIPU_alloc_tensor_buffers(*ctx, gdesc, info);
    if (status != AIPU_STATUS_SUCCESS) {
        AIPU_get_status_msg(status, &status_msg);
        printf("[DEMO ERROR] AIPU_alloc_tensor_buffers: %s\n", status_msg);
        ret = -3;
        //goto unload_graph;
    }
    
    return ret;
}

3. 逐帧计算并显示

    while(!exit_flag)
    {
        //1. cap cam img
        if(cap_img(&lcd_frame, &ai_frame) != 0) {
            break;
        }
        //2. infer cam img, get label
        gettimeofday(&start, NULL);
        ret = infer_img(&ai_frame, &ctx, &gdesc, &info, signed_flag, &label_idx, &label_prob);
        if(ret != 0) goto free_tensor_buffers;
        gettimeofday(&end, NULL);
        //3. draw lcd
        putText(lcd_frame, labels[label_idx-label_oft], Point(0, 224), cv::FONT_HERSHEY_PLAIN, 1, Scalar(255,0,0), 2);
        float fps = cal_fps(start, end);
        char fps_str[16];
        sprintf(fps_str, "%.1ffps", fps);
        putText(lcd_frame, fps_str, Point(0, 16), cv::FONT_HERSHEY_PLAIN, 1, Scalar(255,0,0), 2);
        fb_display(lcd_frame.data, 0, 240, 240, 0, 0, 0, 0);
    }

4.退出清理

注意代码里实现了 SIGINT 的处理,因为当前使用的驱动的清理功能有待完善,如果直接强行退出程序,会导致下次运行时可能出错。

所以我们检测 SIGINT 信号,检测到 CTRL-C后,退出主循环,执行相关的aipu清理操作。

运行效果

如下图所示,以运行mobilenet_v2 1.0为例,可见帧率可达20fps以上。

W6EE4O.jpg

本系列教程由矽速科技撰写提供,矽速科技AIoT交流QQ群: 756313869 .

附R329开发板教程系列:

推荐阅读
关注数
7443
内容数
92
人工智能边缘计算软硬件解决方案,提供高性能、低成本、低功耗、易使用的硬件选型方案.
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息