def bbox_recalls(gts, proposals, proposal_nums=None, iou_thrs=None, print_summary=True): """Calculate recalls Args: gts(list or ndarray): a list of arrays of shape (n, 4) proposals(list or ndarray): a list of arrays of shape (k, 4) or (k, 5) proposal_nums(int or list of int or ndarray): top N proposals thrs(float or list or ndarray): iou thresholds Returns: ndarray: recalls of different ious and proposal nums """ img_num = len(gts) assert img_num == len(proposals) proposal_nums, iou_thrs = set_recall_param(proposal_nums, iou_thrs) all_ious = [] for i in range(img_num): if proposals[i].ndim == 2 and proposals[i].shape[1] == 5: scores = proposals[i][:, 4] sort_idx = np.argsort(scores)[::-1] img_proposal = proposals[i][sort_idx, :] else: img_proposal = proposals[i] prop_num = min(img_proposal.shape[0], proposal_nums[-1]) if gts[i] is None or gts[i].shape[0] == 0: ious = np.zeros((0, img_proposal.shape[0]), dtype=np.float32) else: ious = bbox_overlaps(gts[i], img_proposal[:prop_num, :4]) all_ious.append(ious) all_ious = np.array(all_ious) recalls = _recalls(all_ious, proposal_nums, iou_thrs) if print_summary: print_recall_summary(recalls, proposal_nums, iou_thrs) return recalls
def tpfp_default(det_bboxes, gt_bboxes, gt_ignore, iou_thr, area_ranges=None): """Check if detected bboxes are true positive or false positive. Args: det_bbox(ndarray): the detected bbox gt_bboxes(ndarray): ground truth bboxes of this image gt_ignore(ndarray): indicate if gts are ignored for evaluation or not iou_thr(float): the iou thresholds Returns: tuple: (tp, fp), two arrays whose elements are 0 and 1 """ 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) fp = np.zeros((num_scales, num_dets), dtype=np.float32) # 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: det_areas = (det_bboxes[:, 2] - det_bboxes[:, 0] + 1) * (det_bboxes[:, 3] - det_bboxes[:, 1] + 1) for i, (min_area, max_area) in enumerate(area_ranges): fp[i, (det_areas >= min_area) & (det_areas < max_area)] = 1 return tp, fp ious = bbox_overlaps(det_bboxes, gt_bboxes) ious_max = ious.max(axis=1) ious_argmax = ious.argmax(axis=1) 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) # 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, dtype=bool) else: gt_areas = (gt_bboxes[:, 2] - gt_bboxes[:, 0] + 1) * (gt_bboxes[:, 3] - gt_bboxes[:, 1] + 1) gt_area_ignore = (gt_areas < min_area) | (gt_areas >= max_area) for i in sort_inds: if ious_max[i] >= iou_thr: matched_gt = ious_argmax[i] if not (gt_ignore[matched_gt] or gt_area_ignore[matched_gt]): if not gt_covered[matched_gt]: gt_covered[matched_gt] = True tp[k, i] = 1 else: fp[k, i] = 1 # otherwise ignore this detected bbox, tp = 0, fp = 0 elif min_area is None: fp[k, i] = 1 else: bbox = det_bboxes[i, :4] area = (bbox[2] - bbox[0] + 1) * (bbox[3] - bbox[1] + 1) if area >= min_area and area < max_area: fp[k, i] = 1 return tp, fp
def tpfp_imagenet(det_bboxes, gt_bboxes, gt_ignore, default_iou_thr, area_ranges=None): """Check if detected bboxes are true positive or false positive. Args: det_bbox(ndarray): the detected bbox gt_bboxes(ndarray): ground truth bboxes of this image gt_ignore(ndarray): indicate if gts are ignored for evaluation or not default_iou_thr(float): the iou thresholds for medium and large bboxes area_ranges(list or None): gt bbox area ranges Returns: tuple: two arrays (tp, fp) whose elements are 0 and 1 """ 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) fp = np.zeros((num_scales, num_dets), dtype=np.float32) if gt_bboxes.shape[0] == 0: if area_ranges == [(None, None)]: fp[...] = 1 else: det_areas = (det_bboxes[:, 2] - det_bboxes[:, 0] + 1) * (det_bboxes[:, 3] - det_bboxes[:, 1] + 1) for i, (min_area, max_area) in enumerate(area_ranges): fp[i, (det_areas >= min_area) & (det_areas < max_area)] = 1 return tp, fp ious = bbox_overlaps(det_bboxes, gt_bboxes - 1) gt_w = gt_bboxes[:, 2] - gt_bboxes[:, 0] + 1 gt_h = gt_bboxes[:, 3] - gt_bboxes[:, 1] + 1 iou_thrs = np.minimum((gt_w * gt_h) / ((gt_w + 10.0) * (gt_h + 10.0)), default_iou_thr) # sort all detections by scores in descending order 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) # 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, dtype=bool) else: gt_areas = gt_w * gt_h gt_area_ignore = (gt_areas < min_area) | (gt_areas >= max_area) for i in sort_inds: max_iou = -1 matched_gt = -1 # find best overlapped available gt for j in range(num_gts): # different from PASCAL VOC: allow finding other gts if the # best overlaped ones are already matched by other det bboxes if gt_covered[j]: continue elif ious[i, j] >= iou_thrs[j] and ious[i, j] > max_iou: max_iou = ious[i, j] matched_gt = j # there are 4 cases for a det bbox: # 1. this det bbox matches a gt, tp = 1, fp = 0 # 2. this det bbox matches an ignored gt, tp = 0, fp = 0 # 3. this det bbox matches no gt and within area range, tp = 0, fp = 1 # 4. this det bbox matches no gt but is beyond area range, tp = 0, fp = 0 if matched_gt >= 0: gt_covered[matched_gt] = 1 if not (gt_ignore[matched_gt] or gt_area_ignore[matched_gt]): tp[k, i] = 1 elif min_area is None: fp[k, i] = 1 else: bbox = det_bboxes[i, :4] area = (bbox[2] - bbox[0] + 1) * (bbox[3] - bbox[1] + 1) if area >= min_area and area < max_area: fp[k, i] = 1 return tp, fp