训练自己的yolov5样本, 并部署到rv1126 <四>

有了自己的模型,接下来就是要部署到rv1126上了,我根据rkmedia的示例代码,重新稍微整理了一下.
整体思路如下:
训练自己的yolov5样本, 并部署到rv1126 <四>_第1张图片
分两条通路,一条是推理用:
从 scale1 获取数据 -> vi 通道 1  分辨率1920x1080 -> 绑定rga chn 1 -> 使用单独线程 RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA)转成640x640 RGB,推理之后,放入队列.

另一条推流用:
scale0 -> vi chn 0 -> RK_MPI_SYS_GetMediaBuffer(RK_ID_VI)-> 获取rknn的推测结果队列 -> 画框子 -> RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC) to venc chn 0

代码分析如下:

int main(int argc, char **argv) {

	RK_U32 u32Width = 1920;
    RK_U32 u32Height = 1080;

    // GC2053 只能用 1920*1080
    // RK_U32 u32VC1Width = 1920;
    // RK_U32 u32VC1Height = 1080;

    // imx415 可以使用 1280*720
    RK_U32 u32VC1Width = 1280;
    RK_U32 u32VC1Height = 720;

定义vi的分辨率,实际上imx415能支持到4k, 这里只使用1080p.

   signal(SIGINT, sig_proc);

    int ret = 0;
    if (argc < 2) {
        printf("please input model name and rtsp config file\n");
        return -1;
    }

提示调用的时候需要指定模型的文件名.

    // 初始化模型
    init_model(argc, argv);

初始化模型这个函数:

	int ret = 0;
    m_info.m_path = (char *) argv[1];
    // 初始化模型参数
    printf("model file is : %s \n", m_info.m_path);
    m_info.m_type = YOLOV5;
    m_info.color_expect = RK_FORMAT_RGB_888;
    m_info.anchor_per_branch = 3;
    memcpy(m_info.anchors, fixAnchors, sizeof(fixAnchors));
    m_info.post_type = U8;
    m_info.in_source = VIDEO_STREAM;

m_info是个结构体MODEL_INFO的实例,略有对象编程经验的同学可以当作就是一个对象.
对这个实例的属性进行复制,比如算法是yolov5, 色彩格式,这里我直接把anchors写死,因为yolov5的anchors基本上就是固定的.

int fixAnchors[18] = {10, 13, 16, 30, 33, 23,
                      30, 61, 62, 45, 59, 119,
                      116, 90, 156, 198, 373, 326};

另外因为模型是量化过的,所以直接用u8.

	printf("Loading model...\n");
    int model_data_size = 0;
    unsigned char *model_data = load_model(m_info.m_path, &model_data_size);
    printf("model_data_size = %d \n", model_data_size);

读取模型文件

    // rknn初始化
    ret = rknn_init(&m_ctx, model_data, model_data_size, 0);
    if (ret < 0) {
        printf("rknn_init error ret=%d\n", ret);
        return -1;
    }

rknn使用前,先用rknn_init

训练自己的yolov5样本, 并部署到rv1126 <四>_第2张图片
具体的rknn的api文档在sdk的external/rknpu/rknn/doc下面.

    // 使用rknn的api查询模型信息
    printf("query info\n");
    ret = query_model_info(&m_info, m_ctx);
    if (ret < 0) {
        return -1;
    }

查询打印模型信息.

    /* 初始化输入tensor */
    memset(inputs, 0, sizeof(inputs));
    inputs[0].index = 0;
    inputs[0].type = RKNN_TENSOR_UINT8; /* SAME AS INPUT IMAGE */
    inputs[0].size = MODEL_INPUT_SIZE * MODEL_INPUT_SIZE * 3;
    // 这里有点坑,保持默认就好
    inputs[0].fmt = RKNN_TENSOR_NHWC; 
    inputs[0].pass_through = 0;
    
     /* 初始化输出的tensor */
    memset(outputs, 0, sizeof(outputs));

    // 不使用float, 因为模型是用u8量化过
    for (int i = 0; i < m_info.out_nodes; i++) {
        outputs[i].want_float = 0;
    }

初始化输入输出tensor,主要指定输入的尺寸是640x640,格式这里坑了我2天,我想当然想让这里的设置跟模型的格式一致,因为打印的模型信息是RKNN_TENSOR_NCHW,我就改成了跟模型一致,结果一直没法出推理结果.因为中间有个nv12转RGB, imcvtcolor函数转码的动作,估计这里模型会根据这个设置自动调整.

    // 初始化isp
    init_isp();

初始化isp就是三个老动作,init, run, setFrameRate

static void init_isp(void) {
    SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, pIqfilesPath);
    SAMPLE_COMM_ISP_Run(s32CamId);
    SAMPLE_COMM_ISP_SetFrameRate(s32CamId, FPS);
}

这里3点注意,一个是s32CamId.
根据原子支持群里的说法,在原子的rv1126的板子上,如果只有一个imx415摄像头,插CSI1, CSI0都可以,这个s32CamId都是0.
然后根据我的经验,易百纳的板子则是,首先刷2.2.5的固件,然后imx415的板子插CSI0, GC2053插CSI1, s32CamId都是0.
说了半天好像啥也没说是么?哈哈,总之s32CamId都是0.
然后就是pIqfilesPath,这个在不同的开发板上路径不一样,原子直接就是/etc/iqfiles, 易百纳的是/oem/etc/iqfiles跟官方一致.
FPS基本都是30

    // 初始化rtsp
    init_rtsp();

官方的vi_rknn_venc_rtsp_test.c中用了两个rtsp的session,还要读取配置文件,我直接砍掉一个,只需要保留一个session,用于观测即可.

// 利用rtsp库, 将h264数据封装成rtsp流
void init_rtsp(void) {
    printf("init rtsp\n");
    g_rtsplive = create_rtsp_demo(554);   // 554即rtsp端口号, 返回的是一个rtsp_demo_handle指针
    g_rtsp_session = rtsp_new_session(g_rtsplive, "/live/main_stream");     // 创建rtsp会话, 访问地址是rtsp://ip/live/main_stream
    rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);      // 设置视频编码格式
    rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());    // 设置时间戳
}

rtsp这个库太好用了,只需要简单的初始化就可以使用.

你可能感兴趣的:(算法,人工智能,嵌入式硬件)