Browse Source

examples: update yolov5 demo

Signed-off-by: Randall Zhuo <randall.zhuo@rock-chips.com>
master
Randall Zhuo 2 years ago
parent
commit
5ada5f99bf
  1. BIN
      examples/rknn_yolov5_android_apk_demo/app/src/main/jniLibs/arm64-v8a/librknnrt.so
  2. 83
      examples/rknn_yolov5_demo/CMakeLists.txt
  3. 16
      examples/rknn_yolov5_demo/include/postprocess.h
  4. 16
      examples/rknn_yolov5_demo/include/preprocess.h
  5. 288
      examples/rknn_yolov5_demo/src/main.cc
  6. 340
      examples/rknn_yolov5_demo/src/main_video.cc
  7. 230
      examples/rknn_yolov5_demo/src/postprocess.cc
  8. 61
      examples/rknn_yolov5_demo/src/preprocess.cc

BIN
examples/rknn_yolov5_android_apk_demo/app/src/main/jniLibs/arm64-v8a/librknnrt.so

Binary file not shown.

83
examples/rknn_yolov5_demo/CMakeLists.txt

@ -15,7 +15,7 @@ set(CMAKE_SKIP_INSTALL_RPATH FALSE) @@ -15,7 +15,7 @@ set(CMAKE_SKIP_INSTALL_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
if (CMAKE_C_COMPILER MATCHES "aarch64")
if(CMAKE_C_COMPILER MATCHES "aarch64")
set(LIB_ARCH aarch64)
else()
set(LIB_ARCH armhf)
@ -32,17 +32,18 @@ else() @@ -32,17 +32,18 @@ else()
message(FATAL_ERROR "TARGET_SOC is not set, ref value: rk356x or rk3588 or rv110x")
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(RKNN_RT_LIB ${RKNN_API_PATH}/${CMAKE_ANDROID_ARCH_ABI}/librknnrt.so)
else()
set(RKNN_RT_LIB ${RKNN_API_PATH}/${LIB_ARCH}/librknnrt.so)
endif()
include_directories(${RKNN_API_PATH}/include)
include_directories(${CMAKE_SOURCE_DIR}/../3rdparty)
# opencv
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../3rdparty/opencv/OpenCV-android-sdk/sdk/native/jni/abi-${CMAKE_ANDROID_ARCH_ABI})
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../3rdparty/opencv/OpenCV-android-sdk/sdk/native/jni/abi-${CMAKE_ANDROID_ARCH_ABI})
else()
if(LIB_ARCH STREQUAL "armhf")
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../3rdparty/opencv/opencv-linux-armhf/share/OpenCV)
@ -50,9 +51,10 @@ else() @@ -50,9 +51,10 @@ else()
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../3rdparty/opencv/opencv-linux-aarch64/share/OpenCV)
endif()
endif()
find_package(OpenCV REQUIRED)
#rga
# rga
if(TARGET_SOC STREQUAL "rk356x")
set(RGA_PATH ${CMAKE_SOURCE_DIR}/../3rdparty/rga/RK356X)
elseif(TARGET_SOC STREQUAL "rk3588")
@ -60,41 +62,47 @@ elseif(TARGET_SOC STREQUAL "rk3588") @@ -60,41 +62,47 @@ elseif(TARGET_SOC STREQUAL "rk3588")
else()
message(FATAL_ERROR "TARGET_SOC is not set, ref value: rk356x or rk3588")
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(RGA_LIB ${RGA_PATH}/lib/Android/${CMAKE_ANDROID_ARCH_ABI}/librga.so)
else()
set(RGA_LIB ${RGA_PATH}/lib/Linux//${LIB_ARCH}/librga.so)
endif()
include_directories( ${RGA_PATH}/include)
include_directories(${RGA_PATH}/include)
# mpp
set(MPP_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/mpp)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(MPP_LIBS ${MPP_PATH}/${CMAKE_SYSTEM_NAME}/${LIB_ARCH}/librockchip_mpp.so)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(MPP_LIBS ${MPP_PATH}/${CMAKE_SYSTEM_NAME}/${CMAKE_ANDROID_ARCH_ABI}/libmpp.so)
endif()
include_directories(${MPP_PATH}/include)
# zlmediakit
set(ZLMEDIAKIT_PATH ${CMAKE_SOURCE_DIR}/../3rdparty/zlmediakit)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
include_directories(${ZLMEDIAKIT_PATH}/include)
set(ZLMEDIAKIT_LIBS ${ZLMEDIAKIT_PATH}/${LIB_ARCH}/libmk_api.so)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
include_directories(${ZLMEDIAKIT_PATH}/include)
set(ZLMEDIAKIT_LIBS ${ZLMEDIAKIT_PATH}/${LIB_ARCH}/libmk_api.so)
endif()
if (ZLMEDIAKIT_LIBS)
add_definitions(-DBUILD_VIDEO_RTSP)
if(ZLMEDIAKIT_LIBS)
add_definitions(-DBUILD_VIDEO_RTSP)
endif()
set(CMAKE_INSTALL_RPATH "lib")
# rknn_yolov5_demo
include_directories( ${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_SOURCE_DIR}/include)
add_executable(rknn_yolov5_demo
src/main.cc
src/postprocess.cc
src/main.cc
src/preprocess.cc
src/postprocess.cc
)
target_link_libraries(rknn_yolov5_demo
@ -103,24 +111,23 @@ target_link_libraries(rknn_yolov5_demo @@ -103,24 +111,23 @@ target_link_libraries(rknn_yolov5_demo
${OpenCV_LIBS}
)
if (MPP_LIBS)
add_executable(rknn_yolov5_video_demo
src/main_video.cc
src/postprocess.cc
utils/mpp_decoder.cpp
utils/mpp_encoder.cpp
utils/drawing.cpp
)
target_link_libraries(rknn_yolov5_video_demo
${RKNN_RT_LIB}
${RGA_LIB}
${OpenCV_LIBS}
${MPP_LIBS}
${ZLMEDIAKIT_LIBS}
)
if(MPP_LIBS)
add_executable(rknn_yolov5_video_demo
src/main_video.cc
src/postprocess.cc
utils/mpp_decoder.cpp
utils/mpp_encoder.cpp
utils/drawing.cpp
)
target_link_libraries(rknn_yolov5_video_demo
${RKNN_RT_LIB}
${RGA_LIB}
${OpenCV_LIBS}
${MPP_LIBS}
${ZLMEDIAKIT_LIBS}
)
endif()
# install target and libraries
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install/rknn_yolov5_demo_${CMAKE_SYSTEM_NAME})
install(TARGETS rknn_yolov5_demo DESTINATION ./)
@ -129,11 +136,11 @@ install(PROGRAMS ${RKNN_RT_LIB} DESTINATION lib) @@ -129,11 +136,11 @@ install(PROGRAMS ${RKNN_RT_LIB} DESTINATION lib)
install(PROGRAMS ${RGA_LIB} DESTINATION lib)
install(DIRECTORY model DESTINATION ./)
if (MPP_LIBS)
install(TARGETS rknn_yolov5_video_demo DESTINATION ./)
install(PROGRAMS ${MPP_LIBS} DESTINATION lib)
if(MPP_LIBS)
install(TARGETS rknn_yolov5_video_demo DESTINATION ./)
install(PROGRAMS ${MPP_LIBS} DESTINATION lib)
endif()
if (ZLMEDIAKIT_LIBS)
install(PROGRAMS ${ZLMEDIAKIT_LIBS} DESTINATION lib)
if(ZLMEDIAKIT_LIBS)
install(PROGRAMS ${ZLMEDIAKIT_LIBS} DESTINATION lib)
endif()

16
examples/rknn_yolov5_demo/include/postprocess.h

@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
#ifndef _RKNN_ZERO_COPY_DEMO_POSTPROCESS_H_
#define _RKNN_ZERO_COPY_DEMO_POSTPROCESS_H_
#ifndef _RKNN_YOLOV5_DEMO_POSTPROCESS_H_
#define _RKNN_YOLOV5_DEMO_POSTPROCESS_H_
#include <stdint.h>
#include <vector>
#define OBJ_NAME_MAX_SIZE 16
#define OBJ_NUMB_MAX_SIZE 64
#define OBJ_CLASS_NUM 80
#define NMS_THRESH 0.45
#define BOX_THRESH 0.25
#define PROP_BOX_SIZE (5+OBJ_CLASS_NUM)
#define OBJ_CLASS_NUM 80
#define NMS_THRESH 0.45
#define BOX_THRESH 0.25
#define PROP_BOX_SIZE (5 + OBJ_CLASS_NUM)
typedef struct _BOX_RECT
{
@ -34,9 +34,9 @@ typedef struct _detect_result_group_t @@ -34,9 +34,9 @@ typedef struct _detect_result_group_t
} detect_result_group_t;
int post_process(int8_t *input0, int8_t *input1, int8_t *input2, int model_in_h, int model_in_w,
float conf_threshold, float nms_threshold, float scale_w, float scale_h,
float conf_threshold, float nms_threshold, BOX_RECT pads, float scale_w, float scale_h,
std::vector<int32_t> &qnt_zps, std::vector<float> &qnt_scales,
detect_result_group_t *group);
void deinitPostProcess();
#endif //_RKNN_ZERO_COPY_DEMO_POSTPROCESS_H_
#endif //_RKNN_YOLOV5_DEMO_POSTPROCESS_H_

16
examples/rknn_yolov5_demo/include/preprocess.h

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
#ifndef _RKNN_YOLOV5_DEMO_PREPROCESS_H_
#define _RKNN_YOLOV5_DEMO_PREPROCESS_H_
#include <stdio.h>
#include "im2d.h"
#include "rga.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "postprocess.h"
void letterbox(const cv::Mat &image, cv::Mat &padded_image, BOX_RECT &pads, const float scale, const cv::Size &target_size, const cv::Scalar &pad_color = cv::Scalar(128, 128, 128));
int resize_rga(rga_buffer_t &src, rga_buffer_t &dst, const cv::Mat &image, cv::Mat &resized_image, const cv::Size &target_size);
#endif //_RKNN_YOLOV5_DEMO_PREPROCESS_H_

288
examples/rknn_yolov5_demo/src/main.cc

@ -24,23 +24,22 @@ @@ -24,23 +24,22 @@
#define _BASETSD_H
#include "RgaUtils.h"
#include "im2d.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "postprocess.h"
#include "rga.h"
#include "rknn_api.h"
#include "preprocess.h"
#define PERF_WITH_POST 1
/*-------------------------------------------
Functions
-------------------------------------------*/
static void dump_tensor_attr(rknn_tensor_attr* attr)
static void dump_tensor_attr(rknn_tensor_attr *attr)
{
std::string shape_str = attr->n_dims < 1 ? "" : std::to_string(attr->dims[0]);
for (int i = 1; i < attr->n_dims; ++i) {
for (int i = 1; i < attr->n_dims; ++i)
{
shape_str += ", " + std::to_string(attr->dims[i]);
}
@ -54,25 +53,28 @@ static void dump_tensor_attr(rknn_tensor_attr* attr) @@ -54,25 +53,28 @@ static void dump_tensor_attr(rknn_tensor_attr* attr)
double __get_us(struct timeval t) { return (t.tv_sec * 1000000 + t.tv_usec); }
static unsigned char* load_data(FILE* fp, size_t ofst, size_t sz)
static unsigned char *load_data(FILE *fp, size_t ofst, size_t sz)
{
unsigned char* data;
int ret;
unsigned char *data;
int ret;
data = NULL;
if (NULL == fp) {
if (NULL == fp)
{
return NULL;
}
ret = fseek(fp, ofst, SEEK_SET);
if (ret != 0) {
if (ret != 0)
{
printf("blob seek failure.\n");
return NULL;
}
data = (unsigned char*)malloc(sz);
if (data == NULL) {
data = (unsigned char *)malloc(sz);
if (data == NULL)
{
printf("buffer malloc failure.\n");
return NULL;
}
@ -80,13 +82,14 @@ static unsigned char* load_data(FILE* fp, size_t ofst, size_t sz) @@ -80,13 +82,14 @@ static unsigned char* load_data(FILE* fp, size_t ofst, size_t sz)
return data;
}
static unsigned char* load_model(const char* filename, int* model_size)
static unsigned char *load_model(const char *filename, int *model_size)
{
FILE* fp;
unsigned char* data;
FILE *fp;
unsigned char *data;
fp = fopen(filename, "rb");
if (NULL == fp) {
if (NULL == fp)
{
printf("Open file %s failed.\n", filename);
return NULL;
}
@ -102,11 +105,12 @@ static unsigned char* load_model(const char* filename, int* model_size) @@ -102,11 +105,12 @@ static unsigned char* load_model(const char* filename, int* model_size)
return data;
}
static int saveFloat(const char* file_name, float* output, int element_size)
static int saveFloat(const char *file_name, float *output, int element_size)
{
FILE* fp;
FILE *fp;
fp = fopen(file_name, "w");
for (int i = 0; i < element_size; i++) {
for (int i = 0; i < element_size; i++)
{
fprintf(fp, "%.6f\n", output[i]);
}
fclose(fp);
@ -116,65 +120,58 @@ static int saveFloat(const char* file_name, float* output, int element_size) @@ -116,65 +120,58 @@ static int saveFloat(const char* file_name, float* output, int element_size)
/*-------------------------------------------
Main Functions
-------------------------------------------*/
int main(int argc, char** argv)
int main(int argc, char **argv)
{
int status = 0;
char* model_name = NULL;
rknn_context ctx;
size_t actual_size = 0;
int img_width = 0;
int img_height = 0;
int img_channel = 0;
const float nms_threshold = NMS_THRESH;
const float box_conf_threshold = BOX_THRESH;
if (argc < 3)
{
printf("Usage: %s <rknn model> <input_image_path> <resize/letterbox> <output_image_path>\n", argv[0]);
return -1;
}
int ret;
rknn_context ctx;
size_t actual_size = 0;
int img_width = 0;
int img_height = 0;
int img_channel = 0;
const float nms_threshold = NMS_THRESH; // 默认的NMS阈值
const float box_conf_threshold = BOX_THRESH; // 默认的置信度阈值
struct timeval start_time, stop_time;
int ret;
char *model_name = (char *)argv[1];
char *input_path = argv[2];
std::string option = "letterbox";
std::string out_path = "./out.jpg";
if (argc >= 4)
{
option = argv[3];
}
if (argc >= 5)
{
out_path = argv[4];
}
// init rga context
rga_buffer_t src;
rga_buffer_t dst;
im_rect src_rect;
im_rect dst_rect;
memset(&src_rect, 0, sizeof(src_rect));
memset(&dst_rect, 0, sizeof(dst_rect));
memset(&src, 0, sizeof(src));
memset(&dst, 0, sizeof(dst));
if (argc != 3) {
printf("Usage: %s <rknn model> <jpg> \n", argv[0]);
return -1;
}
printf("post process config: box_conf_threshold = %.2f, nms_threshold = %.2f\n", box_conf_threshold, nms_threshold);
model_name = (char*)argv[1];
char* image_name = argv[2];
printf("Read %s ...\n", image_name);
cv::Mat orig_img = cv::imread(image_name, 1);
if (!orig_img.data) {
printf("cv::imread %s fail!\n", image_name);
return -1;
}
cv::Mat img;
cv::cvtColor(orig_img, img, cv::COLOR_BGR2RGB);
img_width = img.cols;
img_height = img.rows;
printf("img width = %d, img height = %d\n", img_width, img_height);
/* Create the neural network */
printf("Loading mode...\n");
int model_data_size = 0;
unsigned char* model_data = load_model(model_name, &model_data_size);
ret = rknn_init(&ctx, model_data, model_data_size, 0, NULL);
if (ret < 0) {
int model_data_size = 0;
unsigned char *model_data = load_model(model_name, &model_data_size);
ret = rknn_init(&ctx, model_data, model_data_size, 0, NULL);
if (ret < 0)
{
printf("rknn_init error ret=%d\n", ret);
return -1;
}
rknn_sdk_version version;
ret = rknn_query(ctx, RKNN_QUERY_SDK_VERSION, &version, sizeof(rknn_sdk_version));
if (ret < 0) {
if (ret < 0)
{
printf("rknn_init error ret=%d\n", ret);
return -1;
}
@ -182,7 +179,8 @@ int main(int argc, char** argv) @@ -182,7 +179,8 @@ int main(int argc, char** argv)
rknn_input_output_num io_num;
ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
if (ret < 0) {
if (ret < 0)
{
printf("rknn_init error ret=%d\n", ret);
return -1;
}
@ -190,10 +188,12 @@ int main(int argc, char** argv) @@ -190,10 +188,12 @@ int main(int argc, char** argv)
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++) {
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) {
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;
}
@ -202,24 +202,28 @@ int main(int argc, char** argv) @@ -202,24 +202,28 @@ int main(int argc, char** argv)
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++) {
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));
ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr));
dump_tensor_attr(&(output_attrs[i]));
}
int channel = 3;
int width = 0;
int height = 0;
if (input_attrs[0].fmt == RKNN_TENSOR_NCHW) {
int width = 0;
int height = 0;
if (input_attrs[0].fmt == RKNN_TENSOR_NCHW)
{
printf("model is NCHW input fmt\n");
channel = input_attrs[0].dims[1];
height = input_attrs[0].dims[2];
width = input_attrs[0].dims[3];
} else {
height = input_attrs[0].dims[2];
width = input_attrs[0].dims[3];
}
else
{
printf("model is NHWC input fmt\n");
height = input_attrs[0].dims[1];
width = input_attrs[0].dims[2];
height = input_attrs[0].dims[1];
width = input_attrs[0].dims[2];
channel = input_attrs[0].dims[3];
}
@ -227,36 +231,70 @@ int main(int argc, char** argv) @@ -227,36 +231,70 @@ int main(int argc, char** argv)
rknn_input inputs[1];
memset(inputs, 0, sizeof(inputs));
inputs[0].index = 0;
inputs[0].type = RKNN_TENSOR_UINT8;
inputs[0].size = width * height * channel;
inputs[0].fmt = RKNN_TENSOR_NHWC;
inputs[0].index = 0;
inputs[0].type = RKNN_TENSOR_UINT8;
inputs[0].size = width * height * channel;
inputs[0].fmt = RKNN_TENSOR_NHWC;
inputs[0].pass_through = 0;
// You may not need resize when src resulotion equals to dst resulotion
void* resize_buf = nullptr;
if (img_width != width || img_height != height) {
printf("resize with RGA!\n");
resize_buf = malloc(height * width * channel);
memset(resize_buf, 0x00, height * width * channel);
// 读取图片
printf("Read %s ...\n", input_path);
cv::Mat orig_img = cv::imread(input_path, 1);
if (!orig_img.data)
{
printf("cv::imread %s fail!\n", input_path);
return -1;
}
cv::Mat img;
cv::cvtColor(orig_img, img, cv::COLOR_BGR2RGB);
img_width = img.cols;
img_height = img.rows;
printf("img width = %d, img height = %d\n", img_width, img_height);
src = wrapbuffer_virtualaddr((void*)img.data, img_width, img_height, RK_FORMAT_RGB_888);
dst = wrapbuffer_virtualaddr((void*)resize_buf, width, height, RK_FORMAT_RGB_888);
ret = imcheck(src, dst, src_rect, dst_rect);
if (IM_STATUS_NOERROR != ret) {
printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
// 指定目标大小和预处理方式,默认使用LetterBox的预处理
BOX_RECT pads;
memset(&pads, 0, sizeof(BOX_RECT));
cv::Size target_size(width, height);
cv::Mat resized_img(target_size.height, target_size.width, CV_8UC3);
// 计算缩放比例
float scale_w = (float)target_size.width / img.cols;
float scale_h = (float)target_size.height / img.rows;
if (img_width != width || img_height != height)
{
// 直接缩放采用RGA加速
if (option == "resize")
{
printf("resize image by rga\n");
ret = resize_rga(src, dst, img, resized_img, target_size);
if (ret != 0)
{
fprintf(stderr, "resize with rga error\n");
return -1;
}
// 保存预处理图片
cv::imwrite("resize_input.jpg", resized_img);
}
else if (option == "letterbox")
{
printf("resize image with letterbox\n");
float min_scale = std::min(scale_w, scale_h);
scale_w = min_scale;
scale_h = min_scale;
letterbox(img, resized_img, pads, min_scale, target_size);
// 保存预处理图片
cv::imwrite("letterbox_input.jpg", resized_img);
}
else
{
fprintf(stderr, "Invalid resize option. Use 'resize' or 'letterbox'.\n");
return -1;
}
IM_STATUS STATUS = imresize(src, dst);
// for debug
cv::Mat resize_img(cv::Size(width, height), CV_8UC3, resize_buf);
cv::imwrite("resize_input.jpg", resize_img);
inputs[0].buf = resize_buf;
} else {
inputs[0].buf = (void*)img.data;
inputs[0].buf = resized_img.data;
}
else
{
inputs[0].buf = img.data;
}
gettimeofday(&start_time, NULL);
@ -264,33 +302,34 @@ int main(int argc, char** argv) @@ -264,33 +302,34 @@ int main(int argc, char** argv)
rknn_output outputs[io_num.n_output];
memset(outputs, 0, sizeof(outputs));
for (int i = 0; i < io_num.n_output; i++) {
for (int i = 0; i < io_num.n_output; i++)
{
outputs[i].want_float = 0;
}
// 执行推理
ret = rknn_run(ctx, NULL);
ret = rknn_outputs_get(ctx, io_num.n_output, outputs, NULL);
gettimeofday(&stop_time, NULL);
printf("once run use %f ms\n", (__get_us(stop_time) - __get_us(start_time)) / 1000);
// post process
float scale_w = (float)width / img_width;
float scale_h = (float)height / img_height;
// 后处理
detect_result_group_t detect_result_group;
std::vector<float> out_scales;
std::vector<int32_t> out_zps;
for (int i = 0; i < io_num.n_output; ++i) {
std::vector<float> out_scales;
std::vector<int32_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);
}
post_process((int8_t*)outputs[0].buf, (int8_t*)outputs[1].buf, (int8_t*)outputs[2].buf, height, width,
box_conf_threshold, nms_threshold, scale_w, scale_h, out_zps, out_scales, &detect_result_group);
post_process((int8_t *)outputs[0].buf, (int8_t *)outputs[1].buf, (int8_t *)outputs[2].buf, height, width,
box_conf_threshold, nms_threshold, pads, scale_w, scale_h, out_zps, out_scales, &detect_result_group);
// Draw Objects
// 画框和概率
char text[256];
for (int i = 0; i < detect_result_group.count; i++) {
detect_result_t* det_result = &(detect_result_group.results[i]);
for (int i = 0; i < detect_result_group.count; i++)
{
detect_result_t *det_result = &(detect_result_group.results[i]);
sprintf(text, "%s %.1f%%", det_result->name, det_result->prop * 100);
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);
@ -298,23 +337,25 @@ int main(int argc, char** argv) @@ -298,23 +337,25 @@ int main(int argc, char** argv)
int y1 = det_result->box.top;
int x2 = det_result->box.right;
int y2 = det_result->box.bottom;
rectangle(orig_img, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(255, 0, 0, 255), 3);
putText(orig_img, text, cv::Point(x1, y1 + 12), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
rectangle(orig_img, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(256, 0, 0, 256), 3);
putText(orig_img, text, cv::Point(x1, y1 + 12), cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(255, 255, 255));
}
imwrite("./out.jpg", orig_img);
printf("save detect result to %s\n", out_path.c_str());
imwrite(out_path, orig_img);
ret = rknn_outputs_release(ctx, io_num.n_output, outputs);
// loop test
// 耗时统计
int test_count = 10;
gettimeofday(&start_time, NULL);
for (int i = 0; i < test_count; ++i) {
for (int i = 0; i < test_count; ++i)
{
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);
#if PERF_WITH_POST
post_process((int8_t*)outputs[0].buf, (int8_t*)outputs[1].buf, (int8_t*)outputs[2].buf, height, width,
box_conf_threshold, nms_threshold, scale_w, scale_h, out_zps, out_scales, &detect_result_group);
post_process((int8_t *)outputs[0].buf, (int8_t *)outputs[1].buf, (int8_t *)outputs[2].buf, height, width,
box_conf_threshold, nms_threshold, pads, scale_w, scale_h, out_zps, out_scales, &detect_result_group);
#endif
ret = rknn_outputs_release(ctx, io_num.n_output, outputs);
}
@ -327,13 +368,10 @@ int main(int argc, char** argv) @@ -327,13 +368,10 @@ int main(int argc, char** argv)
// release
ret = rknn_destroy(ctx);
if (model_data) {
if (model_data)
{
free(model_data);
}
if (resize_buf) {
free(resize_buf);
}
return 0;
}

340
examples/rknn_yolov5_demo/src/main_video.cc

@ -38,26 +38,28 @@ @@ -38,26 +38,28 @@
#define OUT_VIDEO_PATH "out.h264"
typedef struct {
typedef struct
{
rknn_context rknn_ctx;
rknn_input_output_num io_num;
rknn_tensor_attr* input_attrs;
rknn_tensor_attr* output_attrs;
rknn_tensor_attr *input_attrs;
rknn_tensor_attr *output_attrs;
int model_channel;
int model_width;
int model_height;
FILE* out_fp;
MppDecoder* decoder;
MppEncoder* encoder;
FILE *out_fp;
MppDecoder *decoder;
MppEncoder *encoder;
} rknn_app_context_t;
typedef struct {
typedef struct
{
int width;
int height;
int width_stride;
int height_stride;
int format;
char* virt_addr;
char *virt_addr;
int fd;
} image_frame_t;
@ -65,7 +67,7 @@ typedef struct { @@ -65,7 +67,7 @@ typedef struct {
Functions
-------------------------------------------*/
static void dump_tensor_attr(rknn_tensor_attr* attr)
static void dump_tensor_attr(rknn_tensor_attr *attr)
{
printf(" index=%d, name=%s, n_dims=%d, dims=[%d, %d, %d, %d], n_elems=%d, size=%d, fmt=%s, type=%s, qnt_type=%s, "
"zp=%d, scale=%f\n",
@ -76,25 +78,28 @@ static void dump_tensor_attr(rknn_tensor_attr* attr) @@ -76,25 +78,28 @@ static void dump_tensor_attr(rknn_tensor_attr* attr)
double __get_us(struct timeval t) { return (t.tv_sec * 1000000 + t.tv_usec); }
static unsigned char* load_data(FILE* fp, size_t ofst, size_t sz)
static unsigned char *load_data(FILE *fp, size_t ofst, size_t sz)
{
unsigned char* data;
unsigned char *data;
int ret;
data = NULL;
if (NULL == fp) {
if (NULL == fp)
{
return NULL;
}
ret = fseek(fp, ofst, SEEK_SET);
if (ret != 0) {
if (ret != 0)
{
printf("blob seek failure.\n");
return NULL;
}
data = (unsigned char*)malloc(sz);
if (data == NULL) {
data = (unsigned char *)malloc(sz);
if (data == NULL)
{
printf("buffer malloc failure.\n");
return NULL;
}
@ -102,13 +107,14 @@ static unsigned char* load_data(FILE* fp, size_t ofst, size_t sz) @@ -102,13 +107,14 @@ static unsigned char* load_data(FILE* fp, size_t ofst, size_t sz)
return data;
}
static unsigned char* read_file_data(const char* filename, int* model_size)
static unsigned char *read_file_data(const char *filename, int *model_size)
{
FILE* fp;
unsigned char* data;
FILE *fp;
unsigned char *data;
fp = fopen(filename, "rb");
if (NULL == fp) {
if (NULL == fp)
{
printf("Open file %s failed.\n", filename);
return NULL;
}
@ -124,11 +130,13 @@ static unsigned char* read_file_data(const char* filename, int* model_size) @@ -124,11 +130,13 @@ static unsigned char* read_file_data(const char* filename, int* model_size)
return data;
}
static int write_data_to_file(const char *path, char *data, unsigned int size) {
static int write_data_to_file(const char *path, char *data, unsigned int size)
{
FILE *fp;
fp = fopen(path, "w");
if(fp == NULL) {
if (fp == NULL)
{
printf("open error: %s", path);
return -1;
}
@ -140,61 +148,71 @@ static int write_data_to_file(const char *path, char *data, unsigned int size) { @@ -140,61 +148,71 @@ static int write_data_to_file(const char *path, char *data, unsigned int size) {
return 0;
}
static int init_model(const char* model_path, rknn_app_context_t* app_ctx) {
static int init_model(const char *model_path, rknn_app_context_t *app_ctx)
{
int ret;
rknn_context ctx;
/* Create the neural network */
printf("Loading mode...\n");
int model_data_size = 0;
unsigned char* model_data = read_file_data(model_path, &model_data_size);
if (model_data == NULL) {
unsigned char *model_data = read_file_data(model_path, &model_data_size);
if (model_data == NULL)
{
return -1;
}
ret = rknn_init(&ctx, model_data, model_data_size, 0, NULL);
if (ret < 0) {
if (ret < 0)
{
printf("rknn_init error ret=%d\n", ret);
return -1;
}
if (model_data) {
if (model_data)
{
free(model_data);
}
rknn_sdk_version version;
ret = rknn_query(ctx, RKNN_QUERY_SDK_VERSION, &version, sizeof(rknn_sdk_version));
if (ret < 0) {
if (ret < 0)
{
printf("rknn_query RKNN_QUERY_SDK_VERSION error ret=%d\n", ret);
return -1;
}
printf("sdk version: %s driver version: %s\n", version.api_version, version.drv_version);
ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &app_ctx->io_num, sizeof(rknn_input_output_num));
if (ret < 0) {
if (ret < 0)
{
printf("rknn_query RKNN_QUERY_IN_OUT_NUM error ret=%d\n", ret);
return -1;
}
printf("model input num: %d, output num: %d\n", app_ctx->io_num.n_input, app_ctx->io_num.n_output);
rknn_tensor_attr* input_attrs = (rknn_tensor_attr*)malloc(app_ctx->io_num.n_input * sizeof(rknn_tensor_attr));
memset(input_attrs, 0, sizeof(input_attrs));
for (int i = 0; i < app_ctx->io_num.n_input; i++) {
rknn_tensor_attr *input_attrs = (rknn_tensor_attr *)malloc(app_ctx->io_num.n_input * sizeof(rknn_tensor_attr));
memset(input_attrs, 0, app_ctx->io_num.n_input * sizeof(rknn_tensor_attr));
for (int i = 0; i < app_ctx->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) {
if (ret < 0)
{
printf("rknn_query RKNN_QUERY_INPUT_ATTR error ret=%d\n", ret);
return -1;
}
dump_tensor_attr(&(input_attrs[i]));
}
rknn_tensor_attr* output_attrs = (rknn_tensor_attr*)malloc(app_ctx->io_num.n_output * sizeof(rknn_tensor_attr));
memset(output_attrs, 0, sizeof(output_attrs));
for (int i = 0; i < app_ctx->io_num.n_output; i++) {
rknn_tensor_attr *output_attrs = (rknn_tensor_attr *)malloc(app_ctx->io_num.n_output * sizeof(rknn_tensor_attr));
memset(output_attrs, 0, app_ctx->io_num.n_output * sizeof(rknn_tensor_attr));
for (int i = 0; i < app_ctx->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));
if (ret < 0) {
if (ret < 0)
{
printf("rknn_query RKNN_QUERY_OUTPUT_ATTR error ret=%d\n", ret);
return -1;
}
@ -205,15 +223,18 @@ static int init_model(const char* model_path, rknn_app_context_t* app_ctx) { @@ -205,15 +223,18 @@ static int init_model(const char* model_path, rknn_app_context_t* app_ctx) {
app_ctx->output_attrs = output_attrs;
app_ctx->rknn_ctx = ctx;
if (input_attrs[0].fmt == RKNN_TENSOR_NCHW) {
if (input_attrs[0].fmt == RKNN_TENSOR_NCHW)
{
printf("model is NCHW input fmt\n");
app_ctx->model_channel = input_attrs[0].dims[1];
app_ctx->model_height = input_attrs[0].dims[2];
app_ctx->model_width = input_attrs[0].dims[3];
} else {
app_ctx->model_height = input_attrs[0].dims[2];
app_ctx->model_width = input_attrs[0].dims[3];
}
else
{
printf("model is NHWC input fmt\n");
app_ctx->model_height = input_attrs[0].dims[1];
app_ctx->model_width = input_attrs[0].dims[2];
app_ctx->model_height = input_attrs[0].dims[1];
app_ctx->model_width = input_attrs[0].dims[2];
app_ctx->model_channel = input_attrs[0].dims[3];
}
printf("model input height=%d, width=%d, channel=%d\n", app_ctx->model_height, app_ctx->model_width, app_ctx->model_channel);
@ -221,8 +242,10 @@ static int init_model(const char* model_path, rknn_app_context_t* app_ctx) { @@ -221,8 +242,10 @@ static int init_model(const char* model_path, rknn_app_context_t* app_ctx) {
return 0;
}
static int release_model(rknn_app_context_t* app_ctx) {
if (app_ctx->rknn_ctx != 0) {
static int release_model(rknn_app_context_t *app_ctx)
{
if (app_ctx->rknn_ctx != 0)
{
rknn_destroy(app_ctx->rknn_ctx);
}
free(app_ctx->input_attrs);
@ -231,7 +254,8 @@ static int release_model(rknn_app_context_t* app_ctx) { @@ -231,7 +254,8 @@ static int release_model(rknn_app_context_t* app_ctx) {
return 0;
}
static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, detect_result_group_t* detect_result) {
static int inference_model(rknn_app_context_t *app_ctx, image_frame_t *img, detect_result_group_t *detect_result)
{
int ret;
rknn_context ctx = app_ctx->rknn_ctx;
int model_width = app_ctx->model_width;
@ -239,15 +263,15 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete @@ -239,15 +263,15 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete
int model_channel = app_ctx->model_channel;
struct timeval start_time, stop_time;
const float nms_threshold = NMS_THRESH;
const float box_conf_threshold = BOX_THRESH;
const float nms_threshold = NMS_THRESH;
const float box_conf_threshold = BOX_THRESH;
// You may not need resize when src resulotion equals to dst resulotion
void* resize_buf = nullptr;
void *resize_buf = nullptr;
// init rga context
rga_buffer_t src;
rga_buffer_t dst;
im_rect src_rect;
im_rect dst_rect;
im_rect src_rect;
im_rect dst_rect;
memset(&src_rect, 0, sizeof(src_rect));
memset(&dst_rect, 0, sizeof(dst_rect));
memset(&src, 0, sizeof(src));
@ -260,20 +284,21 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete @@ -260,20 +284,21 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete
rknn_input inputs[1];
memset(inputs, 0, sizeof(inputs));
inputs[0].index = 0;
inputs[0].type = RKNN_TENSOR_UINT8;
inputs[0].size = model_width * model_height * model_channel;
inputs[0].fmt = RKNN_TENSOR_NHWC;
inputs[0].index = 0;
inputs[0].type = RKNN_TENSOR_UINT8;
inputs[0].size = model_width * model_height * model_channel;
inputs[0].fmt = RKNN_TENSOR_NHWC;
inputs[0].pass_through = 0;
printf("resize with RGA!\n");
resize_buf = malloc(model_width * model_height * model_channel);
memset(resize_buf, 0, model_width * model_height * model_channel);
src = wrapbuffer_virtualaddr((void*)img->virt_addr, img->width, img->height, img->format, img->width_stride, img->height_stride);
dst = wrapbuffer_virtualaddr((void*)resize_buf, model_width, model_height, RK_FORMAT_RGB_888);
src = wrapbuffer_virtualaddr((void *)img->virt_addr, img->width, img->height, img->format, img->width_stride, img->height_stride);
dst = wrapbuffer_virtualaddr((void *)resize_buf, model_width, model_height, RK_FORMAT_RGB_888);
ret = imcheck(src, dst, src_rect, dst_rect);
if (IM_STATUS_NOERROR != ret) {
if (IM_STATUS_NOERROR != ret)
{
printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
return -1;
}
@ -286,7 +311,8 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete @@ -286,7 +311,8 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete
rknn_output outputs[app_ctx->io_num.n_output];
memset(outputs, 0, sizeof(outputs));
for (int i = 0; i < app_ctx->io_num.n_output; i++) {
for (int i = 0; i < app_ctx->io_num.n_output; i++)
{
outputs[i].want_float = 0;
}
@ -299,39 +325,45 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete @@ -299,39 +325,45 @@ static int inference_model(rknn_app_context_t* app_ctx, image_frame_t* img, dete
std::vector<float> out_scales;
std::vector<int32_t> out_zps;
for (int i = 0; i < app_ctx->io_num.n_output; ++i) {
for (int i = 0; i < app_ctx->io_num.n_output; ++i)
{
out_scales.push_back(app_ctx->output_attrs[i].scale);
out_zps.push_back(app_ctx->output_attrs[i].zp);
}
BOX_RECT pads;
memset(&pads, 0, sizeof(BOX_RECT));
post_process((int8_t*)outputs[0].buf, (int8_t*)outputs[1].buf, (int8_t*)outputs[2].buf, model_height, model_width,
box_conf_threshold, nms_threshold, scale_w, scale_h, out_zps, out_scales, detect_result);
post_process((int8_t *)outputs[0].buf, (int8_t *)outputs[1].buf, (int8_t *)outputs[2].buf, model_height, model_width,
box_conf_threshold, nms_threshold, pads, scale_w, scale_h, out_zps, out_scales, detect_result);
ret = rknn_outputs_release(ctx, app_ctx->io_num.n_output, outputs);
if (resize_buf) {
if (resize_buf)
{
free(resize_buf);
}
return 0;
}
void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_stride, int width, int height, int format, int fd, void* data) {
void mpp_decoder_frame_callback(void *userdata, int width_stride, int height_stride, int width, int height, int format, int fd, void *data)
{
rknn_app_context_t* ctx = (rknn_app_context_t*)userdata;
rknn_app_context_t *ctx = (rknn_app_context_t *)userdata;
int ret = 0;
static int frame_index = 0;
frame_index++;
void* mpp_frame = NULL;
void *mpp_frame = NULL;
int mpp_frame_fd = 0;
void* mpp_frame_addr = NULL;
void *mpp_frame_addr = NULL;
int enc_data_size;
rga_buffer_t origin;
rga_buffer_t src;
if (ctx->encoder == NULL) {
MppEncoder* mpp_encoder = new MppEncoder();
if (ctx->encoder == NULL)
{
MppEncoder *mpp_encoder = new MppEncoder();
MppEncoderParams enc_params;
memset(&enc_params, 0, sizeof(MppEncoderParams));
enc_params.width = width;
@ -339,8 +371,8 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str @@ -339,8 +371,8 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str
enc_params.hor_stride = width_stride;
enc_params.ver_stride = height_stride;
enc_params.fmt = MPP_FMT_YUV420SP;
//enc_params.type = MPP_VIDEO_CodingHEVC;
//Note: rk3562只能支持h264格式的视频流
// enc_params.type = MPP_VIDEO_CodingHEVC;
// Note: rk3562只能支持h264格式的视频流
enc_params.type = MPP_VIDEO_CodingAVC;
mpp_encoder->Init(enc_params, NULL);
@ -348,7 +380,7 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str @@ -348,7 +380,7 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str
}
int enc_buf_size = ctx->encoder->GetFrameSize();
char* enc_data = (char*)malloc(enc_buf_size);
char *enc_data = (char *)malloc(enc_buf_size);
image_frame_t img;
img.width = width;
@ -356,13 +388,14 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str @@ -356,13 +388,14 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str
img.width_stride = width_stride;
img.height_stride = height_stride;
img.fd = fd;
img.virt_addr = (char*)data;
img.virt_addr = (char *)data;
img.format = RK_FORMAT_YCbCr_420_SP;
detect_result_group_t detect_result;
memset(&detect_result, 0, sizeof(detect_result_group_t));
ret = inference_model(ctx, &img, &detect_result);
if (ret != 0) {
if (ret != 0)
{
printf("inference model fail\n");
goto RET;
}
@ -377,20 +410,22 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str @@ -377,20 +410,22 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str
imcopy(origin, src);
// Draw objects
for (int i = 0; i < detect_result.count; i++) {
detect_result_t* det_result = &(detect_result.results[i]);
for (int i = 0; i < detect_result.count; i++)
{
detect_result_t *det_result = &(detect_result.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;
draw_rectangle_yuv420sp((unsigned char*)mpp_frame_addr, width_stride, height_stride, x1, y1, x2-x1+1, y2-y1+1, 0x00FF0000, 4);
draw_rectangle_yuv420sp((unsigned char *)mpp_frame_addr, width_stride, height_stride, x1, y1, x2 - x1 + 1, y2 - y1 + 1, 0x00FF0000, 4);
}
// Encode to file
// Write header on first frame
if (frame_index == 1) {
if (frame_index == 1)
{
enc_data_size = ctx->encoder->GetHeader(enc_data, enc_buf_size);
fwrite(enc_data, 1, enc_data_size, ctx->out_fp);
}
@ -399,79 +434,91 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str @@ -399,79 +434,91 @@ void mpp_decoder_frame_callback(void* userdata, int width_stride, int height_str
fwrite(enc_data, 1, enc_data_size, ctx->out_fp);
RET:
if (enc_data != nullptr) {
if (enc_data != nullptr)
{
free(enc_data);
}
}
int process_video_file(rknn_app_context_t* ctx, const char* path)
int process_video_file(rknn_app_context_t *ctx, const char *path)
{
int video_size;
char* video_data = (char*)read_file_data(path, &video_size);
char* video_data_end = video_data + video_size;
char *video_data = (char *)read_file_data(path, &video_size);
char *video_data_end = video_data + video_size;
printf("read video size=%d\n", video_size);
const int SIZE = 8192;
char* video_data_ptr = video_data;
do {
int pkt_eos = 0;
int size = SIZE;
if (video_data_ptr + size >= video_data_end) {
pkt_eos = 1;
size = video_data_end - video_data_ptr;
}
char *video_data_ptr = video_data;
do
{
int pkt_eos = 0;
int size = SIZE;
if (video_data_ptr + size >= video_data_end)
{
pkt_eos = 1;
size = video_data_end - video_data_ptr;
}
ctx->decoder->Decode((uint8_t*)video_data_ptr, size, pkt_eos);
ctx->decoder->Decode((uint8_t *)video_data_ptr, size, pkt_eos);
video_data_ptr += size;
video_data_ptr += size;
if (video_data_ptr >= video_data_end) {
printf("reset decoder\n");
break;
}
if (video_data_ptr >= video_data_end)
{
printf("reset decoder\n");
break;
}
// LOGD("video_data_ptr=%p video_data_end=%p", video_data_ptr, video_data_end);
// usleep(10*1000);
// LOGD("video_data_ptr=%p video_data_end=%p", video_data_ptr, video_data_end);
// usleep(10*1000);
} while (1);
return 0;
}
#if defined(BUILD_VIDEO_RTSP)
void API_CALL on_track_frame_out(void *user_data, mk_frame frame) {
rknn_app_context_t *ctx = (rknn_app_context_t *) user_data;
void API_CALL on_track_frame_out(void *user_data, mk_frame frame)
{
rknn_app_context_t *ctx = (rknn_app_context_t *)user_data;
printf("on_track_frame_out ctx=%p\n", ctx);
const char* data = mk_frame_get_data(frame);
const char *data = mk_frame_get_data(frame);
size_t size = mk_frame_get_data_size(frame);
printf("decoder=%p\n", ctx->decoder);
ctx->decoder->Decode((uint8_t*)data, size, 0);
ctx->decoder->Decode((uint8_t *)data, size, 0);
}
void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *err_msg, mk_track tracks[],
int track_count) {
rknn_app_context_t *ctx = (rknn_app_context_t *) user_data;
if (err_code == 0) {
//success
printf("play success!");
int i;
for (i = 0; i < track_count; ++i) {
if (mk_track_is_video(tracks[i])) {
log_info("got video track: %s", mk_track_codec_name(tracks[i]));
//监听track数据回调
mk_track_add_delegate(tracks[i], on_track_frame_out, user_data);
}
int track_count)
{
rknn_app_context_t *ctx = (rknn_app_context_t *)user_data;
if (err_code == 0)
{
// success
printf("play success!");
int i;
for (i = 0; i < track_count; ++i)
{
if (mk_track_is_video(tracks[i]))
{
log_info("got video track: %s", mk_track_codec_name(tracks[i]));
// 监听track数据回调
mk_track_add_delegate(tracks[i], on_track_frame_out, user_data);
}
} else {
printf("play failed: %d %s", err_code, err_msg);
}
}
else
{
printf("play failed: %d %s", err_code, err_msg);
}
}
void API_CALL on_mk_shutdown_func(void *user_data, int err_code, const char *err_msg, mk_track tracks[], int track_count) {
void API_CALL on_mk_shutdown_func(void *user_data, int err_code, const char *err_msg, mk_track tracks[], int track_count)
{
printf("play interrupted: %d %s", err_code, err_msg);
}
int process_video_rtsp(rknn_app_context_t* ctx, const char* url)
int process_video_rtsp(rknn_app_context_t *ctx, const char *url)
{
mk_config config;
memset(&config, 0, sizeof(mk_config));
@ -485,8 +532,9 @@ int process_video_rtsp(rknn_app_context_t* ctx, const char* url) @@ -485,8 +532,9 @@ int process_video_rtsp(rknn_app_context_t* ctx, const char* url)
printf("enter any key to exit\n");
getchar();
if (player) {
mk_player_release(player);
if (player)
{
mk_player_release(player);
}
return 0;
}
@ -495,70 +543,80 @@ int process_video_rtsp(rknn_app_context_t* ctx, const char* url) @@ -495,70 +543,80 @@ int process_video_rtsp(rknn_app_context_t* ctx, const char* url)
/*-------------------------------------------
Main Functions
-------------------------------------------*/
int main(int argc, char** argv)
int main(int argc, char **argv)
{
int status = 0;
int ret;
if (argc != 4) {
if (argc != 4)
{
printf("Usage: %s <rknn_model> <video_path> <video_type 264/265> \n", argv[0]);
return -1;
}
char* model_name = (char*)argv[1];
char* video_name = argv[2];
char *model_name = (char *)argv[1];
char *video_name = argv[2];
int video_type = atoi(argv[3]);
rknn_app_context_t app_ctx;
memset(&app_ctx, 0, sizeof(rknn_app_context_t));
ret = init_model(model_name, &app_ctx);
if (ret != 0) {
if (ret != 0)
{
printf("init model fail\n");
return -1;
}
if (app_ctx.decoder == NULL) {
MppDecoder* decoder = new MppDecoder();
if (app_ctx.decoder == NULL)
{
MppDecoder *decoder = new MppDecoder();
decoder->Init(video_type, 30, &app_ctx);
decoder->SetCallback(mpp_decoder_frame_callback);
app_ctx.decoder = decoder;
}
if (app_ctx.out_fp == NULL) {
FILE* fp = fopen(OUT_VIDEO_PATH, "w");
if(fp == NULL) {
printf("open %s error\n", OUT_VIDEO_PATH);
return -1;
if (app_ctx.out_fp == NULL)
{
FILE *fp = fopen(OUT_VIDEO_PATH, "w");
if (fp == NULL)
{
printf("open %s error\n", OUT_VIDEO_PATH);
return -1;
}
app_ctx.out_fp = fp;
}
printf("app_ctx=%p decoder=%p\n", &app_ctx, app_ctx.decoder);
if (strncmp(video_name, "rtsp", 4) == 0) {
if (strncmp(video_name, "rtsp", 4) == 0)
{
#if defined(BUILD_VIDEO_RTSP)
process_video_rtsp(&app_ctx, video_name);
process_video_rtsp(&app_ctx, video_name);
#else
printf("rtsp no support\n");
printf("rtsp no support\n");
#endif
} else {
}
else
{
process_video_file(&app_ctx, video_name);
}
printf("waiting finish\n");
usleep(3*1000*1000);
usleep(3 * 1000 * 1000);
// release
fflush(app_ctx.out_fp);
fclose(app_ctx.out_fp);
if (app_ctx.decoder != nullptr) {
delete(app_ctx.decoder);
if (app_ctx.decoder != nullptr)
{
delete (app_ctx.decoder);
app_ctx.decoder = nullptr;
}
if (app_ctx.encoder != nullptr) {
delete(app_ctx.encoder);
if (app_ctx.encoder != nullptr)
{
delete (app_ctx.encoder);
app_ctx.encoder = nullptr;
}

230
examples/rknn_yolov5_demo/src/postprocess.cc

@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
#include <vector>
#define LABEL_NALE_TXT_PATH "./model/coco_80_labels_list.txt"
static char* labels[OBJ_CLASS_NUM];
static char *labels[OBJ_CLASS_NUM];
const int anchor0[6] = {10, 13, 16, 30, 33, 23};
const int anchor1[6] = {30, 61, 62, 45, 59, 119};
@ -33,24 +33,26 @@ const int anchor2[6] = {116, 90, 156, 198, 373, 326}; @@ -33,24 +33,26 @@ const int anchor2[6] = {116, 90, 156, 198, 373, 326};
inline static int clamp(float val, int min, int max) { return val > min ? (val < max ? val : max) : min; }
char* readLine(FILE* fp, char* buffer, int* len)
char *readLine(FILE *fp, char *buffer, int *len)
{
int ch;
int i = 0;
int ch;
int i = 0;
size_t buff_len = 0;
buffer = (char*)malloc(buff_len + 1);
buffer = (char *)malloc(buff_len + 1);
if (!buffer)
return NULL; // Out of memory
while ((ch = fgetc(fp)) != '\n' && ch != EOF) {
while ((ch = fgetc(fp)) != '\n' && ch != EOF)
{
buff_len++;
void* tmp = realloc(buffer, buff_len + 1);
if (tmp == NULL) {
void *tmp = realloc(buffer, buff_len + 1);
if (tmp == NULL)
{
free(buffer);
return NULL; // Out of memory
}
buffer = (char*)tmp;
buffer = (char *)tmp;
buffer[i] = (char)ch;
i++;
@ -60,26 +62,29 @@ char* readLine(FILE* fp, char* buffer, int* len) @@ -60,26 +62,29 @@ char* readLine(FILE* fp, char* buffer, int* len)
*len = buff_len;
// Detect end
if (ch == EOF && (i == 0 || ferror(fp))) {
if (ch == EOF && (i == 0 || ferror(fp)))
{
free(buffer);
return NULL;
}
return buffer;
}
int readLines(const char* fileName, char* lines[], int max_line)
int readLines(const char *fileName, char *lines[], int max_line)
{
FILE* file = fopen(fileName, "r");
char* s;
int i = 0;
int n = 0;
FILE *file = fopen(fileName, "r");
char *s;
int i = 0;
int n = 0;
if (file == NULL) {
if (file == NULL)
{
printf("Open %s fail!\n", fileName);
return -1;
}
while ((s = readLine(file, s, &n)) != NULL) {
while ((s = readLine(file, s, &n)) != NULL)
{
lines[i++] = s;
if (i >= max_line)
break;
@ -88,7 +93,7 @@ int readLines(const char* fileName, char* lines[], int max_line) @@ -88,7 +93,7 @@ int readLines(const char* fileName, char* lines[], int max_line)
return i;
}
int loadLabelName(const char* locationFilename, char* label[])
int loadLabelName(const char *locationFilename, char *label[])
{
printf("loadLabelName %s\n", locationFilename);
readLines(locationFilename, label, OBJ_CLASS_NUM);
@ -105,17 +110,21 @@ static float CalculateOverlap(float xmin0, float ymin0, float xmax0, float ymax0 @@ -105,17 +110,21 @@ static float CalculateOverlap(float xmin0, float ymin0, float xmax0, float ymax0
return u <= 0.f ? 0.f : (i / u);
}
static int nms(int validCount, std::vector<float>& outputLocations, std::vector<int> classIds, std::vector<int>& order,
static int nms(int validCount, std::vector<float> &outputLocations, std::vector<int> classIds, std::vector<int> &order,
int filterId, float threshold)
{
for (int i = 0; i < validCount; ++i) {
if (order[i] == -1 || classIds[i] != filterId) {
for (int i = 0; i < validCount; ++i)
{
if (order[i] == -1 || classIds[i] != filterId)
{
continue;
}
int n = order[i];
for (int j = i + 1; j < validCount; ++j) {
for (int j = i + 1; j < validCount; ++j)
{
int m = order[j];
if (m == -1 || classIds[i] != filterId) {
if (m == -1 || classIds[i] != filterId)
{
continue;
}
float xmin0 = outputLocations[n * 4 + 0];
@ -130,7 +139,8 @@ static int nms(int validCount, std::vector<float>& outputLocations, std::vector< @@ -130,7 +139,8 @@ static int nms(int validCount, std::vector<float>& outputLocations, std::vector<
float iou = CalculateOverlap(xmin0, ymin0, xmax0, ymax0, xmin1, ymin1, xmax1, ymax1);
if (iou > threshold) {
if (iou > threshold)
{
order[j] = -1;
}
}
@ -138,28 +148,32 @@ static int nms(int validCount, std::vector<float>& outputLocations, std::vector< @@ -138,28 +148,32 @@ static int nms(int validCount, std::vector<float>& outputLocations, std::vector<
return 0;
}
static int quick_sort_indice_inverse(std::vector<float>& input, int left, int right, std::vector<int>& indices)
static int quick_sort_indice_inverse(std::vector<float> &input, int left, int right, std::vector<int> &indices)
{
float key;
int key_index;
int low = left;
int high = right;
if (left < right) {
int key_index;
int low = left;
int high = right;
if (left < right)
{
key_index = indices[left];
key = input[left];
while (low < high) {
while (low < high && input[high] <= key) {
key = input[left];
while (low < high)
{
while (low < high && input[high] <= key)
{
high--;
}
input[low] = input[high];
input[low] = input[high];
indices[low] = indices[high];
while (low < high && input[low] >= key) {
while (low < high && input[low] >= key)
{
low++;
}
input[high] = input[low];
input[high] = input[low];
indices[high] = indices[low];
}
input[low] = key;
input[low] = key;
indices[low] = key_index;
quick_sort_indice_inverse(input, left, low - 1, indices);
quick_sort_indice_inverse(input, low + 1, right, indices);
@ -179,49 +193,56 @@ inline static int32_t __clip(float val, float min, float max) @@ -179,49 +193,56 @@ inline static int32_t __clip(float val, float min, float max)
static int8_t qnt_f32_to_affine(float f32, int32_t zp, float scale)
{
float dst_val = (f32 / scale) + zp;
int8_t res = (int8_t)__clip(dst_val, -128, 127);
float dst_val = (f32 / scale) + zp;
int8_t res = (int8_t)__clip(dst_val, -128, 127);
return res;
}
static float deqnt_affine_to_f32(int8_t qnt, int32_t zp, float scale) { return ((float)qnt - (float)zp) * scale; }
static int process(int8_t* input, int* anchor, int grid_h, int grid_w, int height, int width, int stride,
std::vector<float>& boxes, std::vector<float>& objProbs, std::vector<int>& classId, float threshold,
static int process(int8_t *input, int *anchor, int grid_h, int grid_w, int height, int width, int stride,
std::vector<float> &boxes, std::vector<float> &objProbs, std::vector<int> &classId, float threshold,
int32_t zp, float scale)
{
int validCount = 0;
int grid_len = grid_h * grid_w;
int8_t thres_i8 = qnt_f32_to_affine(threshold, zp, scale);
for (int a = 0; a < 3; a++) {
for (int i = 0; i < grid_h; i++) {
for (int j = 0; j < grid_w; j++) {
int validCount = 0;
int grid_len = grid_h * grid_w;
int8_t thres_i8 = qnt_f32_to_affine(threshold, zp, scale);
for (int a = 0; a < 3; a++)
{
for (int i = 0; i < grid_h; i++)
{
for (int j = 0; j < grid_w; j++)
{
int8_t box_confidence = input[(PROP_BOX_SIZE * a + 4) * grid_len + i * grid_w + j];
if (box_confidence >= thres_i8) {
int offset = (PROP_BOX_SIZE * a) * grid_len + i * grid_w + j;
int8_t* in_ptr = input + offset;
float box_x = (deqnt_affine_to_f32(*in_ptr, zp, scale)) * 2.0 - 0.5;
float box_y = (deqnt_affine_to_f32(in_ptr[grid_len], zp, scale)) * 2.0 - 0.5;
float box_w = (deqnt_affine_to_f32(in_ptr[2 * grid_len], zp, scale)) * 2.0;
float box_h = (deqnt_affine_to_f32(in_ptr[3 * grid_len], zp, scale)) * 2.0;
box_x = (box_x + j) * (float)stride;
box_y = (box_y + i) * (float)stride;
box_w = box_w * box_w * (float)anchor[a * 2];
box_h = box_h * box_h * (float)anchor[a * 2 + 1];
if (box_confidence >= thres_i8)
{
int offset = (PROP_BOX_SIZE * a) * grid_len + i * grid_w + j;
int8_t *in_ptr = input + offset;
float box_x = (deqnt_affine_to_f32(*in_ptr, zp, scale)) * 2.0 - 0.5;
float box_y = (deqnt_affine_to_f32(in_ptr[grid_len], zp, scale)) * 2.0 - 0.5;
float box_w = (deqnt_affine_to_f32(in_ptr[2 * grid_len], zp, scale)) * 2.0;
float box_h = (deqnt_affine_to_f32(in_ptr[3 * grid_len], zp, scale)) * 2.0;
box_x = (box_x + j) * (float)stride;
box_y = (box_y + i) * (float)stride;
box_w = box_w * box_w * (float)anchor[a * 2];
box_h = box_h * box_h * (float)anchor[a * 2 + 1];
box_x -= (box_w / 2.0);
box_y -= (box_h / 2.0);
int8_t maxClassProbs = in_ptr[5 * grid_len];
int maxClassId = 0;
for (int k = 1; k < OBJ_CLASS_NUM; ++k) {
int maxClassId = 0;
for (int k = 1; k < OBJ_CLASS_NUM; ++k)
{
int8_t prob = in_ptr[(5 + k) * grid_len];
if (prob > maxClassProbs) {
maxClassId = k;
if (prob > maxClassProbs)
{
maxClassId = k;
maxClassProbs = prob;
}
}
if (maxClassProbs>thres_i8){
objProbs.push_back((deqnt_affine_to_f32(maxClassProbs, zp, scale))* (deqnt_affine_to_f32(box_confidence, zp, scale)));
if (maxClassProbs > thres_i8)
{
objProbs.push_back((deqnt_affine_to_f32(maxClassProbs, zp, scale)) * (deqnt_affine_to_f32(box_confidence, zp, scale)));
classId.push_back(maxClassId);
validCount++;
boxes.push_back(box_x);
@ -236,15 +257,17 @@ static int process(int8_t* input, int* anchor, int grid_h, int grid_w, int heigh @@ -236,15 +257,17 @@ static int process(int8_t* input, int* anchor, int grid_h, int grid_w, int heigh
return validCount;
}
int post_process(int8_t* input0, int8_t* input1, int8_t* input2, int model_in_h, int model_in_w, float conf_threshold,
float nms_threshold, float scale_w, float scale_h, std::vector<int32_t>& qnt_zps,
std::vector<float>& qnt_scales, detect_result_group_t* group)
int post_process(int8_t *input0, int8_t *input1, int8_t *input2, int model_in_h, int model_in_w, float conf_threshold,
float nms_threshold, BOX_RECT pads, float scale_w, float scale_h, std::vector<int32_t> &qnt_zps,
std::vector<float> &qnt_scales, detect_result_group_t *group)
{
static int init = -1;
if (init == -1) {
if (init == -1)
{
int ret = 0;
ret = loadLabelName(LABEL_NALE_TXT_PATH, labels);
if (ret < 0) {
ret = loadLabelName(LABEL_NALE_TXT_PATH, labels);
if (ret < 0)
{
return -1;
}
@ -254,40 +277,42 @@ int post_process(int8_t* input0, int8_t* input1, int8_t* input2, int model_in_h, @@ -254,40 +277,42 @@ int post_process(int8_t* input0, int8_t* input1, int8_t* input2, int model_in_h,
std::vector<float> filterBoxes;
std::vector<float> objProbs;
std::vector<int> classId;
std::vector<int> classId;
// stride 8
int stride0 = 8;
int grid_h0 = model_in_h / stride0;
int grid_w0 = model_in_w / stride0;
int stride0 = 8;
int grid_h0 = model_in_h / stride0;
int grid_w0 = model_in_w / stride0;
int validCount0 = 0;
validCount0 = process(input0, (int*)anchor0, grid_h0, grid_w0, model_in_h, model_in_w, stride0, filterBoxes, objProbs,
validCount0 = process(input0, (int *)anchor0, grid_h0, grid_w0, model_in_h, model_in_w, stride0, filterBoxes, objProbs,
classId, conf_threshold, qnt_zps[0], qnt_scales[0]);
// stride 16
int stride1 = 16;
int grid_h1 = model_in_h / stride1;
int grid_w1 = model_in_w / stride1;
int stride1 = 16;
int grid_h1 = model_in_h / stride1;
int grid_w1 = model_in_w / stride1;
int validCount1 = 0;
validCount1 = process(input1, (int*)anchor1, grid_h1, grid_w1, model_in_h, model_in_w, stride1, filterBoxes, objProbs,
validCount1 = process(input1, (int *)anchor1, grid_h1, grid_w1, model_in_h, model_in_w, stride1, filterBoxes, objProbs,
classId, conf_threshold, qnt_zps[1], qnt_scales[1]);
// stride 32
int stride2 = 32;
int grid_h2 = model_in_h / stride2;
int grid_w2 = model_in_w / stride2;
int stride2 = 32;
int grid_h2 = model_in_h / stride2;
int grid_w2 = model_in_w / stride2;
int validCount2 = 0;
validCount2 = process(input2, (int*)anchor2, grid_h2, grid_w2, model_in_h, model_in_w, stride2, filterBoxes, objProbs,
validCount2 = process(input2, (int *)anchor2, grid_h2, grid_w2, model_in_h, model_in_w, stride2, filterBoxes, objProbs,
classId, conf_threshold, qnt_zps[2], qnt_scales[2]);
int validCount = validCount0 + validCount1 + validCount2;
// no object detect
if (validCount <= 0) {
if (validCount <= 0)
{
return 0;
}
std::vector<int> indexArray;
for (int i = 0; i < validCount; ++i) {
for (int i = 0; i < validCount; ++i)
{
indexArray.push_back(i);
}
@ -295,32 +320,35 @@ int post_process(int8_t* input0, int8_t* input1, int8_t* input2, int model_in_h, @@ -295,32 +320,35 @@ int post_process(int8_t* input0, int8_t* input1, int8_t* input2, int model_in_h,
std::set<int> class_set(std::begin(classId), std::end(classId));
for (auto c : class_set) {
for (auto c : class_set)
{
nms(validCount, filterBoxes, classId, indexArray, c, nms_threshold);
}
int last_count = 0;
group->count = 0;
group->count = 0;
/* box valid detect target */
for (int i = 0; i < validCount; ++i) {
if (indexArray[i] == -1 || last_count >= OBJ_NUMB_MAX_SIZE) {
for (int i = 0; i < validCount; ++i)
{
if (indexArray[i] == -1 || last_count >= OBJ_NUMB_MAX_SIZE)
{
continue;
}
int n = indexArray[i];
float x1 = filterBoxes[n * 4 + 0];
float y1 = filterBoxes[n * 4 + 1];
float x2 = x1 + filterBoxes[n * 4 + 2];
float y2 = y1 + filterBoxes[n * 4 + 3];
int id = classId[n];
float x1 = filterBoxes[n * 4 + 0] - pads.left;
float y1 = filterBoxes[n * 4 + 1] - pads.top;
float x2 = x1 + filterBoxes[n * 4 + 2];
float y2 = y1 + filterBoxes[n * 4 + 3];
int id = classId[n];
float obj_conf = objProbs[i];
group->results[last_count].box.left = (int)(clamp(x1, 0, model_in_w) / scale_w);
group->results[last_count].box.top = (int)(clamp(y1, 0, model_in_h) / scale_h);
group->results[last_count].box.right = (int)(clamp(x2, 0, model_in_w) / scale_w);
group->results[last_count].box.left = (int)(clamp(x1, 0, model_in_w) / scale_w);
group->results[last_count].box.top = (int)(clamp(y1, 0, model_in_h) / scale_h);
group->results[last_count].box.right = (int)(clamp(x2, 0, model_in_w) / scale_w);
group->results[last_count].box.bottom = (int)(clamp(y2, 0, model_in_h) / scale_h);
group->results[last_count].prop = obj_conf;
char* label = labels[id];
group->results[last_count].prop = obj_conf;
char *label = labels[id];
strncpy(group->results[last_count].name, label, OBJ_NAME_MAX_SIZE);
// printf("result %2d: (%4d, %4d, %4d, %4d), %s\n", i, group->results[last_count].box.left,
@ -335,8 +363,10 @@ int post_process(int8_t* input0, int8_t* input1, int8_t* input2, int model_in_h, @@ -335,8 +363,10 @@ int post_process(int8_t* input0, int8_t* input1, int8_t* input2, int model_in_h,
void deinitPostProcess()
{
for (int i = 0; i < OBJ_CLASS_NUM; i++) {
if (labels[i] != nullptr) {
for (int i = 0; i < OBJ_CLASS_NUM; i++)
{
if (labels[i] != nullptr)
{
free(labels[i]);
labels[i] = nullptr;
}

61
examples/rknn_yolov5_demo/src/preprocess.cc

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// Copyright (c) 2023 by Rockchip Electronics Co., Ltd. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "preprocess.h"
void letterbox(const cv::Mat &image, cv::Mat &padded_image, BOX_RECT &pads, const float scale, const cv::Size &target_size, const cv::Scalar &pad_color)
{
// 调整图像大小
cv::Mat resized_image;
cv::resize(image, resized_image, cv::Size(), scale, scale);
// 计算填充大小
int pad_width = target_size.width - resized_image.cols;
int pad_height = target_size.height - resized_image.rows;
pads.left = pad_width / 2;
pads.right = pad_width - pads.left;
pads.top = pad_height / 2;
pads.bottom = pad_height - pads.top;
// 在图像周围添加填充
cv::copyMakeBorder(resized_image, padded_image, pads.top, pads.bottom, pads.left, pads.right, cv::BORDER_CONSTANT, pad_color);
}
int resize_rga(rga_buffer_t &src, rga_buffer_t &dst, const cv::Mat &image, cv::Mat &resized_image, const cv::Size &target_size)
{
im_rect src_rect;
im_rect dst_rect;
memset(&src_rect, 0, sizeof(src_rect));
memset(&dst_rect, 0, sizeof(dst_rect));
size_t img_width = image.cols;
size_t img_height = image.rows;
if (image.type() != CV_8UC3)
{
printf("source image type is %d!\n", image.type());
return -1;
}
size_t target_width = target_size.width;
size_t target_height = target_size.height;
src = wrapbuffer_virtualaddr((void *)image.data, img_width, img_height, RK_FORMAT_RGB_888);
dst = wrapbuffer_virtualaddr((void *)resized_image.data, target_width, target_height, RK_FORMAT_RGB_888);
int ret = imcheck(src, dst, src_rect, dst_rect);
if (IM_STATUS_NOERROR != ret)
{
fprintf(stderr, "rga check error! %s", imStrError((IM_STATUS)ret));
return -1;
}
IM_STATUS STATUS = imresize(src, dst);
return 0;
}
Loading…
Cancel
Save