关于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以上。
本系列教程由矽速科技撰写提供,矽速科技AIoT交流QQ群: 756313869 .
附R329开发板教程系列: