一开始我以为跑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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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的示例代码, 进行推测:
注意几点:
具体代码main.cc如下:
/*-------------------------------------------
Includes
-------------------------------------------*/
#include
#include
#include
#include
#include
#include
#include
#define _BASETSD_H
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include
#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 [fp/u8] [single_img/multi_imgs] \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 groundb>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>