一开始我以为跑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 := echoGCC := /home/marc/rv_sdk/prebuilts/gcc/linux-x86/arm/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gccSYSROOT = /home/marc/rv_sdk/buildroot/output/rockchip_rv1126_rv1109/host/arm-buildroot-linux-gnueabihf/sysrootCFLAGS := -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/libLD_FLAGS := -lpthread -leasymedia -ldrm -lrockchip_mpp \-lavformat -lavcodec -lswresample -lavutil \-lasound -lv4l2 -lv4lconvert -lrga \-lRKAP_ANR -lRKAP_Common -lRKAP_3A \-lmd_share -lrkaiq -lod_shareCFLAGS += -DRKAIQSAMPLE_COMMON := common/sample_common_isp.call:$(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 1static 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 0x00000000static 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 0printf("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 0printf("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 sizeOSD_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);
#endifprintf("%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 0stJpegParam.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 1stJpegParam.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.}
#endifRK_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的示例代码, 进行推测:
注意几点:
- 使用模型要复制到app执行的目录下面, 名字是yolov5s_relu_rv1109_rv1126_out_opt.rknn
- COCO的标签也需要复制过去
- 原本执行的参数, 我直接写死了, 省得每次都要打参数进去.
- 输出路径同为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 5000using 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 imageCImg<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 bufferdrm_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 resizeprintf("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 dimresize_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 dimresize_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 contextRGA_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 Objectsconst 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 boximg.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 testprintf("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);}// releaseret = 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>