mmrotate:详细解读eval_map.py里面的计算TP和FP的代码,并计算虚警率和漏警率

        如果需要计算虚警率和漏警率,那么就需要详细了解这个函数:tpfp_default。

        在原始的代码中写了注释,方便大家阅读:

def tpfp_default(det_bboxes,
                 gt_bboxes,
                 gt_bboxes_ignore=None,
                 iou_thr=0.5,
                 area_ranges=None):
    """Check if detected bboxes are true positive or false positive.
	先明白,这里的det已经是检测框了!这里的框已经经过了nms,也就是已经被nms的阈值过了一遍了,已经是最终结果了!所以这里的框要不就是对的,要不就是错的,不存在没用的这个选项!
    Args:
        det_bboxes (ndarray): Detected bboxes of this image, of shape (m, 6).
        gt_bboxes (ndarray): GT bboxes of this image, of shape (n, 5).
        gt_bboxes_ignore (ndarray): Ignored gt bboxes of this image,
            of shape (k, 5). Default: None
        iou_thr (float): IoU threshold to be considered as matched.
            Default: 0.5.
        area_ranges (list[tuple] | None): Range of bbox areas to be evaluated,
            in the format [(min1, max1), (min2, max2), ...]. Default: None.

    Returns:
        tuple[np.ndarray]: (tp, fp) whose elements are 0 and 1. The shape of
            each array is (num_scales, m).
    """
    # an indicator of ignored gts
    det_bboxes = np.array(det_bboxes)
    gt_ignore_inds = np.concatenate(
        (np.zeros(gt_bboxes.shape[0], dtype=np.bool),
         np.ones(gt_bboxes_ignore.shape[0], dtype=np.bool)))
    # stack gt_bboxes and gt_bboxes_ignore for convenience
    gt_bboxes = np.vstack((gt_bboxes, gt_bboxes_ignore))

    num_dets = det_bboxes.shape[0]
    num_gts = gt_bboxes.shape[0]
    if area_ranges is None:
        area_ranges = [(None, None)]
    num_scales = len(area_ranges)
    # tp and fp are of shape (num_scales, num_gts), each row is tp or fp of
    # a certain scale
    tp = np.zeros((num_scales, num_dets), dtype=np.float32) #这个float类型!之后会变成0和1-----tp
    fp = np.zeros((num_scales, num_dets), dtype=np.float32) #这个float类型!之后会变成0和1-----fp

    # if there is no gt bboxes in this image, then all det bboxes
    # within area range are false positives
    if gt_bboxes.shape[0] == 0:
        if area_ranges == [(None, None)]:
            fp[...] = 1
        else:
            raise NotImplementedError
        return tp, fp

    ious = box_iou_rotated(
        torch.from_numpy(det_bboxes).float(),
        torch.from_numpy(gt_bboxes).float()).numpy() # 这个就是计算IOU,IOU是一个位于(0,1)之间的float类型的东西
    ious_max = ious.max(axis=1) # 每一个检测框与所有gt比较,得到的最大IOU,这个是一个位于(0,1)之间的float类型的东西,也就是说,对于第i个det的最大iou就是ious[i]
    ious_argmax = ious.argmax(axis=1) # 对于找到的那个最大的IOU,看看是哪个gt与之匹配,这应该是那个gt对应的id,反正就是一个指示是哪一个gt的identity,长度和gt一样
    sort_inds = np.argsort(-det_bboxes[:, -1]) # 对于所有的预测框,按照分数进行降序排序,先从分最高的开始
    for k, (min_area, max_area) in enumerate(area_ranges):
        gt_covered = np.zeros(num_gts, dtype=bool) # 这个是某一个gt是否为cover到,也就是是否被预测到了,是一个bool类型的,与之前的gt_bboxes一一对应
        # if no area range is specified, gt_area_ignore is all False
        if min_area is None:
            gt_area_ignore = np.zeros_like(gt_ignore_inds, dtype=bool) 
        else:
            raise NotImplementedError
        for i in sort_inds:
            if ious_max[i] >= iou_thr:  #就是,能进入这个if的,都已经是positive了,如果小于,那就认为是negetive(包括TN和PN)
			matched_gt = ious_argmax[i] # 这个是匹配的gt的identity,这里是det匹配上的那【一个】gt,一个det只能有一个gt匹配上,但是一个gt可能不止被一个det盯上
                if not (gt_ignore_inds[matched_gt]
                        or gt_area_ignore[matched_gt]):
							if not gt_covered[matched_gt]: # 把当前的gt的id(也就是matched_gt)所对应的gt找到,如果这个gt没被标注过
							gt_covered[matched_gt] = True # 那么这个gt就是和det匹配的,并记下这个gt是被匹配上了,后面的det如果也想找它匹配的话就都是FP!
                        tp[k, i] = 1 # 这个k是1,记录下当前这个det是TP
                    else: # 如果之前score更大的det已经找到了这个gt了(之前那个已经被标注成TP),那么这个就不对了,那就是FP!
                        fp[k, i] = 1 # 这个k是1,记录下当前这个det是FP
            elif min_area is None:
                fp[k, i] = 1
            else:
                bbox = det_bboxes[i, :5]
                area = bbox[2] * bbox[3]
                if area >= min_area and area < max_area:
                    fp[k, i] = 1
    return tp, fp

        简单来说:如果一个det的IOU大于阈值,那么就先认为它是True,但有可能nms那一步的时候,用score筛选得不是很好,以至于好几个det同时框在了一个gt上,所以那些框的不是很好的det即使大于了iou阈值,也要被划成fp;另外,对于那些小于iou阈值的det,就全部划成了fp。对于那些置信度本来就小于score的det,就认为是negetive,也就是fp和tp全部赋为0。如果需要计算fn,那就用gt的数量减去tp就好~

猜你喜欢

转载自blog.csdn.net/weixin_46812066/article/details/129868818