目标检测mAP计算详解

首先说明计算mAP有多个版本,每个数据集和比赛用的版本和方式也不同,下以VOC与COCO举例说明。精确度(precision),召回率(recall)分别为:
目标检测mAP计算详解_第1张图片
在这里插入图片描述
在这里插入图片描述

常规的mAP计算为(这是一个N类检测任务):
1、计算单张图片中class1的精度P(VOC默认IOU大于0.5即为TP,COCO稍复杂些,下文再说)
2、循环所有测试集图片,重复1过程求所有图片P的均值即为class1的AP
3、对剩余N-1类重复1和2过程,对每个类的AP求均值,即为mAP

注:为什么说是常规呢,因为很多框架例如caffe中上述过程1可能不是单张,也可以为一个mini-batch,其实不差事了。

-----------------------------------------分割线------------------------------------------

以上分析了mAP值的原始初衷,仔细回想一下影响mAP值(即precision与recall)的有哪些因素呢:
1、IOU(例如IOU取接近0,recall会趋近于1,precision会趋紧于0)
2、bbox的score阈值

为了统一标准,VOC 2007年提出采用IOU阈值确定为0.5,采用11采样点来计算mAP,选择11个不同的recall([0, 0.1, …, 0.9, 1.0]),可以认为是选择了11个rank,由于按照置信度排序,所以实际上等于选择了11个不同的置信度阈值。2010年以后VOC提出11点改为全部点。

以上步骤其实就是在常规计算mAP值外加了一层循环,即选取一系列的recall与precision采用点,相当于上述影响mAP值中的2因素进行全面的计算和求均值。

以下为代码:

1、precision与recall计算

# 按照置信度降序排序
sorted_ind = np.argsort(-confidence)
BB = BB[sorted_ind, :]   # 预测框坐标
image_ids = [image_ids[x] for x in sorted_ind] # 各个预测框的对应图片id

# 便利预测框,并统计TPs和FPs
nd = len(image_ids)
tp = np.zeros(nd)
fp = np.zeros(nd)
for d in range(nd):
    R = class_recs[image_ids[d]]
    bb = BB[d, :].astype(float)
    ovmax = -np.inf
    BBGT = R['bbox'].astype(float)  # ground truth

    if BBGT.size > 0:
        # 计算IoU
        # intersection
        ixmin = np.maximum(BBGT[:, 0], bb[0])
        iymin = np.maximum(BBGT[:, 1], bb[1])
        ixmax = np.minimum(BBGT[:, 2], bb[2])
        iymax = np.minimum(BBGT[:, 3], bb[3])
        iw = np.maximum(ixmax - ixmin + 1., 0.)
        ih = np.maximum(iymax - iymin + 1., 0.)
        inters = iw * ih

        # union
        uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
               (BBGT[:, 2] - BBGT[:, 0] + 1.) *
               (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

        overlaps = inters / uni
        ovmax = np.max(overlaps)
        jmax = np.argmax(overlaps)
    # 取最大的IoU
    if ovmax > ovthresh:  # 是否大于阈值
        if not R['difficult'][jmax]:  # 非difficult物体
            if not R['det'][jmax]:    # 未被检测
                tp[d] = 1.
                R['det'][jmax] = 1    # 标记已被检测
            else:
                fp[d] = 1.
    else:
        fp[d] = 1.

# 计算precision recall
fp = np.cumsum(fp)
tp = np.cumsum(tp)
rec = tp / float(npos)
# avoid divide by zero in case the first detection matches a difficult
# ground truth
prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)

2、这里最终得到一系列的precision和recall值,并且这些值是按照置信度降低排列统计的,可以认为是取不同的置信度阈值(或者rank值)得到的。然后据此可以计算AP:

def voc_ap(rec, prec, use_07_metric=False):
    """Compute VOC AP given precision and recall. If use_07_metric is true, uses
    the VOC 07 11-point method (default:False).
    """
    if use_07_metric:  # 使用07年方法
        # 11 个点
        ap = 0.
        for t in np.arange(0., 1.1, 0.1):
            if np.sum(rec >= t) == 0:
                p = 0
            else:
                p = np.max(prec[rec >= t])  # 插值
            ap = ap + p / 11.
    else:  # 新方式,计算所有点
        # correct AP calculation
        # first append sentinel values at the end
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))

        # compute the precision 曲线值(也用了插值)
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])

        # to calculate area under PR curve, look for points
        # where X axis (recall) changes value
        i = np.where(mrec[1:] != mrec[:-1])[0]

        # and sum (\Delta recall) * prec
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    return ap

而COCO数据集在计算mAP时针对因素1,即IOU选取也做了调整,即对IOU选取也做了一次循环求均值的过程,IOU选取为 0.50:0.05:0.95

目标检测mAP计算详解_第2张图片
参考:
https://zhuanlan.zhihu.com/p/37910324
https://blog.csdn.net/katherine_hsr/article/details/79266880
https://blog.csdn.net/lixiang_whu/article/details/64495093
https://www.jianshu.com/p/d7a06a720a2b
https://blog.csdn.net/qq_41994006/article/details/81051150
https://oldpan.me/archives/iu-iou-intersection-over-union-python
https://oldpan.me/archives/understand-coco-metric
https://blog.csdn.net/hsqyc/article/details/81702437

你可能感兴趣的:(计算机视觉,深度学习)