AOC的计算

AOC指的是PR(精度-召回)曲线的曲线下面积,用于评估目标检测网络的性能。
AOC的计算过程如下:
1、获得网络推断的pred_bbox、pred_class、pred_score和真值gt_bbox、gt_class
2、对于每个类别,根据iou条件,增加一个正例(TP)或负例(FP)和对应的score
3、按照score升序,计算精度和召回的前缀和向量
4、计算不同召回下的精度,累加得到AOC

参考代码:
https://github.com/garg-abhinav/FasterRCNN

import numpy as np
import itertools
from collections import defaultdict

def bbox_iou(bbox_a, bbox_b):
    '''
    This function calculates IoU (intersection of union) between bounding boxes. The IoU ratios are used to 
    eliminate overlapping bounding boxes and for training we only take into account with IoU < 0.3 and IoU > 0.7 
    for labeling as foreground and background.

    '''    
    if bbox_a.shape[1] != 4 or bbox_b.shape[1] != 4:
        raise IndexError

    # top left
    tl = np.maximum(bbox_a[:, None, :2], bbox_b[:, :2])  
    # bottom right
    br = np.minimum(bbox_a[:, None, 2:], bbox_b[:, 2:])

    area_i = np.prod(br - tl, axis=2) * (tl < br).all(axis=2)
    area_a = np.prod(bbox_a[:, 2:] - bbox_a[:, :2], axis=1)
    area_b = np.prod(bbox_b[:, 2:] - bbox_b[:, :2], axis=1)
    return area_i / (area_a[:, None] + area_b - area_i)

'''
These functions are used to calculate the mAP values for testing phase
'''

def eval_detection_voc(
        pred_bboxes, pred_labels, pred_scores, gt_bboxes, gt_labels,
        iou_thresh=0.5, use_07_metric=False):
    prec, rec = calc_detection_voc_prec_rec(
        pred_bboxes, pred_labels, pred_scores,
        gt_bboxes, gt_labels,
        iou_thresh=iou_thresh) ##  计算累加的precision 和 recall 矩阵

    ap = calc_detection_voc_ap(prec, rec) ## 所有类别的ap
    ## use 07 metric 就是11点形式
    return {'ap': ap, 'map': np.nanmean(ap)}

## 预处理 precision和 recall 
def calc_detection_voc_prec_rec(
        pred_bboxes, pred_labels, pred_scores, gt_bboxes, gt_labels,
        iou_thresh=0.5):
    pred_bboxes = iter(pred_bboxes)
    pred_labels = iter(pred_labels)
    pred_scores = iter(pred_scores)
    gt_bboxes = iter(gt_bboxes)
    gt_labels = iter(gt_labels)


    n_pos = defaultdict(int)
    score = defaultdict(list)
    match = defaultdict(list) ## 默认value为list

    for pred_bbox, pred_label, pred_score, gt_bbox, gt_label in \
            zip(pred_bboxes, pred_labels, pred_scores,
                gt_bboxes, gt_labels):

        for l in np.unique(np.concatenate((pred_label, gt_label)).astype(int)):
            pred_mask_l = pred_label == l
            pred_bbox_l = pred_bbox[pred_mask_l]
            pred_score_l = pred_score[pred_mask_l]

            gt_mask_l = gt_label == l
            gt_bbox_l = gt_bbox[gt_mask_l]

            n_pos[l] += gt_mask_l.sum() ## 用于计算recall, tp+fn 

            score[l].extend(pred_score_l)

            if len(pred_bbox_l) == 0:
                continue
            if len(gt_bbox_l) == 0:
                match[l].extend((0,) * pred_bbox_l.shape[0])
                continue
            # VOC evaluation follows integer typed bounding boxes.
            pred_bbox_l = pred_bbox_l.copy() ## 
            pred_bbox_l[:, 2:] += 1
            gt_bbox_l = gt_bbox_l.copy()
            gt_bbox_l[:, 2:] += 1

            iou = bbox_iou(pred_bbox_l, gt_bbox_l) ## 删掉iou小于0.5的结果
            gt_index = iou.argmax(axis=1)
            # set -1 if there is no matching ground truth
            gt_index[iou.max(axis=1) < iou_thresh] = -1
            del iou

            selec = np.zeros(gt_bbox_l.shape[0], dtype=bool)
            for gt_idx in gt_index:
                if gt_idx >= 0:
                    if not selec[gt_idx]:
                        match[l].append(1)
                    else:
                        match[l].append(0)
                    selec[gt_idx] = True
                else:
                    match[l].append(0)

    for iter_ in (
            pred_bboxes, pred_labels, pred_scores,
            gt_bboxes, gt_labels):
        if next(iter_, None) is not None:
            raise ValueError('Length of input iterables need to be same.')

    n_fg_class = max(n_pos.keys()) + 1
    prec = [None] * n_fg_class
    rec = [None] * n_fg_class

    for l in n_pos.keys():
        score_l = np.array(score[l])
        match_l = np.array(match[l], dtype=np.int8)

        order = score_l.argsort()[::-1] ## 排序后保留前缀和,便于计算AOC
        match_l = match_l[order]

        tp = np.cumsum(match_l == 1)
        fp = np.cumsum(match_l == 0)

        # If an element of fp + tp is 0,
        # the corresponding element of prec[l] is nan.
        prec[l] = tp / (fp + tp)
        # If n_pos[l] is 0, rec[l] is None.
        if n_pos[l] > 0:
            rec[l] = tp / n_pos[l]

    return prec, rec

## 计算AOC 
def calc_detection_voc_ap(prec, rec):
    ##  prec 精度 , rec 召回
    n_fg_class = len(prec) ## 类别数
    ap = np.empty(n_fg_class)
    for l in range(n_fg_class):
        if prec[l] is None or rec[l] is None:
            ap[l] = np.nan
            continue
        # 11 point metric
        ap[l] = 0
        for t in np.arange(0., 1.1, 0.1):
            if np.sum(rec[l] >= t) == 0:
                p = 0
            else:
                p = np.max(np.nan_to_num(prec[l])[rec[l] >= t])
            ap[l] += p / 11
    return ap

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值