目标检测中的评价指标知识点总结:IOU交叉重叠单元、map/AP/TP/FP/NP的归纳

在目标检测任务中,我们时常会让模型一次性生成大量的候选框(candidate bound),然后再根据每一个框的置信度对框进行排序,进而依次计算框与框之间的IoU,以非极大值抑制的方式,来判断到底哪一个是我们真正要找的物体,哪几个又该删除。例如在做人脸检测时,模型输出的可能是左图,而最终我们得到的是右图。
在这里插入图片描述

代码实现

import numpy as np
# box:[上, 左, 下, 右]
box1 = [0,0,8,6]
box2 = [2,3,10,9]

def IoU(box1, box2):
    # 计算中间矩形的宽高
    in_h = min(box1[2], box2[2]) - max(box1[0], box2[0])
    in_w = min(box1[3], box2[3]) - max(box1[1], box2[1])

    # 计算交集、并集面积
    inter = 0 if in_h < 0 or in_w < 0 else in_h * in_w
    union = (box1[2] - box1[0]) * (box1[3] - box1[1]) + \
            (box2[2] - box2[0]) * (box2[3] - box2[1]) - inter
    # 计算IoU
    iou = inter / union
    return iou
IoU(box1, box2)

其他的评价指标:分类的精度如何。一般可以用准确度(Accuracy),精度(Precision),召回率(Recall Rate), PR 曲线,AP,mAP等
定位的精度如何。比如 IoU
运行的速度如何。比如 fps,一秒处理几张图。
严格说某些场合也会很在意模型的大小,这也是一个研究方向,比如 squeeze net, mobile net, shuffle net 等。所以除了上面三个维度,模型的大小也可以是一个评价维度。
AP(Average Precision) mAP(mean AP全局所有种类加权平均的平均准确率) IoU(Intersection over Union)
在计算mAP之前,需要了解下面四个衡量指标:

(1)True Positive (TP):表示一个正确的检测结果。在标注边界框附近存在预测边界框,并且预测边界框与标注边界框之间的IoU大于交并比阈值。

(2)False Positive (FP):表示一个错误的检测结果。在标注边界框附近存在预测边界框,但是预测边界框与标注边界框之间的IoU小于交并比阈值。

(3)False Negative(FN):表示在一个标注边界框附近,检测网络并没有输出预测值。换句话说,就是漏检了。

(4)True Negative(TN):计算mAP的时候,这个指标并不需要,因此就不再详细介绍。

1.3 查准率(Precision)和查全率(Recall)
查准率表示模型成功预测正样本的能力。它的计算公式如下:
Precision=TP/(TP+FP)
查全率表示模型能够预测出正样本的能力。它的计算公式如下:
RECALL=TP/(TP+FN)

查准率和查全率是一对矛盾的度量,一般而言,查准率高时,查全率往往偏低;而查全率高时,查准率往往偏低。我们从直观理解确实如此:我们如果希望好瓜尽可能多地选出来,则可以通过增加选瓜的数量来实现,如果将所有瓜都选上了,那么所有好瓜也必然被选上,但是这样查准率就会越低;若希望选出的瓜中好瓜的比例尽可能高,则只选最有把握的瓜,但这样难免会漏掉不少好瓜,导致查全率较低。通常只有在一些简单任务中,才可能使查全率和查准率都很高。所以为了更全面的衡量模型的性能提出了 AP。平均精确率(Average Precision).
平均准确率(AP)是衡量目标检测器的一个性能指标,它可以根据P-R曲线与坐标轴所围成的面积计算得到。其中,P-R曲线表示在以查全率为横坐标,查准率为纵坐标的坐标系下,所绘制的曲线,具体绘制过程下面会详细介绍。其中计算AP值有两种方法,但是这边我只详细介绍其中一种,因为这个方法更为常用。该方法称为Interpolating all points(另一个方法称为11-point interpolation),该方法求的AP值就是在查准率-查全率坐标图中曲线与坐标轴的面积。

重要的来了:mAP的计算过程就是求每一类物体的AP值,然后求和取平均

classes <- 所有类别标签的集合
rests <- 每一类precision和recall以及AP的值的集合
predicts <- 模型预测的所有结果
ground_truth <- 标注的所有结果
# 对每一类物体求AP
for cls in classes do:
    preds <- precits中所有类别为cls的边界框信息
    gts <- ground_truth中所有类别为cls的边界框信息
    TP <- 长度为len(preds)的数组,并初始化为0
    FP <- 长度为len(preds)的数组,并初始化为0
    occupied <- 记录每个图像中n个gt是否被pred负责预测的词典
    # 确定每一个pred是TP还是FP
    for i, pred in enumerate(preds) do:
        # 找到该pred与gts哪个边界框的IOU最大,将让该pred负责预测该gt,并保存该gt的索引
        for j, gt in enumerate(gts) do:
            jou = IOU(pred, gt)
            jmax = j
        # 当iou不小于阈值并且该边界框预测的gt没有被预测,将其设置为TP
        if iou >= threshold and (occupied[cls][imax] == 0):
            TP[i] = 1
        else
            FP[i] = 1
    # 根据TP和FP求acc_TP和acc_FP
    acc_TP = np.cumsum(TP)
    acc_FP = np.cumsum(FP)
    rec = acc_TP / len(gts)
    prec = acc_TP / (acc_TP + acc_FP)
    # 根据rec和prec求ap
    ap <- CalculateAveragePrecision(rec, prec)
    # 将每一类的ap保存在rests中
    rests.append(ap)


当采用VOC数据集格式时:


```bash
def GetPascalVOCMetrics(boundingboxes,
                        IOUThreshold=0.5,
                        method=MethodAveragePrecision.EveryPointInterpolation):
    # 输出结果初始化为一个列表
    ret = [] 
    # List with all ground truths (Ex: [imageName,class,confidence=1, (bb coordinates XYX2Y2)])
    # 存放标记的所有边界框(与下文的detections一起使用,用于求每个预测结果是TP还是FP)
    groundTruths = []
    # List with all detections (Ex: [imageName,class,confidence,(bb coordinates XYX2Y2)])
    detections = []
    # 存放该数据集中所有的类别(需要求每个类别的AP值)
    classes = []
    # 这段代码涉及到一些更加细节的问题,你可以将其视为从boundingboxes中获取gt和pred的边界框信息
    # detections = [['00001', 'person', 0.88, (5.0, 67.0, 36.0, 115.0)],[],....]
    # gt的值也类似,只不过第三列数据是0或者1,而不是小数
    for bb in boundingboxes.getBoundingBoxes():
        # [imageName, class, confidence, (bb coordinates XYX2Y2)]
        if bb.getBBType() == BBType.GroundTruth:
            groundTruths.append([
                bb.getImageName(),
                bb.getClassId(), 1,
                bb.getAbsoluteBoundingBox(BBFormat.XYX2Y2)
            ])
        else:
            detections.append([
                bb.getImageName(),
                bb.getClassId(),
                bb.getConfidence(),
                bb.getAbsoluteBoundingBox(BBFormat.XYX2Y2)
            ])
        # get class
        if bb.getClassId() not in classes:
            classes.append(bb.getClassId())
    # 对类别进行排序
    classes = sorted(classes)
    ...
    return ret
###以下是补充对TP/FP的判断:正确的检测结果和错误的判断
# 精确到该类在哪个图像中
for d in range(len(dects)):
    # print('dect %s => %s' % (dects[d][0], dects[d][3],))
    # Find ground truth image
    # 将所有属于文件detect[d][0]图像的gt都保存下来
    gt = [gt for gt in gts if gt[0] == dects[d][0]]
    iouMax = sys.float_info.min
    # 选择gt与当前预测值的边界框最大的交并比
    for j in range(len(gt)):
        # print('Ground truth gt => %s' % (gt[j][3],))
        iou = Evaluator.iou(dects[d][3], gt[j][3])
        if iou > iouMax:
            iouMax = iou
            jmax = j
    # Assign detection as true positive/don't care/false positive
    # 如果阈值
    if iouMax >= IOUThreshold:
        # 表示当前jmax个物体
        if det[dects[d][0]][jmax] == 0:
            TP[d] = 1  # count as true positive
            # 表示这个gt已经有相应的prediction进行预测了
            det[dects[d][0]][jmax] = 1  # flag as already 'seen'
            # print("TP")
        else:
            FP[d] = 1  # count as false positive
            # print("FP")
    # - A detected "cat" is overlaped with a GT "cat" with IOU >= IOUThreshold.
    # 假阴性
    else:
        FP[d] = 1  # count as false positive
        # print("FP")

版权声明:本文为CSDN博主「Life is a joke」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45756171/article/details/122744194

Life is a joke

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

Yolo(3)(项目)Yolo v3 目标检测(85分类)

目录 基础理论 一、 读取文件 二、神经网络初始化 1、搭建神经网络 2、GPU加速 三、打开摄像头、按帧读取图像 四、向神经网络输入 五、获取神经网络输出 1、获取各层名称 2、获取输出层名称 3、获取输出层图像&#xff

GiraffeDet:Heavy Neck的目标检测框架

关注并星标 从此不迷路 计算机视觉研究院 公众号ID|ComputerVisionGzq 学习群|扫码在主页获取加入方式 获取论文:关注并回复“GD” 计算机视觉研究院专栏 作者:Edison_G 在传统的目标检测框架中,从图像识别模型继承的主