'evaluate detection proposal recall metrics
record max overlap value for each gt box; return vector of overlap values
:param roidb: used to evaluate
:param candidate_boxes: if not given, use roidb\'s non-gt boxes
:param thresholds: array-like recall threshold
:return: None
ar: average recall, recalls: vector recalls at each IoU overlap threshold
thresholds: vector of IoU overlap threshold, gt_overlaps: vector of all ground-truth overlaps'

def evaluate_recall(self, roidb, candidate_boxes=None, thresholds=None):

    area_names = ['all', '0-25', '25-50', '50-100', '100-200', '200-300', '300-inf']
    area_ranges = [[(0 ** 2), (100000.0 ** 2)], [(0 ** 2), (25 ** 2)], [(25 ** 2), (50 ** 2)], [(50 ** 2), (100 ** 2)], [(100 ** 2), (200 ** 2)], [(200 ** 2), (300 ** 2)], [(300 ** 2), (100000.0 ** 2)]]
    area_counts = []
    for (area_name, area_range) in zip(area_names[1:], area_ranges[1:]):
        area_count = 0
        for i in range(self.num_images):
            if (candidate_boxes is None):
                non_gt_inds = np.where((roidb[i]['gt_classes'] == 0))[0]
                boxes = roidb[i]['boxes'][non_gt_inds, :]
            else:
                boxes = candidate_boxes[i]
            boxes_areas = (((boxes[:, 2] - boxes[:, 0]) + 1) * ((boxes[:, 3] - boxes[:, 1]) + 1))
            valid_range_inds = np.where(((boxes_areas >= area_range[0]) & (boxes_areas < area_range[1])))[0]
            area_count += len(valid_range_inds)
        area_counts.append(area_count)
    total_counts = float(sum(area_counts))
    for (area_name, area_count) in zip(area_names[1:], area_counts):
        logger.info(('percentage    of    %s    is    %f' % (area_name, (area_count / total_counts))))
    logger.info(('average    number    of    proposal    is    %f' % (total_counts / self.num_images)))
    for (area_name, area_range) in zip(area_names, area_ranges):
        gt_overlaps = np.zeros(0)
        num_pos = 0
        for i in range(self.num_images):
            max_gt_overlaps = roidb[i]['gt_overlaps'].max(axis=1)
            gt_inds = np.where(((roidb[i]['gt_classes'] > 0) & (max_gt_overlaps == 1)))[0]
            gt_boxes = roidb[i]['boxes'][gt_inds, :]
            gt_areas = (((gt_boxes[:, 2] - gt_boxes[:, 0]) + 1) * ((gt_boxes[:, 3] - gt_boxes[:, 1]) + 1))
            valid_gt_inds = np.where(((gt_areas >= area_range[0]) & (gt_areas < area_range[1])))[0]
            gt_boxes = gt_boxes[valid_gt_inds, :]
            num_pos += len(valid_gt_inds)
            if (candidate_boxes is None):
                non_gt_inds = np.where((roidb[i]['gt_classes'] == 0))[0]
                boxes = roidb[i]['boxes'][non_gt_inds, :]
            else:
                boxes = candidate_boxes[i]
            if (boxes.shape[0] == 0):
                continue
            overlaps = bbox_overlaps(boxes.astype(np.float), gt_boxes.astype(np.float))
            _gt_overlaps = np.zeros(gt_boxes.shape[0])
            rounds = min(boxes.shape[0], gt_boxes.shape[0])
            for j in range(rounds):
                argmax_overlaps = overlaps.argmax(axis=0)
                max_overlaps = overlaps.max(axis=0)
                gt_ind = max_overlaps.argmax()
                gt_ovr = max_overlaps.max()
                assert (gt_ovr >= 0), ('%s\n%s\n%s' % (boxes, gt_boxes, overlaps))
                box_ind = argmax_overlaps[gt_ind]
                _gt_overlaps[j] = overlaps[(box_ind, gt_ind)]
                assert (_gt_overlaps[j] == gt_ovr)
                overlaps[box_ind, :] = (-1)
                overlaps[:, gt_ind] = (-1)
            gt_overlaps = np.hstack((gt_overlaps, _gt_overlaps))
        gt_overlaps = np.sort(gt_overlaps)
        if (thresholds is None):
            step = 0.05
            thresholds = np.arange(0.5, (0.95 + 1e-05), step)
        recalls = np.zeros_like(thresholds)
        for (i, t) in enumerate(thresholds):
            recalls[i] = ((gt_overlaps >= t).sum() / float(num_pos))
        ar = recalls.mean()
        print 'average    recall    for    {}:    {:.3f}'.format(area_name, ar)
        for (threshold, recall) in zip(thresholds, recalls):
            print 'recall    @{:.2f}:    {:.3f}'.format(threshold, recall)
