易百纳rv1126 a201开发板跑rknn yolov5

一开始我以为跑yolov5啊, 那必须上debian/ubuntu啊, 不然怎么装python, pytorch?buildroot没有apt, 于是花了大量时间想办法在a201的板子上跑debian, 等我debian跑上, python安排上, rknn-lite按照firefly的方法装好
https://dev.t-firefly.com/thread-104204-1-1.html
再去找rknn的示例程序的时候, 发现原来有c的版本.
https://github.com/airockchip/rknn_model_zoo/tree/main/models/vision/object_detection/yolov5-pytorch/RKNN_C_demo/RKNN_toolkit_1/rknn_yolov5_demo
默认易百纳的出厂固件就有rknn的lib

[root@RV1126_RV1109:/etc]# echo $LD_LIBRARY_PATH
:/oem/usrlibs:/oem/usr/lib:/oem/lib
[root@RV1126_RV1109:/etc]# cd /oem/usr/lib
[root@RV1126_RV1109:/oem/usr/lib]# ls
face_attribute.data           libeasymedia.so.1      librockchip_mpp.so.0
face_detection_v3.data        libeasymedia.so.1.0.1  librockchip_mpp.so.1
face_detection_v3_large.data  libgdbus.so            librockchip_vpu.so
face_landmark5.data           libispclient.so        librockchip_vpu.so.0
face_landmarks106.data        libmal.so              librockchip_vpu.so.1
face_landmarks68.data         librkaiq.so            librockface.so
face_recognition.data         librkdb.so             librockx.so
libCallFunIpc.so              librkisp_api.so        object_detection.data
libIPCProtocol.so             librknn_api.so         pose_body_v2.data
libeasymedia.so               librockchip_mpp.so     pose_finger.data

实现方法, 第一步, 用rkmedia产生一个jpeg图片,这个就简单了, 直接改rkmedia的example里面的示例代码,但是原本是用的CMakelists编译的, 效率太低, 直接改Makefile

hide := @
ECHO := echo

GCC := /home/marc/rv_sdk/prebuilts/gcc/linux-x86/arm/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc

SYSROOT =  /home/marc/rv_sdk/buildroot/output/rockchip_rv1126_rv1109/host/arm-buildroot-linux-gnueabihf/sysroot

CFLAGS := -I../include/rkmedia \
		  -I../include/rkaiq/common \
		  -I../include/rkaiq/xcore \
		  -I../include/rkaiq/uAPI \
		  -I../include/rkaiq/algos \
		  -I../include/rkaiq/iq_parser\
		  #-I/home/marc/rv_sdk/buildroot/output/rockchip_rv1126_rv1109/build/camera_engine_rkaiq-1.0/include/uAPI/\
		  #-I/home/marc/rv_sdk/buildroot/output/rockchip_rv1126_rv1109/build/camera_engine_rkaiq-1.0/include/xcore/\
		  #-I/home/marc/rv_sdk/buildroot/output/rockchip_rv1126_rv1109/build/camera_engine_rkaiq-1.0/include/iq_parser/\

LIB_FILES := -L$(SYSROOT)/usr/lib

LD_FLAGS := -lpthread -leasymedia -ldrm -lrockchip_mpp \
	        -lavformat -lavcodec -lswresample -lavutil \
			-lasound -lv4l2 -lv4lconvert -lrga \
			-lRKAP_ANR -lRKAP_Common -lRKAP_3A \
			-lmd_share -lrkaiq -lod_share

CFLAGS += -DRKAIQ

SAMPLE_COMMON := common/sample_common_isp.c

all:
	$(GCC) jpeg_cap.c $(SAMPLE_COMMON) $(LIB_FILES) $(LD_FLAGS) $(CFLAGS) -o build/jpeg_capture --sysroot=$(SYSROOT)
	# $(GCC) my_vi.c $(SAMPLE_COMMON) $(LIB_FILES) $(LD_FLAGS) $(CFLAGS) -o build/my_vi --sysroot=$(SYSROOT)
	$(hide)$(ECHO) "Build Done ..."

就是改下GCC的目录跟加入sysroot目录, 不然会提示找不到库
通过make编译一下这个获取图片并保存的app:

#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include "common/sample_common.h"
#include "rkmedia_api.h"
#include "rkmedia_venc.h"

#define RKAIQ 1

static RK_CHAR *g_pOutPath = "/tmp/";
static bool getPicture = false;

char jpeg_file_path_old[128];

void video_packet_cb(MEDIA_BUFFER mb) {
    static RK_U32 jpeg_id = 0;
    static bool firstRun = true;
    //    printf("Get JPEG packet[%d]:ptr:%p, fd:%d, size:%zu, mode:%d, channel:%d, timestamp:%lld\n",
    //           jpeg_id, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetFD(mb),
    //           RK_MPI_MB_GetSize(mb), RK_MPI_MB_GetModeID(mb),
    //           RK_MPI_MB_GetChannelID(mb), RK_MPI_MB_GetTimestamp(mb));
    char *jpeg_path = "/mnt/www/rknn_before.jpeg";
    // sprintf(jpeg_path, "/tmp/rknn.jpeg");

    if (!firstRun) {
        int rtn = remove(jpeg_path);
        if (rtn == 0) {
            // printf("File deleted successfully\n");
        } else {
            printf("Error: unable to delete the file\n");
            return;
        }
    }

    FILE *file = fopen(jpeg_path, "w");
    if (file) {
        fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), file);
        fclose(file);
    }

    RK_MPI_MB_ReleaseBuffer(mb);
    jpeg_id++;

    getPicture = true;

    firstRun = false;
}

void video_packet_cb_old(MEDIA_BUFFER mb) {
    static RK_U32 jpeg_id = 0;
    static bool firstRun = true;
    printf("Get JPEG packet[%d]:ptr:%p, fd:%d, size:%zu, mode:%d, channel:%d, timestamp:%lld\n",
           jpeg_id, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetFD(mb),
           RK_MPI_MB_GetSize(mb), RK_MPI_MB_GetModeID(mb),
           RK_MPI_MB_GetChannelID(mb), RK_MPI_MB_GetTimestamp(mb));

    char jpeg_path[128];

    sprintf(jpeg_path, "%s%lld.jpeg", g_pOutPath, RK_MPI_MB_GetTimestamp(mb));

    if (!firstRun) {
        int rtn = remove(jpeg_file_path_old);
        if (rtn == 0) {
            printf("File deleted successfully\n");
        } else {
            printf("Error: unable to delete the file\n");
            return;
        }
    }

    FILE *file = fopen(jpeg_path, "w");
    if (file) {
        fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), file);
        fclose(file);
    }

    RK_MPI_MB_ReleaseBuffer(mb);
    jpeg_id++;

    memcpy(jpeg_file_path_old, jpeg_path, 128);

    getPicture = true;
    firstRun = false;
}

#define TEST_ARGB32_YELLOW 0xFFFFFF00
#define TEST_ARGB32_RED 0xFFFF0033
#define TEST_ARGB32_BLUE 0xFF003399
#define TEST_ARGB32_TRANS 0x00000000

static void set_argb8888_buffer(RK_U32 *buf, RK_U32 size, RK_U32 color) {
    for (RK_U32 i = 0; buf && (i < size); i++)
        *(buf + i) = color;
}

static RK_CHAR optstr[] = "?::a::w:h:W:H:o:I:M:r:";
static const struct option long_options[] = {
        {"aiq",      optional_argument, NULL, 'a'},
        {"width",    required_argument, NULL, 'w'},
        {"height",   required_argument, NULL, 'h'},
        {"Width",    required_argument, NULL, 'W'},
        {"Height",   required_argument, NULL, 'H'},
        {"output",   required_argument, NULL, 'o'},
        {"camid",    required_argument, NULL, 'I'},
        {"multictx", required_argument, NULL, 'M'},
        {"rotation", required_argument, NULL, 'r'},
        {"help",     optional_argument, NULL, '?'},
        {NULL,       0,                 NULL, 0},
};

static void print_usage(const RK_CHAR *name) {
    printf("usage example:\n");
    printf("\t%s [-a [iqfiles_dir]]"
           "[-I 0] "
           "[-M 0] "
           "[-H 1920] "
           "[-W 1080] "
           "[-h 720] "
           "[-w 480] "
           "[-o output_dir] "
           "\n",
           name);
    printf("\t-a | --aiq: enable aiq with dirpath provided, eg:-a "
           "/oem/etc/iqfiles/, "
           "set dirpath empty to using path by default, without this option aiq "
           "should run in other application\n");
    printf("\t-M | --multictx: switch of multictx in isp, set 0 to disable, set "
           "1 to enable. Default: 0\n");

    printf("\t-I | --camid: camera ctx id, Default 0\n");
    printf("\t-W | --Width: source width, Default:1920\n");
    printf("\t-H | --Height: source height, Default:1080\n");
    printf("\t-w | --width: destination width, Default:720\n");
    printf("\t-h | --height: destination height, Default:480\n");
    printf("\t-o | --output: output dirpath, Default:/tmp/\n");
    printf("\t-r | --rotation: rotation control, Default:0. Values:0/90/180/270\n");
    printf("\t tip: destination resolution should not over 4096*4096\n");
}

RK_S32 ret;
RK_U32 u32SrcWidth = 1920;
RK_U32 u32SrcHeight = 1080;
RK_U32 u32DstWidth = 960;
RK_U32 u32DstHeight = 540;
IMAGE_TYPE_E enPixFmt = IMAGE_TYPE_NV12;
const RK_CHAR *pcIqFileDir = "/oem/etc/iqfiles/";
RK_S32 s32CamId = 0;
RK_U32 u32Rotation = 0;
RK_BOOL bMultictx = RK_FALSE;
RK_CHAR *pDeviceName = "rkispp_scale0";

void print_info(void) {

    printf("#SrcWidth: %d\n", u32SrcWidth);
    printf("#u32SrcHeight: %d\n", u32SrcHeight);
    printf("#u32DstWidth: %d\n", u32DstWidth);
    printf("#u32DstHeight: %d\n", u32DstHeight);
    printf("#u32Rotation: %d\n", u32Rotation);
    printf("#OutPath: %s\n", g_pOutPath);
    printf("#CameraIdx: %d\n\n", s32CamId);
    printf("#Rkaiq XML DirPath: %s\n", pcIqFileDir);
    printf("#bMultictx: %d\n\n", bMultictx);
}

void set_vi_chn(VI_CHN_ATTR_S *vi_chn_attr) {
    memset(vi_chn_attr, 0, sizeof(vi_chn_attr));
    // memset(&vi_chn_attr, 0, sizeof(VI_CHN_ATTR_S));
    vi_chn_attr->pcVideoNode = pDeviceName;
    vi_chn_attr->u32BufCnt = 3;
    vi_chn_attr->u32Width = u32SrcWidth;
    vi_chn_attr->u32Height = u32SrcHeight;
    vi_chn_attr->enPixFmt = enPixFmt;
    vi_chn_attr->enBufType = VI_CHN_BUF_TYPE_MMAP;
    vi_chn_attr->enWorkMode = VI_WORK_MODE_NORMAL;
}

void set_venc_chn(VENC_CHN_ATTR_S *venc_chn_attr) {
    memset(venc_chn_attr, 0, sizeof(VENC_CHN_ATTR_S));
    venc_chn_attr->stVencAttr.enType = RK_CODEC_TYPE_JPEG;
    venc_chn_attr->stVencAttr.imageType = IMAGE_TYPE_NV12;
    venc_chn_attr->stVencAttr.u32PicWidth = u32SrcWidth;
    venc_chn_attr->stVencAttr.u32PicHeight = u32SrcHeight;
    venc_chn_attr->stVencAttr.u32VirWidth = u32SrcWidth;
    venc_chn_attr->stVencAttr.u32VirHeight = u32SrcHeight;
    venc_chn_attr->stVencAttr.stAttrJpege.u32ZoomWidth = u32DstWidth;
    venc_chn_attr->stVencAttr.stAttrJpege.u32ZoomHeight = u32DstHeight;
    venc_chn_attr->stVencAttr.stAttrJpege.u32ZoomVirWidth = u32DstWidth;
    venc_chn_attr->stVencAttr.stAttrJpege.u32ZoomVirHeight = u32DstHeight;
    venc_chn_attr->stVencAttr.enRotation = VENC_ROTATION_180;
}

int main(void) {

    static int picCounter = 0;
    int c;
    print_info();

    rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
    int fps = 30;
    SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, pcIqFileDir);
    SAMPLE_COMM_ISP_Run(s32CamId);
    SAMPLE_COMM_ISP_SetFrameRate(s32CamId, fps);

    printf("init sys\n");
    ret = RK_MPI_SYS_Init();
    if (ret) {
        printf("Sys Init failed! ret=%d\n", ret);
        return -1;
    }
    printf("1\n");
    VI_CHN_ATTR_S vi_chn_attr;
    set_vi_chn(&vi_chn_attr);

    printf("2\n");
    ret = RK_MPI_VI_SetChnAttr(s32CamId, 1, &vi_chn_attr);
    ret |= RK_MPI_VI_EnableChn(s32CamId, 1);
    printf("3\n");
    if (ret) {
        printf("Create Vi failed! ret=%d\n", ret);
        return -1;
    }
    printf("create channel \n");
    VENC_CHN_ATTR_S venc_chn_attr;
    set_venc_chn(&venc_chn_attr);

    ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
    if (ret) {
        printf("Create Venc failed! ret=%d\n", ret);
        return -1;
    }

    MPP_CHN_S stEncChn;
    stEncChn.enModId = RK_ID_VENC;
    stEncChn.s32ChnId = 0;
    printf("reg out cb\n");
    ret = RK_MPI_SYS_RegisterOutCb(&stEncChn, video_packet_cb);
    if (ret) {
        printf("Register Output callback failed! ret=%d\n", ret);
        return -1;
    }

    // The encoder defaults to continuously receiving frames from the previous
    // stage. Before performing the bind operation, set s32RecvPicNum to 0 to
    // make the encoding enter the pause state.
    VENC_RECV_PIC_PARAM_S stRecvParam;
    stRecvParam.s32RecvPicNum = 0;
    RK_MPI_VENC_StartRecvFrame(0, &stRecvParam);

    // bind vi ch 1 to venc ch 0
    printf("bind vi and venc\n");
    MPP_CHN_S stSrcChn;
    stSrcChn.enModId = RK_ID_VI;
    stSrcChn.s32ChnId = 1;
    MPP_CHN_S stDestChn;
    stDestChn.enModId = RK_ID_VENC;
    stDestChn.s32ChnId = 0;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (ret) {
        printf("Bind VI[1] to VENC[0]::JPEG failed! ret=%d\n", ret);
        return -1;
    }

#if 0
    printf("init rgn\n");
    RK_MPI_VENC_RGN_Init(0, NULL);


    BITMAP_S BitMap;
    BitMap.enPixelFormat = PIXEL_FORMAT_ARGB_8888;
    BitMap.u32Width = 64;
    BitMap.u32Height = 256;
    BitMap.pData = malloc(BitMap.u32Width * 4 * BitMap.u32Height);
    RK_U8 *ColorData = (RK_U8 *) BitMap.pData;
    RK_U16 ColorBlockSize = BitMap.u32Height * BitMap.u32Width;
    set_argb8888_buffer((RK_U32 *) ColorData, ColorBlockSize / 4, TEST_ARGB32_YELLOW);
    set_argb8888_buffer((RK_U32 *) (ColorData + ColorBlockSize), ColorBlockSize / 4, TEST_ARGB32_TRANS);
    set_argb8888_buffer((RK_U32 *) (ColorData + 2 * ColorBlockSize), ColorBlockSize / 4, TEST_ARGB32_RED);
    set_argb8888_buffer((RK_U32 *) (ColorData + 3 * ColorBlockSize), ColorBlockSize / 4, TEST_ARGB32_BLUE);

    printf("create rgn\n");
    // Case 1: Canvas and bitmap are equal in size
    OSD_REGION_INFO_S RngInfo;
    RngInfo.enRegionId = REGION_ID_0;
    RngInfo.u32PosX = 0;
    RngInfo.u32PosY = 0;
    RngInfo.u32Width = 64;
    RngInfo.u32Height = 256;
    RngInfo.u8Enable = 1;
    RngInfo.u8Inverse = 0;
    RK_MPI_VENC_RGN_SetBitMap(0, &RngInfo, &BitMap);
#endif

    printf("%s initial finish\n", __func__);
    // signal(SIGINT, sigterm_handler);

    char cmd[64];
    // int qfactor = 0;
    VENC_JPEG_PARAM_S stJpegParam;
    // printf("#Usage: input 'quit' to exit programe!\n peress any other key to capture one picture to file\n");
#if 0
    stJpegParam.u32Qfactor = 99;
    RK_MPI_VENC_SetJpegParam(0, &stJpegParam);
    stRecvParam.s32RecvPicNum = 1;
    ret = RK_MPI_VENC_StartRecvFrame(0, &stRecvParam);
    if (ret) {
        printf("RK_MPI_VENC_StartRecvFrame failed!\n");
        return -1;
    }
#endif
#if 1
    stJpegParam.u32Qfactor = 99;
    RK_MPI_VENC_SetJpegParam(0, &stJpegParam);

    printf("main start\n");
    while (1) {
//
//        if (qfactor >= 99)
//            qfactor = 1;
//        else
//            qfactor = ((qfactor + 10) > 99) ? 99 : (qfactor + 10);

        //  printf("qfactor = %d\n", qfactor);
        // printf("running main\n");
        stRecvParam.s32RecvPicNum = 1;
        ret = RK_MPI_VENC_StartRecvFrame(0, &stRecvParam);
        if (ret) {
            printf("RK_MPI_VENC_StartRecvFrame failed!\n");
            break;
        }

        getPicture = false;
        while (!getPicture) {
            usleep(10000); // sleep 30 ms.
        }

        picCounter++;
        if (picCounter > 10) {
            // break;
        }
        // usleep(30000); // sleep 30 ms.
    }
#endif

    RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
    RK_MPI_VENC_DestroyChn(0);
    RK_MPI_VI_DisableChn(s32CamId, 1);

    if (pcIqFileDir) {
        SAMPLE_COMM_ISP_Stop(s32CamId);
    }

    printf("%s exit!\n", __func__);
    return 0;
}

上面的代码执行起来, 会不停的删除之前的图片,抓取jpeg编码后的数据,写入新的同名图片, 保存在一个nginx的www目录下面, 方便我们后期用一个自动刷新的网站来显示使用yolov5做predict之前的图片.

这样我们就获得了一张从摄像头获取的jpeg图片. 且是不断刷新的.
然后使用前面说的rknn的示例代码, 进行推测:
注意几点:

  1. 使用模型要复制到app执行的目录下面, 名字是yolov5s_relu_rv1109_rv1126_out_opt.rknn
  2. COCO的标签也需要复制过去
  3. 原本执行的参数, 我直接写死了, 省得每次都要打参数进去.
  4. 输出路径同为nginx的www目录, 不过我的nginx的是跑在我开发环境的ubuntu上面的, 所以目录不能搞乱了, 其实可以考虑把nginx跑在开发板上, 只是需要拿nginx源码编译一下就行.

具体代码main.cc如下:

/*-------------------------------------------
                Includes
-------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <dlfcn.h>
#include <vector>
#include <string>

#define _BASETSD_H

#define STB_IMAGE_IMPLEMENTATION

#include "stb/stb_image.h"

#define STB_IMAGE_RESIZE_IMPLEMENTATION

#include <stb/stb_image_resize.h>

#define STB_IMAGE_WRITE_IMPLEMENTATION

#include "stb/stb_image_write.h"

#undef cimg_display
#define cimg_display 0
#undef cimg_use_jpeg
#define cimg_use_jpeg 1
#undef cimg_use_png
#define cimg_use_png 1

#include "CImg/CImg.h"

#include "drm_func.h"
#include "rga_func.h"
#include "rknn_api.h"
#include "postprocess.h"

#define PERF_WITH_POST 1
#define COCO_IMG_NUMBER 5000

using namespace cimg_library;

/*-------------------------------------------
                  Functions
-------------------------------------------*/
static void printRKNNTensor(rknn_tensor_attr *attr) {
    printf("index=%d name=%s n_dims=%d dims=[%d %d %d %d] n_elems=%d size=%d "
           "fmt=%d type=%d qnt_type=%d fl=%d zp=%d scale=%f\n",
           attr->index, attr->name, attr->n_dims, attr->dims[3], attr->dims[2],
           attr->dims[1], attr->dims[0], attr->n_elems, attr->size, 0, attr->type,
           attr->qnt_type, attr->fl, attr->zp, attr->scale);
}

double __get_us(struct timeval t) { return (t.tv_sec * 1000000 + t.tv_usec); }

rknn_context ctx;
int status = 0;
void *drm_buf = NULL;
int drm_fd = -1;
int buf_fd = -1; // converted from buffer handle
unsigned int handle;
size_t actual_size = 0;
int img_width = 0;
int img_height = 0;
int img_channel = 0;
rga_context rga_ctx;
drm_context drm_ctx;
const float nms_threshold = 0.65;
const float conf_threshold = 0.2;
struct timeval start_time, stop_time;
int ret;

static unsigned char *load_data(FILE *fp, size_t ofst, size_t sz) {
    unsigned char *data;
    int ret;

    data = NULL;

    if (NULL == fp) {
        return NULL;
    }

    ret = fseek(fp, ofst, SEEK_SET);
    if (ret != 0) {
        printf("blob seek failure.\n");
        return NULL;
    }

    data = (unsigned char *) malloc(sz);
    if (data == NULL) {
        printf("buffer malloc failure.\n");
        return NULL;
    }
    ret = fread(data, 1, sz, fp);
    return data;
}

static unsigned char *load_model(const char *filename, int *model_size) {

    FILE *fp;
    unsigned char *data;

    fp = fopen(filename, "rb");
    if (NULL == fp) {
        printf("Open file %s failed.\n", filename);
        return NULL;
    }

    fseek(fp, 0, SEEK_END);
    int size = ftell(fp);

    data = load_data(fp, 0, size);

    fclose(fp);

    *model_size = size;
    return data;
}

static int saveFloat(const char *file_name, float *output, int element_size) {
    FILE *fp;
    fp = fopen(file_name, "w");
    for (int i = 0; i < element_size; i++) {
        fprintf(fp, "%.6f\n", output[i]);
    }
    fclose(fp);
    return 0;
}

static unsigned char *
load_image(const char *image_path, int *org_height, int *org_width, int *org_ch, rknn_tensor_attr *input_attr) {
    int req_height = 0;
    int req_width = 0;
    int req_channel = 0;

    switch (input_attr->fmt) {
        case RKNN_TENSOR_NHWC:
            req_height = input_attr->dims[2];
            req_width = input_attr->dims[1];
            req_channel = input_attr->dims[0];
            break;
        case RKNN_TENSOR_NCHW:
            req_height = input_attr->dims[1];
            req_width = input_attr->dims[0];
            req_channel = input_attr->dims[2];
            break;
        default:
            printf("meet unsupported layout\n");
            return NULL;
    }

    // printf("w=%d,h=%d,c=%d, fmt=%d\n", req_width, req_height, req_channel, input_attr->fmt);

    int height = 0;
    int width = 0;
    int channel = 0;

    unsigned char *image_data = stbi_load(image_path, &width, &height, &channel, req_channel);
    if (image_data == NULL) {
        printf("load image-%s failed!\n", image_path);
        return NULL;
    }

    if (channel == 1) {
        printf("image is grey, convert to RGB");
        void *rgb_data = malloc(width * height * 3);
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int offset = (i * width + j) * 3;
                ((unsigned char *) rgb_data)[offset] = ((unsigned char *) image_data)[offset];
                ((unsigned char *) rgb_data)[offset + 1] = ((unsigned char *) image_data)[offset];
                ((unsigned char *) rgb_data)[offset + 2] = ((unsigned char *) image_data)[offset];
            }
        }
        free(image_data);
        image_data = (unsigned char *) rgb_data;
        channel = 3;
    }

    if (width % 4 != 0) {
        int new_width = width + (4 - width % 4);
        printf("%d is not pixel align, resize to %d, this will make the result shift slightly\n", width, new_width);
        void *resize_data = malloc(new_width * height * channel);
        stbir_resize_uint8(image_data, width, height, 0, (unsigned char *) resize_data, new_width, height, 0, channel);
        free(image_data);
        image_data = (unsigned char *) resize_data;
        *org_width = new_width;
    } else {
        *org_width = width;
    }

    *org_height = height;
    *org_ch = channel;

    return image_data;
}

void predict(rknn_tensor_attr *output_attrs, rknn_output *outputs, rknn_input *inputs, rknn_input_output_num *io_num,
             int input_width, int input_height, int input_channel, rknn_tensor_attr *input_attrs, void *resize_buf) {
    char *image_name = "/mnt/www/rknn_before.jpeg";
    unsigned char *input_data = NULL;
    /* Input preprocess */
    // Load image
    CImg<unsigned char> img(image_name);
    input_data = load_image(image_name, &img_height, &img_width, &img_channel, input_attrs);
    if (!input_data) {
        return;
    }

    printf("init drm\n");
    // DRM alloc buffer
    drm_fd = drm_init(&drm_ctx);
    drm_buf = drm_buf_alloc(&drm_ctx, drm_fd, img_width, img_height, input_channel * 8,
                            &buf_fd, &handle, &actual_size);
    memcpy(drm_buf, input_data, img_width * img_height * input_channel);

    // Letter box resize
    printf("resize\n");

    float img_wh_ratio = (float) img_width / (float) img_height;
    float input_wh_ratio = (float) input_width / (float) input_height;
    float resize_scale = 0;
    int resize_width;
    int resize_height;
    int h_pad;
    int w_pad;
    if (img_wh_ratio >= input_wh_ratio) {
        //pad height dim
        resize_scale = (float) input_width / (float) img_width;
        resize_width = input_width;
        resize_height = (int) ((float) img_height * resize_scale);
        w_pad = 0;
        h_pad = (input_height - resize_height) / 2;
    } else {
        //pad width dim
        resize_scale = (float) input_height / (float) img_height;
        resize_width = (int) ((float) img_width * resize_scale);
        resize_height = input_height;
        w_pad = (input_width - resize_width) / 2;;
        h_pad = 0;
    }
    // printf("w_pad: %d, h_pad: %d\n", w_pad, h_pad);
    // printf("resize_width: %d, resize_height: %d\n", resize_width, resize_height);

    printf("init rga_ctx\n");
    // Init rga context
    RGA_init(&rga_ctx);
    img_resize_slow(&rga_ctx, drm_buf, img_width, img_height, resize_buf, resize_width, resize_height, w_pad,
                    h_pad);
    inputs[0].buf = resize_buf;
    gettimeofday(&start_time, NULL);
    rknn_inputs_set(ctx, io_num->n_input, inputs);
    printf("rknn run\n");
    ret = rknn_run(ctx, NULL);
    ret = rknn_outputs_get(ctx, io_num->n_output, outputs, NULL);
    printf("post process\n");
    /* Post process */
    detect_result_group_t detect_result_group;
    std::vector<float> out_scales;
    std::vector<uint8_t> out_zps;
    for (int i = 0; i < io_num->n_output; ++i) {
        out_scales.push_back(output_attrs[i].scale);
        out_zps.push_back(output_attrs[i].zp);
    }
    printf("post process u8\n");
    post_process_u8((uint8_t *) outputs[0].buf, (uint8_t *) outputs[1].buf, (uint8_t *) outputs[2].buf,
                    input_height, input_width,
                    h_pad, w_pad, resize_scale, conf_threshold, nms_threshold, out_zps, out_scales,
                    &detect_result_group);

    printf("get time\n");
    gettimeofday(&stop_time, NULL);
    printf("once run use %f ms\n",
           (__get_us(stop_time) - __get_us(start_time)) / 1000);

    printf("draw object\n");
    // Draw Objects
    const unsigned char blue[] = {0, 0, 255};
    char score_result[64];
    for (int i = 0; i < detect_result_group.count; i++) {
        detect_result_t *det_result = &(detect_result_group.results[i]);
        printf("%s @ (%d %d %d %d) %f\n",
               det_result->name,
               det_result->box.left, det_result->box.top, det_result->box.right, det_result->box.bottom,
               det_result->prop);
        int x1 = det_result->box.left;
        int y1 = det_result->box.top;
        int x2 = det_result->box.right;
        int y2 = det_result->box.bottom;
        int ret = snprintf(score_result, sizeof score_result, "%f", det_result->prop);
        //draw box
        img.draw_rectangle(x1, y1, x2, y2, blue, 1, ~0U);
        img.draw_text(x1, y1 - 24, det_result->name, blue);
        img.draw_text(x1, y1 - 12, score_result, blue);
    }
    img.save("/mnt/www/rknn_after.bmp");
    ret = rknn_outputs_release(ctx, io_num->n_output, outputs);

    // loop test
    printf("loop test\n");
    int test_count = 50;
    gettimeofday(&start_time, NULL);
    for (int i = 0; i < test_count; ++i) {
        img_resize_slow(&rga_ctx, drm_buf, img_width, img_height, resize_buf, resize_width, resize_height, w_pad,
                        h_pad);
        rknn_inputs_set(ctx, io_num->n_input, inputs);
        ret = rknn_run(ctx, NULL);
        ret = rknn_outputs_get(ctx, io_num->n_output, outputs, NULL);

        post_process_u8((uint8_t *) outputs[0].buf, (uint8_t *) outputs[1].buf, (uint8_t *) outputs[2].buf,
                        input_height, input_width,
                        h_pad, w_pad, resize_scale, conf_threshold, nms_threshold, out_zps, out_scales,
                        &detect_result_group);
        ret = rknn_outputs_release(ctx, io_num->n_output, outputs);
    }

    gettimeofday(&stop_time, NULL);
    printf("run loop count = %d , average time: %f ms\n", test_count,
           (__get_us(stop_time) - __get_us(start_time)) / 1000.0 / test_count);

    drm_buf_destroy(&drm_ctx, drm_fd, buf_fd, handle, drm_buf, actual_size);
    drm_deinit(&drm_ctx, drm_fd);
    free(input_data);
}


/*-------------------------------------------
 * Main Functions
-------------------------------------------*/
int main(int argc, char **argv) {

    memset(&rga_ctx, 0, sizeof(rga_context));
    memset(&drm_ctx, 0, sizeof(drm_context));

    if (argc != 5) {
        printf("Usage: %s <rknn model> [fp/u8] [single_img/multi_imgs] <path>\n", argv[0]);
        // return -1;
    }

    // model_name = (char *) argv[1];
    // char *input_type = argv[3];
    // char *input_path = argv[4];

    printf("Post process with u8\n");
    printf("Test with single img\n");

    /* Create the neural network */
    printf("Loading model...\n");

    int model_data_size = 0;
    char *modelName = "/mnt/my_stuff/yolov5s_relu_rv1109_rv1126_out_opt.rknn";
    unsigned char *model_data = load_model(modelName, &model_data_size);
    printf("model_name:%s model_data_size:%d\n", modelName, model_data_size);

    ret = rknn_init(&ctx, model_data, model_data_size, 0);
    if (ret < 0) {
        printf("rknn_init error ret=%d\n", ret);
        return -1;
    }
    printf("Query SDK version...\n");

    /* Query sdk version */
    rknn_sdk_version version;
    ret = rknn_query(ctx, RKNN_QUERY_SDK_VERSION, &version, sizeof(rknn_sdk_version));
    if (ret < 0) {
        printf("rknn_init error ret=%d\n", ret);
        return -1;
    }
    printf("sdk version: %s driver version: %s\n", version.api_version, version.drv_version);

    /* Get input,output attr */
    rknn_input_output_num io_num;
    ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
    if (ret < 0) {
        printf("rknn_init error ret=%d\n", ret);
        return -1;
    }
    printf("model input num: %d, output num: %d\n", io_num.n_input, io_num.n_output);

    rknn_tensor_attr input_attrs[io_num.n_input];
    memset(input_attrs, 0, sizeof(input_attrs));
    for (int i = 0; i < io_num.n_input; i++) {
        input_attrs[i].index = i;
        ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(input_attrs[i]), sizeof(rknn_tensor_attr));
        if (ret < 0) {
            printf("rknn_init error ret=%d\n", ret);
            return -1;
        }
        printRKNNTensor(&(input_attrs[i]));
    }

    rknn_tensor_attr output_attrs[io_num.n_output];
    memset(output_attrs, 0, sizeof(output_attrs));
    for (int i = 0; i < io_num.n_output; i++) {
        output_attrs[i].index = i;
        ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr));
        printRKNNTensor(&(output_attrs[i]));
    }

    int input_channel = 3;
    int input_width = 0;
    int input_height = 0;
    if (input_attrs[0].fmt == RKNN_TENSOR_NCHW) {
        printf("model is NCHW input fmt\n");
        input_width = input_attrs[0].dims[0];
        input_height = input_attrs[0].dims[1];
    } else {
        printf("model is NHWC input fmt\n");
        input_width = input_attrs[0].dims[1];
        input_height = input_attrs[0].dims[2];
    }

    printf("model input height=%d, width=%d, channel=%d\n", input_height, input_width, input_channel);

    /* Init input tensor */
    rknn_input inputs[1];
    memset(inputs, 0, sizeof(inputs));
    inputs[0].index = 0;
    inputs[0].type = RKNN_TENSOR_UINT8;
    inputs[0].size = input_width * input_height * input_channel;
    inputs[0].fmt = RKNN_TENSOR_NHWC;
    inputs[0].pass_through = 0;

    /* Init output tensor */
    rknn_output outputs[io_num.n_output];
    memset(outputs, 0, sizeof(outputs));
    for (int i = 0; i < io_num.n_output; i++) {
        outputs[i].want_float = 0;
    }

    void *resize_buf = malloc(input_height * input_width * input_channel);
    // unsigned char *input_data = NULL;

    /* Single img input */
    printf("Single img input\n");
    while (1) {
        predict(output_attrs, outputs, inputs, &io_num,
                input_width, input_height, input_channel, input_attrs, resize_buf);

        usleep(10000);
    }

    // release
    ret = rknn_destroy(ctx);

    RGA_deinit(&rga_ctx);
    if (model_data) {
        free(model_data);
    }

    if (resize_buf) {
        free(resize_buf);
    }

    return 0;
}

使用自带的build.sh脚本编译安装就行.

接着 把两个应用跟nginx都跑起来, 就可以看到整个效果了.

在这里插入图片描述

我特么红外又忘了关了。。。

最后这个自动刷新的网站的html脚本如下:

<!DOCTYPE html>
<html>

<head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
</head>

<body>
    <center>
        <b>Marc's rknn_yolov5 play ground</b></br>
        <img src="rknn_before.jpeg" /> 
	<img src="rknn_after.bmp" />

    </center>

</body>
<script language="Javascript">
    function myrefresh() {
        window.location.reload();
    }
    setTimeout('myrefresh ()', 1000); // 指定 1 秒刷新一次(1401)
</script>

</html>

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值