863 lines
29 KiB
C
863 lines
29 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include "xmedia_cl.h"
|
|
#include "xmedia_mmz.h"
|
|
#include "xmedia_sys.h"
|
|
#include "xmedia_tde.h"
|
|
#include "xmedia_video_common.h"
|
|
#include "xmedia_svp.h"
|
|
#include "xmedia_vgs.h"
|
|
#include "xmedia_vb.h"
|
|
|
|
#include <sys/time.h>
|
|
#include <math.h>
|
|
#include <stdint.h>
|
|
|
|
#define ALIGN_BYTE 8
|
|
#define DEFAULT_INOUT_NUM 16
|
|
#define DFL_LEN 16
|
|
#define FEATURE_NUM 3
|
|
#define MAX_TARGET_NUM 30
|
|
#define AI_EPSILON 0.000001f
|
|
#define PHY_NUM 5
|
|
#define MAX_FILE_LEN 256
|
|
|
|
/* 模型相关信息 */
|
|
#define IMAGE_WIDTH 640
|
|
#define IMAGE_HEIGTH 640
|
|
#define MODEL_FILE_NAME "./model/neuron_network.xmm"
|
|
#define DETECT_THRE 0.7
|
|
#define DETECT_IOU_THRE 0.5
|
|
#define INPUT_IMAGE_FILE_NAME "./input/test_image1_640x640_NV21.yuv"
|
|
|
|
#define ALIGN_FUNC(A, ALIGN) \
|
|
((((A) % (ALIGN)) == 0) ? (A) : ((A) + (ALIGN) - ((A) % (ALIGN))))
|
|
#define STD_MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
#define STD_MIN(a, b) ((a) > (b) ? (b) : (a))
|
|
|
|
#define CFREE(a) \
|
|
if (a) { \
|
|
free(a); \
|
|
a = NULL; \
|
|
}
|
|
|
|
static xmedia_cl_s32 feature_map_size[FEATURE_NUM] = {80, 40, 20};
|
|
static xmedia_cl_s32 stride_down[FEATURE_NUM] = {8, 16, 32};
|
|
static xmedia_video_rect target_rect[MAX_TARGET_NUM];
|
|
|
|
typedef struct {
|
|
xmedia_float x1;
|
|
xmedia_float y1;
|
|
xmedia_float x2;
|
|
xmedia_float y2;
|
|
} xmedia_ai_rect;
|
|
|
|
typedef struct {
|
|
xmedia_cl_s32 detect_type;
|
|
xmedia_cl_s32 class_type;
|
|
xmedia_float score;
|
|
xmedia_float classfier_score;
|
|
xmedia_float tracker_iou;
|
|
xmedia_ai_rect rect;
|
|
} xmedia_ai_detect_result;
|
|
|
|
static xmedia_cl_s32 sample_abs(int num)
|
|
{
|
|
return num < 0 ? -num : num;
|
|
}
|
|
|
|
inline static xmedia_s32 sample_clamp(xmedia_float val, int min, int max)
|
|
{
|
|
return val > min ? (val < max ? val : max) : min;
|
|
}
|
|
|
|
inline static xmedia_float sample_sigmoid(xmedia_float x) { return 1.0 / (1.0 + expf(-x)); }
|
|
|
|
inline static xmedia_float sample_unsigmoid(xmedia_float y) { return -1.0 * logf((1.0 / y) - 1.0); }
|
|
|
|
inline static xmedia_s32 sample_clip(xmedia_float val, xmedia_float min, xmedia_float max)
|
|
{
|
|
xmedia_float f = val <= min ? min : (val >= max ? max : val);
|
|
return f;
|
|
}
|
|
|
|
inline static xmedia_float sample_deqnt_affine_u8_to_f32(xmedia_u8 qnt, xmedia_s32 zp, xmedia_float scale)
|
|
{
|
|
return ((xmedia_float)qnt - (xmedia_float)zp) * scale;
|
|
}
|
|
|
|
static xmedia_u8 sample_qnt_f32_to_affine_u8(xmedia_float f32, xmedia_s32 zp, xmedia_float scale)
|
|
{
|
|
xmedia_float dst_val = (f32 / scale) + zp;
|
|
xmedia_u8 res = (xmedia_u8)sample_clip(dst_val, 0, 255);
|
|
return res;
|
|
}
|
|
|
|
static xmedia_cl_s32 sample_malloc_inout_tensor_mem(xmedia_cl_tensor_info_inout *inout)
|
|
{
|
|
inout->tensor = malloc(sizeof(xmedia_cl_tensor) * inout->num);
|
|
inout->current_batch = malloc(sizeof(xmedia_cl_u32) * inout->num);
|
|
inout->tensor_batch = malloc(sizeof(xmedia_cl_tensor_batch) * inout->num);
|
|
|
|
if (inout->tensor == NULL || inout->current_batch == NULL
|
|
|| inout->tensor_batch == NULL) {
|
|
return XMEDIA_CL_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
return XMEDIA_SUCCESS;
|
|
}
|
|
|
|
static xmedia_void sample_free_inout_tensor_mem(xmedia_cl_tensor_info_inout inout)
|
|
{
|
|
if (inout.tensor != NULL) {
|
|
free(inout.tensor);
|
|
}
|
|
if (inout.current_batch != NULL) {
|
|
free(inout.current_batch);
|
|
}
|
|
if (inout.tensor_batch != NULL) {
|
|
free(inout.tensor_batch);
|
|
}
|
|
}
|
|
|
|
static xmedia_void sample_compute_dfl(xmedia_float* tensor, xmedia_float* box)
|
|
{
|
|
for (xmedia_s32 b=0; b<4; b++){
|
|
xmedia_float exp_t[DFL_LEN];
|
|
xmedia_float exp_sum=0;
|
|
xmedia_float acc_sum=0;
|
|
for (xmedia_s32 i=0; i< DFL_LEN; i++){
|
|
exp_t[i] = exp(tensor[i+b*DFL_LEN]);
|
|
exp_sum += exp_t[i];
|
|
}
|
|
|
|
for (xmedia_s32 i=0; i< DFL_LEN; i++){
|
|
acc_sum += exp_t[i]/exp_sum *i;
|
|
}
|
|
box[b] = acc_sum;
|
|
}
|
|
}
|
|
|
|
static inline xmedia_s32 cmp_score_fall(const xmedia_void *lsh, const xmedia_void *rsh)
|
|
{
|
|
// 降序排列, 令score最大的box在队列末端
|
|
xmedia_ai_detect_result *s1 = (xmedia_ai_detect_result *)lsh;
|
|
xmedia_ai_detect_result *s2 = (xmedia_ai_detect_result *)rsh;
|
|
return s1->score > s2->score ? -1 : 1;
|
|
}
|
|
|
|
static inline xmedia_float sample_iou
|
|
(xmedia_ai_detect_result *box1, xmedia_ai_detect_result *box2, xmedia_bool total_ratio)
|
|
{
|
|
xmedia_float area1;
|
|
xmedia_float area2;
|
|
xmedia_float mix_area;
|
|
|
|
if (box1->class_type != box2->class_type) {
|
|
return 0.0f;
|
|
}
|
|
|
|
mix_area = STD_MAX(0.0f, STD_MIN(box1->rect.x2, box2->rect.x2) -
|
|
STD_MAX(box1->rect.x1, box2->rect.x1)) *
|
|
STD_MAX(0.0f, STD_MIN(box1->rect.y2, box2->rect.y2) -
|
|
STD_MAX(box1->rect.y1, box2->rect.y1));
|
|
if (mix_area == 0.0f) {
|
|
return 0.0f;
|
|
}
|
|
area1 = (box1->rect.x2 - box1->rect.x1) * (box1->rect.y2 - box1->rect.y1);
|
|
area2 = (box2->rect.x2 - box2->rect.x1) * (box2->rect.y2 - box2->rect.y1);
|
|
|
|
if (total_ratio) {
|
|
xmedia_float tmp = area1 + area2 - mix_area;
|
|
return (tmp == 0.0f) ? 0.0f : (mix_area / tmp);
|
|
} else {
|
|
return (area1 == 0.0f) ? 0.0f : (mix_area / area1);
|
|
}
|
|
}
|
|
|
|
static xmedia_s32 sample_det_nms(xmedia_ai_detect_result *vec_bbox,
|
|
xmedia_u32 vec_bbox_len, xmedia_float threshold, xmedia_u32 *picked_bbox_len)
|
|
{
|
|
xmedia_u32 i;
|
|
xmedia_u32 j;
|
|
xmedia_ai_detect_result *box_b;
|
|
xmedia_ai_detect_result *box_a;
|
|
xmedia_ai_detect_result *picked_bbox;
|
|
xmedia_u32 valid_count = 0;
|
|
|
|
qsort(vec_bbox, vec_bbox_len, sizeof(xmedia_ai_detect_result), cmp_score_fall);
|
|
for (i = 0; i < vec_bbox_len; i++) {
|
|
box_a = &vec_bbox[i];
|
|
if (box_a->score == 0.0) {
|
|
continue;
|
|
}
|
|
for (j = i + 1; j < vec_bbox_len; j++) {
|
|
box_b = &vec_bbox[j];
|
|
if (box_b->score == 0.0) {
|
|
continue;
|
|
}
|
|
xmedia_float box_iou = sample_iou(box_a, box_b, XMEDIA_TRUE);
|
|
if (box_iou >= threshold) {
|
|
box_b->score = 0.0;
|
|
}
|
|
}
|
|
valid_count++;
|
|
}
|
|
|
|
picked_bbox = (xmedia_ai_detect_result *)malloc(valid_count * sizeof(xmedia_ai_detect_result));
|
|
if (picked_bbox == XMEDIA_NULL) {
|
|
*picked_bbox_len = 0;
|
|
return XMEDIA_NULL;
|
|
}
|
|
for (i = 0, j = 0; i < vec_bbox_len; i++) {
|
|
if (vec_bbox[i].score == 0.0) {
|
|
continue;
|
|
}
|
|
if (j < valid_count) {
|
|
picked_bbox[j++] = vec_bbox[i];
|
|
}
|
|
}
|
|
*picked_bbox_len = valid_count;
|
|
|
|
memcpy(vec_bbox, picked_bbox, sizeof(xmedia_ai_detect_result) * valid_count);
|
|
|
|
CFREE(picked_bbox);
|
|
return XMEDIA_SUCCESS;
|
|
}
|
|
|
|
static xmedia_s32 sample_svp_draw(xmedia_video_rect target_rect[],
|
|
xmedia_video_frame_info *frame,
|
|
xmedia_svp_yolov5_output result)
|
|
{
|
|
xmedia_s32 ret;
|
|
xmedia_vgs_frame_info task = {0};
|
|
xmedia_vgs_cover_attr cover[XMEDIA_SVP_MAX_TARGET_NUM];
|
|
xmedia_s32 handle = -1;
|
|
xmedia_s32 i;
|
|
xmedia_u8 object_num = result.target_num;
|
|
if (0 == object_num)
|
|
{
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
|
|
object_num = object_num > XMEDIA_SVP_MAX_TARGET_NUM ? XMEDIA_SVP_MAX_TARGET_NUM : object_num;
|
|
memcpy(&task.img_in,frame,sizeof(xmedia_video_frame_info));
|
|
memcpy(&task.img_out,frame,sizeof(xmedia_video_frame_info));
|
|
ret = xmedia_vgs_init();
|
|
if(ret != XMEDIA_SUCCESS) {
|
|
printf("xmedia_vgs_init failed !\n");
|
|
return ret;
|
|
}
|
|
ret = xmedia_vgs_create_job(&handle);
|
|
if (XMEDIA_SUCCESS != ret)
|
|
{
|
|
xmedia_vgs_exit();
|
|
printf("xmedia_vgs_cancel_job failed !\n");
|
|
handle = -1;
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
for (i = 0; i < object_num; i++) {
|
|
if (result.targets[i].class_type == XMEDIA_SVP_CLASS_TYPE_FIREWORKS_SMOKE ||
|
|
result.targets[i].class_type == XMEDIA_SVP_CLASS_TYPE_TRICYCLER) {
|
|
cover[i].color = 0x0000FF;
|
|
} else if (result.targets[i].class_type == XMEDIA_SVP_CLASS_TYPE_BIKER) {
|
|
cover[i].color = 0x000FFF;
|
|
} else if (result.targets[i].class_type == XMEDIA_SVP_CLASS_TYPE_MOTOR) {
|
|
cover[i].color = 0x0F000F;
|
|
} else if (result.targets[i].class_type == XMEDIA_SVP_CLASS_TYPE_MOTORER) {
|
|
cover[i].color = 0xFF00FF;
|
|
} else if (result.targets[i].class_type == XMEDIA_SVP_CLASS_TYPE_TRICYCLE) {
|
|
cover[i].color = 0x00FF00;
|
|
} else {
|
|
cover[i].color = 0xFF0000;
|
|
}
|
|
cover[i].cover_type = XMEDIA_VGS_COVER_TYPE_QUAD_RANGLE;
|
|
cover[i].quadrangle.is_solid = XMEDIA_FALSE;
|
|
cover[i].quadrangle.thick = 2;
|
|
cover[i].quadrangle.points[0].x = target_rect[i].x;
|
|
cover[i].quadrangle.points[0].y = target_rect[i].y;
|
|
cover[i].quadrangle.points[1].x = target_rect[i].x + target_rect[i].width;
|
|
cover[i].quadrangle.points[1].y = target_rect[i].y;
|
|
cover[i].quadrangle.points[2].x = target_rect[i].x + target_rect[i].width;
|
|
cover[i].quadrangle.points[2].y = target_rect[i].y + target_rect[i].height;
|
|
cover[i].quadrangle.points[3].x = target_rect[i].x;
|
|
cover[i].quadrangle.points[3].y = target_rect[i].y + target_rect[i].height;
|
|
}
|
|
ret = xmedia_vgs_add_task_cover(handle, &task, &cover[0], object_num);
|
|
if (XMEDIA_SUCCESS != ret) {
|
|
xmedia_vgs_cancel_job(handle);
|
|
xmedia_vgs_exit();
|
|
printf("xmedia_vgs_add_task_cover failed ! ret [%#x] \n", ret);
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
ret = xmedia_vgs_submit_job(handle);
|
|
if (XMEDIA_SUCCESS != ret) {
|
|
xmedia_vgs_cancel_job(handle);
|
|
xmedia_vgs_exit();
|
|
printf("xmedia_vgs_submit_job failed ! ret [%d] \n", ret);
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
ret = xmedia_vgs_wait_job(handle, 2000);
|
|
if (ret != XMEDIA_SUCCESS) {
|
|
xmedia_vgs_exit();
|
|
printf("xmedia_vgs_wait_job failed ! ret [%d] \n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return XMEDIA_SUCCESS;
|
|
}
|
|
|
|
static xmedia_s32 sample_mmzalloc_cached(xmedia_u64 *pu64PhyAddr,
|
|
xmedia_void **ppVirAddr,
|
|
const xmedia_char *strMmb,
|
|
const xmedia_char *strZone,
|
|
xmedia_u32 u32Len)
|
|
{
|
|
*pu64PhyAddr = xmedia_mmz_alloc(strZone, strMmb, u32Len);
|
|
if (*pu64PhyAddr == XMEDIA_NULL) {
|
|
return XMEDIA_CL_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
*ppVirAddr = xmedia_mmz_map(*pu64PhyAddr, u32Len, 1);
|
|
if (*ppVirAddr == XMEDIA_NULL) {
|
|
return XMEDIA_CL_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
return XMEDIA_SUCCESS;
|
|
}
|
|
|
|
static xmedia_s32 sample_mmzfree(xmedia_u64 u64PhyAddr, xmedia_void *pVirAddr)
|
|
{
|
|
xmedia_cl_s32 ret;
|
|
|
|
if (pVirAddr != XMEDIA_NULL) {
|
|
ret = xmedia_mmz_unmap(pVirAddr);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
}
|
|
|
|
return xmedia_mmz_free(u64PhyAddr);
|
|
}
|
|
|
|
static xmedia_s32 sample_get_input_one_data(xmedia_void* data_yuv, xmedia_u32 image_size)
|
|
{
|
|
FILE* fp_temp = fopen(INPUT_IMAGE_FILE_NAME, "rb");
|
|
if (fp_temp)
|
|
{
|
|
fread(data_yuv, image_size, 1, fp_temp);
|
|
}
|
|
else {
|
|
printf("fopen failed.\n");
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
fclose(fp_temp);
|
|
fp_temp = XMEDIA_NULL;
|
|
|
|
return XMEDIA_SUCCESS;
|
|
}
|
|
|
|
static xmedia_s32 sample_tde_y2r(xmedia_cl_tensor_info_inout input,
|
|
xmedia_u64 img_src_phy, xmedia_u64 img_src_rgb_phy)
|
|
{
|
|
xmedia_s32 handle = XMEDIA_FAILURE;
|
|
|
|
xmedia_s32 ret;
|
|
xmedia_tde_surface_info src = {0};
|
|
xmedia_tde_surface_info dst = {0};
|
|
|
|
ret = xmedia_tde_create_job(&handle);
|
|
if (XMEDIA_SUCCESS != ret)
|
|
{
|
|
printf("xmedia_tde_create_job failed %#x!\n",ret);
|
|
handle = XMEDIA_FAILURE;
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
|
|
src.surface.phys_addr[0] = img_src_phy;
|
|
src.surface.phys_addr[1] = img_src_phy + input.tensor[0].shape.dims[2] * input.tensor[0].shape.dims[1];
|
|
src.surface.stride[0] = input.tensor[0].shape.dims[2];
|
|
src.surface.stride[1] = input.tensor[0].shape.dims[2];
|
|
src.surface.width = input.tensor[0].shape.dims[2];
|
|
src.surface.height = input.tensor[0].shape.dims[1];
|
|
src.surface.pixel_format = XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420;
|
|
src.surface.alpha0 = 0;
|
|
src.surface.alpha1 = 255;
|
|
src.surface.is_alpha_ext_1555 = 0;
|
|
src.surface.clut_reload = XMEDIA_FALSE;
|
|
|
|
src.rect.x = 0;
|
|
src.rect.y = 0;
|
|
src.rect.width = input.tensor[0].shape.dims[2];
|
|
src.rect.height = input.tensor[0].shape.dims[1];
|
|
|
|
dst.surface.phys_addr[0] = img_src_rgb_phy;
|
|
dst.surface.width = input.tensor[0].shape.dims[2];
|
|
dst.surface.height = input.tensor[0].shape.dims[1];
|
|
dst.surface.stride[0] = input.tensor[0].shape.dims[2] * 3;
|
|
dst.surface.pixel_format = XMEDIA_VIDEO_PIXEL_FMT_RGB_888;
|
|
dst.surface.is_alpha_ext_1555 = XMEDIA_FALSE;
|
|
dst.surface.alpha0 = 0;
|
|
dst.surface.alpha1 = 255;
|
|
dst.surface.clut_reload = XMEDIA_FALSE;
|
|
|
|
dst.rect.x = 0;
|
|
dst.rect.y = 0;
|
|
dst.rect.width = input.tensor[0].shape.dims[2];
|
|
dst.rect.height = input.tensor[0].shape.dims[1];
|
|
|
|
ret = xmedia_tde_add_task_single_blit(handle, &src, &dst, 0, XMEDIA_NULL);
|
|
if (XMEDIA_SUCCESS != ret)
|
|
{
|
|
printf("xmedia_tde_add_task_scale failed ret: %#x !\n", ret);
|
|
xmedia_tde_cancel_job(handle);
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
|
|
ret = xmedia_tde_submit_job(handle);
|
|
if (XMEDIA_SUCCESS != ret)
|
|
{
|
|
printf("xmedia_tde_submit_job failed ,ret: %#x!\n", ret);
|
|
xmedia_tde_cancel_job(handle);
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
|
|
ret = xmedia_tde_wait_job(handle, 2000);
|
|
if (XMEDIA_SUCCESS != ret)
|
|
{
|
|
printf("tde overtime %#x!\n",ret);
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
|
|
return XMEDIA_SUCCESS;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
void *buff[DEFAULT_INOUT_NUM] = { 0 };
|
|
xmedia_cl_s8 name[MAX_FILE_LEN] = { 0 };
|
|
xmedia_cl_u64 u64SrcPhyAddr[PHY_NUM] = { 0 };
|
|
xmedia_char *nocache_buffer_start[PHY_NUM] = { 0 };
|
|
xmedia_cl_s32 output_size[DEFAULT_INOUT_NUM] = { 0 };
|
|
xmedia_cl_s8 *model = MODEL_FILE_NAME;
|
|
xmedia_cl_s32 i = 0, j, size = 0, ret, err;
|
|
xmedia_cl_graph graph = XMEDIA_NULL;
|
|
xmedia_cl_u32 num_devices = 0, input_num = 0, output_num = 0;
|
|
xmedia_cl_tensor_info_inout input = { 0 }, output = { 0 };
|
|
xmedia_cl_s32 err_code = 0;
|
|
xmedia_cl_context context = XMEDIA_NULL;
|
|
xmedia_cl_device_id *devices = XMEDIA_NULL;
|
|
xmedia_cl_u32 worksize, weightsize, inputsize = 0, outputsize = 0;
|
|
xmedia_u32 image_size;
|
|
xmedia_s32 image_width, image_heigth;
|
|
|
|
// 公共模块初始化
|
|
ret = xmedia_sys_init(XMEDIA_NULL);
|
|
if (ret != XMEDIA_SUCCESS) {
|
|
printf("xmedia_sys_init err, errno %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = xmedia_tde_init();
|
|
if (XMEDIA_SUCCESS != ret)
|
|
{
|
|
printf("xmedia_tde_init failed %#x!\n",ret);
|
|
goto SYS_EXIT;
|
|
}
|
|
// 运行时初始化
|
|
ret = xmedia_cl_init();
|
|
if (ret != XMEDIA_SUCCESS) {
|
|
printf("xmedia_cl_init err, errno %d\n", ret);
|
|
goto TDE_EXIT;
|
|
}
|
|
// 第一次调用该接口获取设备数量
|
|
ret = xmedia_cl_get_device_ids(XMEDIA_CL_DEVICE_ALL, NULL, &num_devices);
|
|
if (ret != XMEDIA_SUCCESS) {
|
|
printf("xmedia_cl_get_device_ids err, errno %d\n", ret);
|
|
goto CL_EXIT;
|
|
}
|
|
devices = (xmedia_cl_device_id *)calloc(num_devices, sizeof(xmedia_cl_device_id));
|
|
if (devices == NULL) {
|
|
printf("calloc err\n");
|
|
ret = XMEDIA_CL_OUT_OF_HOST_MEMORY;
|
|
goto CL_EXIT;
|
|
}
|
|
// 第二次调用该接口传递获取到的设备数量申请设备资源
|
|
ret = xmedia_cl_get_device_ids(XMEDIA_CL_DEVICE_ALL, devices, &num_devices);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_get_device_ids err, errno %d\n", ret);
|
|
free(devices);
|
|
goto CL_EXIT;
|
|
}
|
|
// 创建资源管理的对象
|
|
context = xmedia_cl_create_context(num_devices, devices, &err_code);
|
|
if (err_code != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_create_context err, errno %d\n", ret);
|
|
goto DEVICE_EXIT;
|
|
}
|
|
|
|
// 从模型文件中查询work和weight的大小
|
|
ret = xmedia_cl_graph_querysize_from_file(model, &worksize, &weightsize);
|
|
if (XMEDIA_CL_SUCCESS != ret) {
|
|
printf("xmedia_cl_graph_querysize_from_file, errno %d\n", ret);
|
|
goto CONTEXT_EXIT;
|
|
}
|
|
if (worksize) {
|
|
// 根据查询到的大小申请work和weight的内存
|
|
ret = sample_mmzalloc_cached(&u64SrcPhyAddr[0], (void **)(&nocache_buffer_start[0]),
|
|
"npu_workspace", NULL, worksize);
|
|
if (XMEDIA_CL_SUCCESS != ret) {
|
|
goto CONTEXT_EXIT;
|
|
}
|
|
} else {
|
|
nocache_buffer_start[0] = NULL;
|
|
}
|
|
if (weightsize) {
|
|
ret = sample_mmzalloc_cached(&u64SrcPhyAddr[1], (void **)(&nocache_buffer_start[1]),
|
|
"npu_weight", NULL, weightsize);
|
|
if (XMEDIA_CL_SUCCESS != ret) {
|
|
goto ERROR;
|
|
}
|
|
} else {
|
|
nocache_buffer_start[1] = NULL;
|
|
}
|
|
// 加载解析模型文件,若是从文件中加载,则model为文件路径,若从内存中加载,则model为内存地址
|
|
ret = xmedia_cl_graph_loadmodel_from_file_withmem(
|
|
&context, model, nocache_buffer_start[0], worksize,
|
|
nocache_buffer_start[1], weightsize, &graph);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_loadmodel err, errno %d\n", ret);
|
|
goto ERROR;
|
|
}
|
|
|
|
// 第一次调用该接口获取输入数量
|
|
ret = xmedia_cl_graph_get_input(graph, input_num, &input);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_get_input, errno %d\n", ret);
|
|
goto ERROR;
|
|
}
|
|
if (input.num > DEFAULT_INOUT_NUM) {
|
|
printf("model input num is greater than default value!\n");
|
|
goto ERROR;
|
|
}
|
|
// 根据输入数量申请内存
|
|
sample_malloc_inout_tensor_mem(&input);
|
|
input_num = input.num;
|
|
// 第二次调用该接口获取输入信息
|
|
ret = xmedia_cl_graph_get_input(graph, input_num, &input);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_get_input, errno %d\n", ret);
|
|
goto ERROR;
|
|
}
|
|
|
|
// 第一次调用该接口获取输出数量
|
|
ret = xmedia_cl_graph_get_output(graph, output_num, &output);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_get_output, errno %d\n", ret);
|
|
goto ERROR;
|
|
}
|
|
if (output.num > DEFAULT_INOUT_NUM) {
|
|
printf("model output num is greater than default value!\n");
|
|
goto ERROR;
|
|
}
|
|
// 根据输出数量申请内存
|
|
sample_malloc_inout_tensor_mem(&output);
|
|
output_num = output.num;
|
|
|
|
// 第二次调用该接口获取输出信息
|
|
ret = xmedia_cl_graph_get_output(graph, output_num, &output);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_get_output, errno %d\n", ret);
|
|
goto ERROR;
|
|
}
|
|
|
|
// 计算输入的大小并申请内存
|
|
for (i = 0; i < input.num; i++) {
|
|
size = input.tensor[i].size;
|
|
inputsize += ALIGN_FUNC(size, ALIGN_BYTE);
|
|
}
|
|
|
|
ret = sample_mmzalloc_cached(&u64SrcPhyAddr[2], (void **)(&nocache_buffer_start[2]),
|
|
"npu_input", NULL, inputsize);
|
|
if (XMEDIA_CL_SUCCESS != ret) {
|
|
goto ERROR;
|
|
}
|
|
|
|
// 计算输出的大小并申请内存
|
|
for (i = 0; i < output.num; i++) {
|
|
output_size[i] = output.tensor[i].size;
|
|
outputsize += ALIGN_FUNC(output_size[i], ALIGN_BYTE);
|
|
}
|
|
ret = sample_mmzalloc_cached(&u64SrcPhyAddr[3], (void **)(&nocache_buffer_start[3]),
|
|
"npu_output", NULL, outputsize);
|
|
if (XMEDIA_CL_SUCCESS != ret) {
|
|
goto ERROR;
|
|
}
|
|
|
|
image_width = IMAGE_WIDTH;
|
|
image_heigth = IMAGE_HEIGTH;
|
|
image_size = image_width * image_heigth * 3 / 2;
|
|
|
|
// 申请yuv图像内存
|
|
sample_mmzalloc_cached(&u64SrcPhyAddr[4], (void **)(&nocache_buffer_start[4]),
|
|
"test_yuv_image", NULL, image_size);
|
|
|
|
// 读取yuv图像
|
|
ret = sample_get_input_one_data(nocache_buffer_start[4], image_size);
|
|
if (ret != XMEDIA_SUCCESS) {
|
|
printf("get input data failed!\n");
|
|
}
|
|
|
|
sample_tde_y2r(input, u64SrcPhyAddr[4], u64SrcPhyAddr[2]);
|
|
|
|
// 设置输入,把输入golden数据拷贝到输入地址,每个输入必须设置一次
|
|
for (i = 0; i < input.num; i++) {
|
|
if (i > 0) {
|
|
input.tensor[i].addr =
|
|
input.tensor[i - 1].addr + ALIGN_FUNC(size, ALIGN_BYTE);
|
|
} else {
|
|
input.tensor[i].addr = nocache_buffer_start[2];
|
|
}
|
|
size = input.tensor[i].size;
|
|
|
|
printf("input.tensor[%d].addr = %p input size = 0x%x\n", i,
|
|
input.tensor[i].addr, size);
|
|
}
|
|
|
|
// 把输出的golden数据拷贝到内存,用来与npu的输出做对比
|
|
for (i = 0; i < output.num; i++) {
|
|
if (i > 0) {
|
|
output.tensor[i].addr = output.tensor[i - 1].addr +
|
|
ALIGN_FUNC(output_size[i - 1], ALIGN_BYTE);
|
|
} else {
|
|
output.tensor[i].addr = nocache_buffer_start[3];
|
|
}
|
|
memset(name, 0, sizeof(name));
|
|
output_size[i] = output.tensor[i].size;
|
|
|
|
printf("output.tensor[%d].addr = %p output size = %d\n", i,
|
|
output.tensor[i].addr, output_size[i]);
|
|
}
|
|
|
|
// 在xmm2下,用户需要申请输入地址,输出地址可以动态改变,把输入与输出设置为推理的输入、输出
|
|
ret = xmedia_cl_graph_set_inout(graph, &input, &output);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_set_inout, errno %d\n", ret);
|
|
goto ERROR;
|
|
}
|
|
|
|
struct timeval t_start, t_end;
|
|
gettimeofday(&t_start, NULL);
|
|
ret = xmedia_cl_graph_process(graph);
|
|
gettimeofday(&t_end, NULL);
|
|
printf("xmedia_cl_graph_process start time = [%ld]\n", t_start.tv_usec);
|
|
printf("xmedia_cl_graph_process end time = [%ld]\n", t_end.tv_usec);
|
|
printf("xmedia_cl_graph_process timeval = [%ld] us\n",
|
|
((t_end.tv_sec - t_start.tv_sec) * 1000000) + t_end.tv_usec - t_start.tv_usec);
|
|
if (ret != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_process err, errno %d\n", ret);
|
|
}
|
|
|
|
// 解析输出tensor
|
|
xmedia_cl_s32 feature_map_num = FEATURE_NUM;
|
|
xmedia_cl_s32 index;
|
|
xmedia_cl_u32 idx = 0;
|
|
|
|
xmedia_cl_float detect_threshold = DETECT_THRE;
|
|
xmedia_cl_u32 target_num = MAX_TARGET_NUM;
|
|
xmedia_ai_detect_result *bbox;
|
|
bbox = (xmedia_ai_detect_result *)calloc(1, target_num * sizeof(xmedia_ai_detect_result));
|
|
|
|
for (index = 0; index < feature_map_num; index++) {
|
|
xmedia_cl_s32 grid_h = feature_map_size[index];
|
|
xmedia_cl_s32 grid_w = feature_map_size[index];
|
|
xmedia_cl_s32 stride = stride_down[index];
|
|
xmedia_cl_s32 box_index = index * 2;
|
|
xmedia_cl_s32 score_index = index * 2 + 1;
|
|
|
|
xmedia_cl_s32 box_zp = output.tensor[box_index].quant.zp;
|
|
xmedia_cl_float box_scale = output.tensor[box_index].quant.scale;
|
|
xmedia_cl_u8* box_tensor = output.tensor[box_index].addr;
|
|
|
|
xmedia_cl_s32 score_zp = output.tensor[score_index].quant.zp;
|
|
xmedia_cl_float score_scale = output.tensor[score_index].quant.scale;
|
|
xmedia_cl_u8* score_tensor = output.tensor[score_index].addr;
|
|
|
|
xmedia_cl_s32 grid_len = grid_w * grid_h;
|
|
xmedia_cl_u8 score_thres_u8 =
|
|
sample_qnt_f32_to_affine_u8(sample_unsigmoid(detect_threshold), score_zp, score_scale);
|
|
|
|
for (i = 0; i < grid_h; i++) {
|
|
for (j = 0; j < grid_w; j++) {
|
|
xmedia_cl_s32 score_offset = i * grid_w + j;
|
|
xmedia_cl_s32 max_class_id = -1;
|
|
xmedia_cl_s32 bbox_offset = i * grid_w + j;
|
|
xmedia_cl_u8 max_score = -score_zp;
|
|
xmedia_cl_float box[4];
|
|
xmedia_cl_float before_dfl[DFL_LEN * 4];
|
|
xmedia_cl_float x1, x2, y1, y2;
|
|
|
|
if (idx >= target_num) {
|
|
break;
|
|
}
|
|
|
|
for (xmedia_cl_s32 c = 0; c < 80; c++) {
|
|
if ((score_tensor[score_offset] > score_thres_u8) &&
|
|
(score_tensor[score_offset] > max_score)) {
|
|
max_score = score_tensor[score_offset];
|
|
max_class_id = c;
|
|
}
|
|
score_offset += grid_len;
|
|
}
|
|
|
|
if (max_score < score_thres_u8) {
|
|
continue;
|
|
}
|
|
|
|
for (xmedia_cl_s32 k = 0; k < DFL_LEN * 4; k++) {
|
|
before_dfl[k] = sample_deqnt_affine_u8_to_f32(box_tensor[bbox_offset], box_zp, box_scale);
|
|
bbox_offset += grid_len;
|
|
}
|
|
sample_compute_dfl(before_dfl, box);
|
|
|
|
x1 = (-box[0] + j + 0.5) * stride;
|
|
y1 = (-box[1] + i + 0.5) * stride;
|
|
x2 = (box[2] + j + 0.5) * stride;
|
|
y2 = (box[3] + i + 0.5) * stride;
|
|
|
|
bbox[idx].rect.x1 = sample_clamp(x1, 0, image_width);
|
|
bbox[idx].rect.y1 = sample_clamp(y1, 0, image_heigth);
|
|
bbox[idx].rect.x2 = sample_clamp(x2, 0, image_width);
|
|
bbox[idx].rect.y2 = sample_clamp(y2, 0, image_heigth);
|
|
|
|
bbox[idx].score = sample_sigmoid(sample_deqnt_affine_u8_to_f32(max_score, score_zp, score_scale));
|
|
bbox[idx].class_type = max_class_id;
|
|
idx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// NMS抑制
|
|
xmedia_cl_float iou_threshold = DETECT_IOU_THRE;
|
|
xmedia_u32 out_box_len = 0;
|
|
ret = sample_det_nms(bbox, idx, iou_threshold,&out_box_len);
|
|
|
|
// 构造框结构体
|
|
xmedia_u32 w,h;
|
|
xmedia_s32 x1, y1, x2, y2;
|
|
xmedia_svp_yolov5_output result;
|
|
result.target_num = out_box_len;
|
|
for (i = 0; i < out_box_len; i++) {
|
|
x1 = (xmedia_s32)roundf(bbox[i].rect.x1 / 2) * 2;
|
|
y1 = (xmedia_s32)roundf(bbox[i].rect.y1 / 2) * 2;
|
|
x2 = (xmedia_s32)roundf(bbox[i].rect.x2 / 2) * 2;
|
|
y2 = (xmedia_s32)roundf(bbox[i].rect.y2 / 2) * 2;
|
|
w = sample_abs(x2 - x1);
|
|
h = sample_abs(y2 - y1);
|
|
target_rect[i].x = x1;
|
|
target_rect[i].y = y1;
|
|
target_rect[i].width = w;
|
|
target_rect[i].height = h;
|
|
|
|
result.targets[i].class_type = bbox[i].class_type;
|
|
|
|
printf("yolov8 %d target tag:%d (x1:%.2f, y1:%.2f) (x1:%.2f, y1:%.2f) (w: %u, h: %u) !\n",
|
|
i+1, bbox[i].class_type,
|
|
bbox[i].rect.x1, bbox[i].rect.y1,
|
|
bbox[i].rect.x2, bbox[i].rect.y2,
|
|
target_rect[i].width, target_rect[i].height);
|
|
}
|
|
|
|
// 构造帧存结构体
|
|
xmedia_video_frame_info video_frame;
|
|
memset(&video_frame, 0, sizeof(video_frame));
|
|
video_frame.pool_id = VB_INVALID_POOLID;
|
|
video_frame.frame.width = ALIGN_FUNC(image_width, ALIGN_BYTE);
|
|
video_frame.frame.height = ALIGN_FUNC(image_heigth, ALIGN_BYTE);
|
|
video_frame.frame.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420;
|
|
video_frame.frame.bit_width = XMEDIA_VIDEO_DATA_WIDTH_8;
|
|
video_frame.frame.stride.y_stride = ALIGN_FUNC(image_width, ALIGN_BYTE);
|
|
video_frame.frame.stride.c_stride = ALIGN_FUNC(image_width, ALIGN_BYTE);
|
|
video_frame.frame.addr.y_phy_addr = u64SrcPhyAddr[4];
|
|
video_frame.frame.addr.c_phy_addr = u64SrcPhyAddr[4] + image_width * image_heigth;
|
|
// 绘制框
|
|
sample_svp_draw(&target_rect[0], &video_frame, result);
|
|
|
|
// 保存 YUV 图像
|
|
xmedia_char file_path[MAX_FILE_LEN];
|
|
snprintf(file_path, sizeof(file_path), "./output/yolov8_detect_result_%ux%u_NV21.yuv", image_width, image_heigth);
|
|
FILE *file = fopen(file_path, "wb");
|
|
if (file == NULL) {
|
|
perror("file open failed\n");
|
|
return -1;
|
|
}
|
|
fwrite(nocache_buffer_start[4], sizeof(uint8_t), image_width * image_heigth * 3 / 2, file);
|
|
fclose(file);
|
|
|
|
CFREE(bbox);
|
|
|
|
ERROR:
|
|
//释放资源
|
|
sample_free_inout_tensor_mem(input);
|
|
sample_free_inout_tensor_mem(output);
|
|
|
|
for (i = 0; i < PHY_NUM; i++) {
|
|
if (nocache_buffer_start[i] != NULL) {
|
|
sample_mmzfree(u64SrcPhyAddr[i], nocache_buffer_start[i]);
|
|
}
|
|
}
|
|
for (i = 0; i < output.num; i++) {
|
|
if (buff[i] != NULL) {
|
|
free(buff[i]);
|
|
}
|
|
}
|
|
if (graph != NULL) {
|
|
err = xmedia_cl_graph_unload(graph);
|
|
if (err != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_graph_unload err, errno %d\n", err);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
CONTEXT_EXIT:
|
|
if (context != NULL) {
|
|
err = xmedia_cl_release_context(context);
|
|
if (err != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_release_context err, errno %d\n", err);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
DEVICE_EXIT:
|
|
if (devices != NULL) {
|
|
err = xmedia_cl_release_device_ids(devices, &num_devices);
|
|
if (err != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_release_device_ids err, errno %d\n", err);
|
|
return err;
|
|
}
|
|
free(devices);
|
|
}
|
|
|
|
CL_EXIT:
|
|
err = xmedia_cl_uninit();
|
|
if (err != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_cl_uninit err, errno %d\n", err);
|
|
return err;
|
|
}
|
|
|
|
TDE_EXIT:
|
|
xmedia_tde_exit();
|
|
|
|
SYS_EXIT:
|
|
err = xmedia_sys_exit();
|
|
if (err != XMEDIA_CL_SUCCESS) {
|
|
printf("xmedia_sys_exit err, errno %d\n", err);
|
|
return err;
|
|
}
|
|
|
|
return ret;
|
|
}
|