• 目标检测框存在内嵌情况分析与解决


    问题描述

    目标检测模型输出的检测框存在内嵌情况。

    在这里插入图片描述


    原因分析与解决方法:

    根据经验,第一感觉是后处理nms部分出了问题。来看下对应的代码:

    static float CalcIou(const vector<float> &box1, const vector<float> &box2)
    {
        float area1 = box1[6];
        float area2 = box2[6];
        float xx1 = max(box1[0], box2[0]);
        float yy1 = max(box1[1], box2[1]);
        float xx2 = min(box1[2], box2[2]);
        float yy2 = min(box1[3], box2[3]);
        float w = max(0.0f, xx2 - xx1 + 1);
        float h = max(0.0f, yy2 - yy1 + 1);
        float inter = w * h;
        float ovr = inter /(area1 + area2 - inter);
        return ovr;
    }
    
    static void MulticlassNms(vector<vector<float>>& bboxes, const vector<vector<float>>& vaildBox, float nmsThr)
    {
        for (auto &item : vaildBox) { /* score, xcenter, ycenter, w, h, classId */
            float boxXCenter = item[XCENTER_IDX];
            float boxYCenter = item[YCENTER_IDX];
            float boxWidth = item[W_IDX];
            float boxHeight = item[H_IDX];
    
            float x1 = (boxXCenter - boxWidth / 2);
            float y1 = (boxYCenter - boxHeight / 2);
            float x2 = (boxXCenter + boxWidth / 2);
            float y2 = (boxYCenter + boxHeight / 2);
            float area = (x2 - x1 + 1) * (y2 - y1 + 1);
            bool keep = true;
            /* lx, ly, rx, ry, score, class id, area */
            vector<float> bbox {x1, y1, x2, y2, item[SCORE_IDX], item[CLSAA_ID_IDX], area};
            for (size_t j = 0; j < bboxes.size(); j++) {
                if (CalcIou(bbox, bboxes[j]) > nmsThr) {
                    keep = false;
                    break;
                }
            }
            if (keep) {
                bboxes.push_back(bbox);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    目前分析最可能的原因是nmsnmsThr设置过大,没能滤除重叠检测框,原来nmsThr设置的为0.45,现调整为0.1
    检测框内嵌情况基本消失:
    在这里插入图片描述


    后续及思考

    先给个结论,综合的看下各个Loss函数的不同点::
    IOU_Loss:主要考虑检测框和目标框重叠面积
    GIOU_Loss:在IOU的基础上,解决边界框不重合时的问题。
    DIOU_Loss:在IOU和GIOU的基础上,考虑边界框中心点距离的信息。
    CIOU_Loss:在DIOU的基础上,考虑边界框宽高比的尺度信息。
    此项目中用的是基本的IOU,在推理性能足够的情况下,可以考虑使用DIOU,下面也给出使用DIOUnms代码:

    static float CalcDiou(const vector<float>& box1, const vector<float>& box2) {
        float x1 = min(box1[0], box2[0]);
        float y1 = min(box1[1], box2[1]);
        float x2 = max(box1[2], box2[2]);
        float y2 = max(box1[3], box2[3]);
        
        float c_x1 = (box1[0] + box1[2]) / 2.0;
        float c_y1 = (box1[1] + box1[3]) / 2.0;
        float c_x2 = (box2[0] + box2[2]) / 2.0;
        float c_y2 = (box2[1] + box2[3]) / 2.0;
        
        float dist_center = sqrt((c_x1 - c_x2) * (c_x1 - c_x2) + (c_y1 - c_y2) * (c_y1 - c_y2));
        
        float w = max(0.0f, x2 - x1);
        float h = max(0.0f, y2 - y1);
        
        float intersection = w * h;
        float area1 = (box1[2] - box1[0]) * (box1[3] - box1[1]);
        float area2 = (box2[2] - box2[0]) * (box2[3] - box2[1]);
        
        float union_area = area1 + area2 - intersection;
        
        float diou = intersection / union_area - dist_center * dist_center / (union_area * union_area);
        
        return diou;
    }
    
    static void MulticlassNms(vector<vector<float>>& bboxes, const vector<vector<float>>& vaildBox, float nmsThr)
    {
        for (auto &item : vaildBox) { /* score, xcenter, ycenter, w, h, classId */
            float boxXCenter = item[XCENTER_IDX];
            float boxYCenter = item[YCENTER_IDX];
            float boxWidth = item[W_IDX];
            float boxHeight = item[H_IDX];
    
            float x1 = (boxXCenter - boxWidth / 2);
            float y1 = (boxYCenter - boxHeight / 2);
            float x2 = (boxXCenter + boxWidth / 2);
            float y2 = (boxYCenter + boxHeight / 2);
            float area = (x2 - x1 + 1) * (y2 - y1 + 1);
            bool keep = true;
    
            vector<float> bbox {x1, y1, x2, y2, item[SCORE_IDX], item[CLSAA_ID_IDX], area};
            for (size_t j = 0; j < bboxes.size(); j++) {
                if (CalcDiou(bbox, bboxes[j]) > nmsThr) {
                    keep = false;
                    break;
                }
            }
            if (keep) {
                bboxes.push_back(bbox);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    有读者会有疑问,这里为什么不用CIOU_nms,而用DIOU_nms?
    答:因为CIOU_loss,是在DIOU_loss的基础上,添加的影响因子,包含groundtruth标注框的信息,在训练时用于回归。
    但在测试过程中,并没有groundtruth的信息,不用考虑影响因子,因此直接用DIOU_nms即可。

    参考文档

    https://blog.csdn.net/nan355655600/article/details/106246625

  • 相关阅读:
    qmake TEMPLATE subdirs
    【无标题】
    Java面试题13-CountDownLatch和Semaphore的区别和底层原理
    02 | 如何进行code diff
    2022年,你的数据库还没有上云吗?
    数据结构与算法知识点总结(3)树、图与并查集
    前端性能优化方法与实战04 指标采集:首屏时间指标采集具体办法
    实战|轻松用 Python 开发一个简单有趣的聊天小程序
    基于区域划分的GaN HEMT 准物理大信号模型
    高端知识竞赛活动中的舞美设计
  • 原文地址:https://blog.csdn.net/JulyLi2019/article/details/134465967