#include "mult_yolov5_post_copy.h"

/* 调试开关:是否打印每个检测头top-k conf */

#define DEBUG_PRINT_TOPK_CONF  (1)

#define TOPK_CONF_NUM          (5)

static void swap_bbox(ttevxYoloV5BBox *a, ttevxYoloV5BBox *b);

static float iou(ttevxYoloV5BBox *box_a, ttevxYoloV5BBox *box_b);

static ttevxYoloV5BBox* quick_sort_part(ttevxYoloV5BBox *left, ttevxYoloV5BBox *right);

static void quick_sort_bbox(ttevxYoloV5BBox *left, ttevxYoloV5BBox *right);

/* ================================================================================== */

static void swap_bbox(ttevxYoloV5BBox *a, ttevxYoloV5BBox *b) {

    if (a == b) return;

    ttevxYoloV5BBox tmp;

    memcpy(&tmp, a, sizeof(ttevxYoloV5BBox));

    memcpy(a, b, sizeof(ttevxYoloV5BBox));

    memcpy(b, &tmp, sizeof(ttevxYoloV5BBox));

}

static float iou(ttevxYoloV5BBox *box_a, ttevxYoloV5BBox *box_b) {

    if (box_a->x1 >= box_a->x2 || box_a->y1 >= box_a->y2 || box_b->x1 >= box_b->x2 || box_b->y1 >= box_b->y2) {

        return 1.0f;

    }

    float x1 = box_a->x1 > box_b->x1 ? box_a->x1 : box_b->x1;

    float y1 = box_a->y1 > box_b->y1 ? box_a->y1 : box_b->y1;

    float x2 = box_a->x2 < box_b->x2 ? box_a->x2 : box_b->x2;

    float y2 = box_a->y2 < box_b->y2 ? box_a->y2 : box_b->y2;

    if (x1 >= x2 || y1 >= y2) {

        return 0.0f;

    }

    float inter_area = (x2 - x1) * (y2 - y1);

    float union_area = (float)(box_a->x2 - box_a->x1) * (float)(box_a->y2 - box_a->y1)

                        + (float)(box_b->x2 - box_b->x1) * (float)(box_b->y2 - box_b->y1)

                        - inter_area;

    return inter_area / union_area;

}

int NMS(ttevxYoloV5BBox *bbox_obj_arr, int bbox_num, float nms_thresh) {

    if (bbox_num == 0) return 0;

    quick_sort_bbox(bbox_obj_arr, bbox_obj_arr + bbox_num - 1);

    /* 第一个目标是可信的 */

    int accept_len = 1;

    /* 用于循环待验证序列 */

    int iter;

    /* 用于循环可信序列 */

    int iter_accept;

    for (iter = 1; iter < bbox_num; ++iter) {

        for (iter_accept = 0; iter_accept < accept_len; ++iter_accept) {

            /* 如果是同一个类别才进行IoU判断 */

            if (bbox_obj_arr[iter_accept].soltcls == bbox_obj_arr[iter].soltcls) {

                if (iou(&bbox_obj_arr[iter_accept], &bbox_obj_arr[iter]) > nms_thresh) {

                    /* 如果该目标框与已经accept的目标框iou过大,则确定为冗余目标框 */

                    break;

                }

            }

        }

        if (iter_accept == accept_len) {

            /* 如果该目标框与所有accept目标框的iou都较小,则接受该目标框 */

            swap_bbox(&bbox_obj_arr[accept_len], &bbox_obj_arr[iter]);

            accept_len++;

        }

    }

    return accept_len;

}

static ttevxYoloV5BBox* quick_sort_part(ttevxYoloV5BBox *left, ttevxYoloV5BBox *right) {

    ttevxYoloV5BBox *index = left;

    while (left < right) {

        while (index < right && right->soltconfidence <= index->soltconfidence) {

            right--;

        }

        if (left == right) break;

        swap_bbox(index, right);

        index = right;

        while (left < index && left->soltconfidence >= index->soltconfidence) {

            left++;

        }

        if (left == right) break;

        swap_bbox(index, left);

        index = left;

    }

    return index;

}

static void quick_sort_bbox(ttevxYoloV5BBox *left, ttevxYoloV5BBox *right) {

    if (left < right) {

        ttevxYoloV5BBox *index = quick_sort_part(left, right);

        quick_sort_bbox(left, index-1);

        quick_sort_bbox(index+1, right);

    }

}

void initMult_yolov5params(ttevxYoloV5PostProcParams *yolov5params)

{

    yolov5params->num_anchors = TTE_YOLOV5_NUM_ANCHOR;

    yolov5params->num_classes = TTE_YOLOV5_NUM_CLASSES;

    yolov5params->num_heads = TTE_YOLOV5_NUM_HEAD;

    /* 依据日志:部分图片 max_conf 约 0.11~0.12,低于 0.25 导致无输出 */

    yolov5params->conf_thresh = 0.10;

    yolov5params->nms_thresh = 0.45;  

    int i, j, k;

    for (i = 0; i < TTE_YOLOV5_NUM_HEAD; ++i) {

        for (j = 0; j < TTE_YOLOV5_NUM_ANCHOR; ++j) {

            for (k = 0; k < 2; ++k) {

                yolov5params->anchors[i][j][k] = ANCHORS[i][j][k];

            }

        }

    }

}

int getMult_yolov5e2eResult(ttevxYoloV5PostProcParams *yolov5params, ttevxYoloV5Detections *detections)

{

    int status = 0;

    float max_conf[MAX_TTE_YOLOV5_HEAD_NUM] = {0};

    float max_cls_prob[MAX_TTE_YOLOV5_HEAD_NUM] = {0};

    float max_score[MAX_TTE_YOLOV5_HEAD_NUM] = {0};

    int conf_pass_cnt[MAX_TTE_YOLOV5_HEAD_NUM] = {0};

    int final_cnt[MAX_TTE_YOLOV5_HEAD_NUM] = {0};

    int overflow_cnt[MAX_TTE_YOLOV5_HEAD_NUM] = {0};

    float topk_conf[MAX_TTE_YOLOV5_HEAD_NUM][TOPK_CONF_NUM] = {{0}};

    /*开始对端到端车位后处理进行解码*/

    int width, height, outPadL, outPadT, inPadL, inPadT;

    int output_sizes[TTE_APP_MAX_TENSOR_DIMS];

    void *output_buffer;

    int  map_id_output, map_id_input;

    int output_strides[TTE_APP_MAX_TENSOR_DIMS];

    int output_start[TTE_APP_MAX_TENSOR_DIMS];

    int head_idx, h_idx, w_idx, anchor_idx;

    int yolov5_class_stride = TTE_YOLOV5_NUM_CLASSES + 5 + 8 + 6; //cls confxywh points slot

    int bbox_num = 0;

    ttevxYoloV5BBox *bbox_obj_arr = detections->buffer;

    /* for mulTask_yolov5_det decode*/

    for(int head_idx = 0; head_idx < yolov5params->num_heads; head_idx++)

    {

        if (yolov5params->outDataTypeVX[head_idx] != 5) {

            printf("WARN: det_head[%d] outDataTypeVX=%d (expected VX_TYPE_UINT16=5), raw_data类型可能不匹配\n",

                   head_idx, yolov5params->outDataTypeVX[head_idx]);

        }

        output_sizes[0] = yolov5params->outWidth[head_idx] + yolov5params->outPadL[head_idx] + yolov5params->outPadR[head_idx];

        output_sizes[1] = yolov5params->outHeight[head_idx] + yolov5params->outPadT[head_idx] + yolov5params->outPadB[head_idx];

        output_sizes[2] = yolov5params->outNumChannels[head_idx];

        width = yolov5params->outWidth[head_idx];

        height = yolov5params->outHeight[head_idx];

        outPadL = yolov5params->outPadL[head_idx];

        outPadT = yolov5params->outPadT[head_idx];

        int in_w = yolov5params->inWidth[head_idx] > 0 ? yolov5params->inWidth[head_idx] : yolov5params->inWidth[0];

        int in_h = yolov5params->inHeight[head_idx] > 0 ? yolov5params->inHeight[head_idx] : yolov5params->inHeight[0];

        //获取内存块

        output_start[0] = output_start[1] = output_start[2] = output_start[3] = 0;

        output_strides[0] = 1;

        output_strides[1] = output_sizes[0];

        output_strides[2] = output_sizes[1] * output_strides[1];

        if(width > 0)

        {

            /* 初始时将指针定位到第一个有效内存位置 */

            unsigned short *pOut = (unsigned short *)yolov5params->output_tensors[head_idx];

            unsigned short *raw_data = (unsigned short*)(pOut) + (output_sizes[0] * outPadT + outPadL);

            /* TIDL中内存实际是CHW排布,但是以WHC记录,所以查找内存时首先定位正确的通道,再进行WH的偏移 */

            for (h_idx = 0; h_idx < yolov5params->outHeight[head_idx]; ++h_idx) {

                for (w_idx = 0; w_idx < yolov5params->outWidth[head_idx]; ++w_idx) {

                    for (anchor_idx = 0; anchor_idx < yolov5params->num_anchors; ++anchor_idx) {

                        /* 在内存片中对应[h,w]的线性位置 */

                        int obj_hw_idx = h_idx * output_sizes[0] + w_idx;

                        /* 找到正确conf内存通道位置,并做hw偏移 */

                        int obj_conf_idx = (anchor_idx * yolov5_class_stride + 4) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                        /* 获得conf并将conf缩放回输入尺度 */

                        if (yolov5params->scale[head_idx] <= 0.0f) {

                            printf("WARN: det_head[%d] scale=0, skip decoding\n", head_idx);

                            continue;

                        }

                        float conf = (float)(raw_data[obj_conf_idx]) / (float)yolov5params->scale[head_idx];

                        if(conf>1)

                        {

                            printf("save to (float)(raw_data[obj_conf_idx]) = %f!!!\n", (float)(raw_data[obj_conf_idx]));

                            printf("save to (float)yolov5params->scale[head_idx] = %f!!!\n", (float)yolov5params->scale[head_idx]);

                            printf("save to conf = %f!!!\n", conf);

                        }

                        for (int tk = 0; tk < TOPK_CONF_NUM; tk++)

                        {

                            if (conf > topk_conf[head_idx][tk])

                            {

                                for (int sh = TOPK_CONF_NUM - 1; sh > tk; sh--)

                                {

                                    topk_conf[head_idx][sh] = topk_conf[head_idx][sh - 1];

                                }

                                topk_conf[head_idx][tk] = conf;

                                break;

                            }

                        }

                        // printf("端到端车位解码耗时2 \n");

                        if (conf > max_conf[head_idx]) max_conf[head_idx] = conf;

                        if (conf >= yolov5params->conf_thresh) {      

                            conf_pass_cnt[head_idx]++;

                            /* 计算xywh和cls内存位置并转化为输出值 */

                            int obj_x_idx = (anchor_idx * yolov5_class_stride + 0) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_y_idx = (anchor_idx * yolov5_class_stride + 1) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_w_idx = (anchor_idx * yolov5_class_stride + 2) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_h_idx = (anchor_idx * yolov5_class_stride + 3) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            float x = (float)raw_data[obj_x_idx] / yolov5params->scale[head_idx];

                            x = (x * 2.0 - 0.5 + w_idx) * (float)in_w / (float)(yolov5params->outWidth[head_idx]);

                            float y = (float)raw_data[obj_y_idx] / yolov5params->scale[head_idx];

                            y = (y * 2.0 - 0.5 + h_idx) * (float)in_h / (float)(yolov5params->outHeight[head_idx]);

                            float w = (float)raw_data[obj_w_idx] / yolov5params->scale[head_idx];

                            w = (w * 2.0) * (w * 2.0) * yolov5params->anchors[head_idx][anchor_idx][0];

                            float h = (float)raw_data[obj_h_idx] / yolov5params->scale[head_idx];

                            h = (h * 2.0) * (h * 2.0) * yolov5params->anchors[head_idx][anchor_idx][1];

                            /*计算points关键点的值*/

                            int obj_front1x_idx = (anchor_idx * yolov5_class_stride + 5) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_front1y_idy = (anchor_idx * yolov5_class_stride + 6) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_front2x_idx = (anchor_idx * yolov5_class_stride + 7) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_front2y_idx = (anchor_idx * yolov5_class_stride + 8) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_rear1x_idx = (anchor_idx * yolov5_class_stride + 9) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_rear1y_idx = (anchor_idx * yolov5_class_stride + 10) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_rear2x_idx = (anchor_idx * yolov5_class_stride + 11) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_rear2y_idx = (anchor_idx * yolov5_class_stride + 12) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            float front1x_sig = (float)raw_data[obj_front1x_idx] / yolov5params->scale[head_idx];

                            float front1x_log = -log((1/(front1x_sig + 1e-8)) - 1);

                            float front1x = front1x_log *  yolov5params->anchors[head_idx][anchor_idx][0] + w_idx * (float)in_w / (float)(yolov5params->outWidth[head_idx]);

                            float front1y_sig = (float)raw_data[obj_front1y_idy] / yolov5params->scale[head_idx];

                            float front1y_log = -log((1/(front1y_sig + 1e-8)) - 1);

                            float front1y = front1y_log *  yolov5params->anchors[head_idx][anchor_idx][1] + h_idx * (float)in_h / (float)(yolov5params->outHeight[head_idx]);                        

                            float front2x_sig = (float)raw_data[obj_front2x_idx] / yolov5params->scale[head_idx];

                            float front2x_log = -log((1/(front2x_sig + 1e-8)) - 1);

                            float front2x = front2x_log *  yolov5params->anchors[head_idx][anchor_idx][0] + w_idx * (float)in_w / (float)(yolov5params->outWidth[head_idx]);

                            float front2y_sig = (float)raw_data[obj_front2y_idx] / yolov5params->scale[head_idx];

                            float front2y_log = -log((1/(front2y_sig + 1e-8)) - 1);

                            float front2y = front2y_log *  yolov5params->anchors[head_idx][anchor_idx][1] + h_idx * (float)in_h / (float)(yolov5params->outHeight[head_idx]);  

                            float rear1x_sig = (float)raw_data[obj_rear1x_idx] / yolov5params->scale[head_idx];

                            float rear1x_log = -log((1/(rear1x_sig + 1e-8)) - 1);

                            float rear1x = rear1x_log *  yolov5params->anchors[head_idx][anchor_idx][0] + w_idx * (float)in_w / (float)(yolov5params->outWidth[head_idx]);

                            float rear1y_sig = (float)raw_data[obj_rear1y_idx] / yolov5params->scale[head_idx];

                            float rear1y_log = -log((1/(rear1y_sig + 1e-8)) - 1);

                            float rear1y = rear1y_log *  yolov5params->anchors[head_idx][anchor_idx][1] + h_idx * (float)in_h / (float)(yolov5params->outHeight[head_idx]);  

       

                            float rear2x_sig = (float)raw_data[obj_rear2x_idx] / yolov5params->scale[head_idx];

                            float rear2x_log = -log((1/(rear2x_sig + 1e-8)) - 1);

                            float rear2x = rear2x_log *  yolov5params->anchors[head_idx][anchor_idx][0] + w_idx * (float)in_w / (float)(yolov5params->outWidth[head_idx]);

                            float rear2y_sig = (float)raw_data[obj_rear2y_idx] / yolov5params->scale[head_idx];

                            float rear2y_log = -log((1/(rear2y_sig + 1e-8)) - 1);

                            float rear2y = rear2y_log *  yolov5params->anchors[head_idx][anchor_idx][1] + h_idx * (float)in_h / (float)(yolov5params->outHeight[head_idx]);  

                            /*计算车位属性的值*/

                            int obj_solt_occ_idx = (anchor_idx * yolov5_class_stride + 13) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_solt_vip_idx = (anchor_idx * yolov5_class_stride + 14) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_solt_woman_idx = (anchor_idx * yolov5_class_stride + 15) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_solt_disabled_idx = (anchor_idx * yolov5_class_stride + 16) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_solt_charging_idx = (anchor_idx * yolov5_class_stride + 17) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            int obj_solt_step_idx = (anchor_idx * yolov5_class_stride + 18) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                            float occ = (float)raw_data[obj_solt_occ_idx] / yolov5params->scale[head_idx];

                            float vip = (float)raw_data[obj_solt_vip_idx] / yolov5params->scale[head_idx];

                            float woman = (float)raw_data[obj_solt_woman_idx] / yolov5params->scale[head_idx];

                            float disable = (float)raw_data[obj_solt_disabled_idx] / yolov5params->scale[head_idx];

                            float charging = (float)raw_data[obj_solt_charging_idx] / yolov5params->scale[head_idx];

                            float step = (float)raw_data[obj_solt_step_idx] / yolov5params->scale[head_idx];

                            int cls = 0;

                            float cls_prob = 0.0;

                            /* 遍历查找类别内存,找到最大的置信度进行赋值 */

                            {

                                int obj_cls_idx;

                                int max_prob_idx;

                                float p;

                                for (max_prob_idx = 0; max_prob_idx < yolov5params->num_classes; ++max_prob_idx) {

                                    obj_cls_idx = (anchor_idx * yolov5_class_stride + 5 + 8 + 6 + max_prob_idx) * yolov5params->outChannelPitch[head_idx] + obj_hw_idx;

                                    p = (float)raw_data[obj_cls_idx] / yolov5params->scale[head_idx];

                                    if (p > cls_prob) {

                                        cls_prob = p;

                                        cls = max_prob_idx;

                                    }

                                }

                            }

                            if (cls_prob > max_cls_prob[head_idx]) {

                                max_cls_prob[head_idx] = cls_prob;

                            }

                            /* 输出概率 = 存在目标概率 * 类别置信概率 */

                            if (bbox_num >= MAX_TTE_YOLOV5_DETECTIONS_NUM) {

                                overflow_cnt[head_idx]++;

                                continue;

                            }

                            bbox_obj_arr[bbox_num].soltconfidence = conf * cls_prob;

                            if (bbox_obj_arr[bbox_num].soltconfidence > max_score[head_idx]) {

                                max_score[head_idx] = bbox_obj_arr[bbox_num].soltconfidence;

                            }

                            if (bbox_obj_arr[bbox_num].soltconfidence >= yolov5params->conf_thresh) {

                                // printf("save to conf = %f!!!\n", conf);

                                // printf("save to cls_prob = %f!!!\n", cls_prob);

                                // printf("save to bbox_obj_arr[bbox_num].soltconfidence = %f!!!\n", bbox_obj_arr[bbox_num].soltconfidence);

                                // printf("save to (float)raw_data[obj_cls_idx] = %f!!!\n", (float)raw_data[obj_cls_idx]);

                                bbox_obj_arr[bbox_num].x1 = (int)(x - w / 2 + 0.5);

                                bbox_obj_arr[bbox_num].y1 = (int)(y - h / 2 + 0.5);

                                bbox_obj_arr[bbox_num].x2 = (int)(x + w / 2 + 0.5);

                                bbox_obj_arr[bbox_num].y2 = (int)(y + h / 2 + 0.5);

                                bbox_obj_arr[bbox_num].soltcls = (int)cls;

                                bbox_obj_arr[bbox_num].occ_conf = occ;

                                bbox_obj_arr[bbox_num].vip_conf = vip;

                                bbox_obj_arr[bbox_num].woman_conf = woman;

                                bbox_obj_arr[bbox_num].disabled_conf = disable;

                                bbox_obj_arr[bbox_num].charging_conf = charging;

                                bbox_obj_arr[bbox_num].step_conf = step;

                                {

                                    if (front1x < 0) front1x = 0;

                                    if (front1y < 0) front1y = 0;

                                    if (front2x < 0) front2x = 0;

                                    if (front2y < 0) front2y = 0;

                                    if (rear1x < 0) rear1x = 0;

                                    if (rear1y < 0) rear1y = 0;

                                    if (rear2x < 0) rear2x = 0;

                                    if (rear2y < 0) rear2y = 0;

                                    bbox_obj_arr[bbox_num].soltpoints[0] = (int)front1x;

                                    bbox_obj_arr[bbox_num].soltpoints[1] = (int)front1y;

                                    bbox_obj_arr[bbox_num].soltpoints[2] = (int)front2x;

                                    bbox_obj_arr[bbox_num].soltpoints[3] = (int)front2y;

                                    bbox_obj_arr[bbox_num].soltpoints[4] = (int)rear1x;

                                    bbox_obj_arr[bbox_num].soltpoints[5] = (int)rear1y;

                                    bbox_obj_arr[bbox_num].soltpoints[6] = (int)rear2x;

                                    bbox_obj_arr[bbox_num].soltpoints[7] = (int)rear2y;

                                }

                                bbox_num++;

                                final_cnt[head_idx]++;

                            }

                        }

                    }

                }

            }

        }

    }

    //NMS

    bbox_num = NMS(bbox_obj_arr, bbox_num, yolov5params->nms_thresh);

    detections->num_bbox = bbox_num;

    //conf统计

    for(int h = 0; h < yolov5params->num_heads; h++)

    {

        printf("det_head[%d] stats: max_conf=%.4f max_cls=%.4f max_score=%.4f conf_pass=%d final=%d overflow=%d\n",

               h, max_conf[h], max_cls_prob[h], max_score[h], conf_pass_cnt[h], final_cnt[h], overflow_cnt[h]);

#if DEBUG_PRINT_TOPK_CONF

        printf("det_head[%d] topk_conf:", h);

        for (int tk = 0; tk < TOPK_CONF_NUM; tk++)

        {

            printf(" %.4f", topk_conf[h][tk]);

        }

        printf("\n");

#endif

    }

    {

        float best_conf = 0.0f;

        float best_score = 0.0f;

        int total_conf_pass = 0;

        int total_final = 0;

        for (int h = 0; h < yolov5params->num_heads; h++)

        {

            if (max_conf[h] > best_conf) best_conf = max_conf[h];

            if (max_score[h] > best_score) best_score = max_score[h];

            total_conf_pass += conf_pass_cnt[h];

            total_final += final_cnt[h];

        }

        printf("det_all stats: max_conf=%.4f max_score=%.4f conf_pass=%d final=%d\n",

               best_conf, best_score, total_conf_pass, total_final);

    }

    //conf统计

    for(int num = 0; num < bbox_num; num++)

    {

        detections->buffer[num] = bbox_obj_arr[num];

    }

    int num = detections->num_bbox;

    ttevxYoloV5BBox num0 = detections->buffer[0];

    ttevxYoloV5BBox num1 = detections->buffer[1];

    return status;

}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐