def evaluate_recall()

in lib/datasets/imdb_rel.py [0:0]


    def evaluate_recall(self, candidate_boxes=None, thresholds=None,
                        area='all', limit=None):
        """Evaluate detection proposal recall metrics.
                Returns:
                    results: dictionary of results with keys
                        'ar': average recall
                        'recalls': vector recalls at each IoU overlap threshold
                        'thresholds': vector of IoU overlap thresholds
                        'gt_overlaps': vector of all ground-truth overlaps
                """
        # Record max overlap value for each gt box
        # Return vector of overlap values

        assert candidate_boxes is not None

        areas = {'all': 0, 'small': 1, 'medium': 2, 'large': 3,
                 '96-128': 4, '128-256': 5, '256-512': 6, '512-inf': 7}
        area_ranges = [[0 ** 2, 1e5 ** 2],  # all
                       [0 ** 2, 32 ** 2],  # small
                       [32 ** 2, 96 ** 2],  # medium
                       [96 ** 2, 1e5 ** 2],  # large
                       [96 ** 2, 128 ** 2],  # 96-128
                       [128 ** 2, 256 ** 2],  # 128-256
                       [256 ** 2, 512 ** 2],  # 256-512
                       [512 ** 2, 1e5 ** 2],  # 512-inf
                       ]
        assert area in areas, 'unknown area range: {}'.format(area)
        area_range = area_ranges[areas[area]]
        gt_overlaps = np.zeros(0)
        gt_sbj_overlaps = np.zeros(0)
        gt_obj_overlaps = np.zeros(0)
        gt_all_inds = []
        gt_all_ovrs = []
        bx_sbj_inds = []
        bx_sbj_ovrs = []
        bx_obj_inds = []
        bx_obj_ovrs = []
        sbj_num_pos = 0
        obj_num_pos = 0
        
        for i in range(self.num_images):

            print('Calculating image %d/%d...' % (i + 1, self.num_images))

            boxes = candidate_boxes

            sbj_boxes = boxes['boxes_sbj'][i]
            obj_boxes = boxes['boxes_obj'][i]

            scores = boxes['scores'][i]
            order = scores.argsort(kind='mergesort')[::-1]
            if limit is not None:
                order = order[:limit]
            sbj_boxes = sbj_boxes[order, :]
            obj_boxes = obj_boxes[order, :]

            print('num_proposals: ', sbj_boxes.shape[0])

            # calculate overlaps for subjects
            max_gt_sbj_overlaps = self.roidb[i][
                'gt_sbj_overlaps'].toarray().max(axis=1)
            gt_sbj_inds = np.where((self.roidb[i]['gt_sbj_classes'] > 0) &
                                   (max_gt_sbj_overlaps == 1))[0]
            gt_sbj_boxes = self.roidb[i]['sbj_boxes'][gt_sbj_inds, :]
            gt_sbj_areas = self.roidb[i]['sbj_seg_areas'][gt_sbj_inds]
            valid_gt_sbj_inds = np.where((gt_sbj_areas >= area_range[0]) &
                                         (gt_sbj_areas <= area_range[1]))[0]
            gt_sbj_boxes = gt_sbj_boxes[valid_gt_sbj_inds, :]
            sbj_num_pos += len(valid_gt_sbj_inds)
            sbj_overlaps = bbox_overlaps(sbj_boxes.astype(np.float32),
                                         gt_sbj_boxes.astype(np.float32))
            # calculate overlaps for objects
            max_gt_obj_overlaps = self.roidb[i][
                'gt_obj_overlaps'].toarray().max(axis=1)
            gt_obj_inds = np.where((self.roidb[i]['gt_obj_classes'] > 0) &
                                   (max_gt_obj_overlaps == 1))[0]
            gt_obj_boxes = self.roidb[i]['obj_boxes'][gt_obj_inds, :]
            gt_obj_areas = self.roidb[i]['obj_seg_areas'][gt_obj_inds]
            valid_gt_obj_inds = np.where((gt_obj_areas >= area_range[0]) &
                                         (gt_obj_areas <= area_range[1]))[0]
            gt_obj_boxes = gt_obj_boxes[valid_gt_obj_inds, :]
            obj_num_pos += len(valid_gt_obj_inds)
            obj_overlaps = bbox_overlaps(obj_boxes.astype(np.float32),
                                         gt_obj_boxes.astype(np.float32))

            assert sbj_overlaps.shape == obj_overlaps.shape

            # add up the sbj and obj overlaps to get total overlaps
            all_overlaps = (sbj_overlaps + obj_overlaps) / 2.0

            _gt_overlaps = np.zeros((gt_sbj_boxes.shape[0]))
            _gt_sbj_overlaps = np.zeros((gt_sbj_boxes.shape[0]))
            _gt_obj_overlaps = np.zeros((gt_sbj_boxes.shape[0]))
            _gt_all_inds = []
            _gt_all_ovrs = []
            _bx_sbj_inds = []
            _bx_sbj_ovrs = []
            _bx_obj_inds = []
            _bx_obj_ovrs = []
            num_iters = min(gt_sbj_boxes.shape[0], sbj_boxes.shape[0])
            for j in range(num_iters):
                # find which proposal box maximally covers each gt box
                argmax_all_overlaps = all_overlaps.argmax(axis=0)
                # and get the iou amount of coverage for each gt pair
                max_all_overlaps = all_overlaps.max(axis=0)

                # find which gt pair is 'best' covered (i.e. 'best' = most iou)
                gt_ind = max_all_overlaps.argmax()
                gt_ovr = max_all_overlaps.max()
                assert(gt_ovr >= 0)
                # find the proposal pair that covers the best covered gt box
                pair_ind = argmax_all_overlaps[gt_ind]
                _gt_all_inds.append(gt_ind)
                _gt_all_ovrs.append(gt_ovr)
                _gt_all_inds.append(gt_ind)
                _gt_all_ovrs.append(gt_ovr)
                _bx_sbj_inds.append(pair_ind)
                _bx_sbj_ovrs.append(sbj_overlaps[pair_ind, gt_ind])
                _bx_obj_inds.append(pair_ind)
                _bx_obj_ovrs.append(obj_overlaps[pair_ind, gt_ind])
                # record the iou coverage of this gt box
                _gt_overlaps[j] = all_overlaps[pair_ind, gt_ind]
                _gt_sbj_overlaps[j] = sbj_overlaps[pair_ind, gt_ind]
                _gt_obj_overlaps[j] = obj_overlaps[pair_ind, gt_ind]
                assert(_gt_overlaps[j] == gt_ovr)
                # mark the proposal box and the gt box as used
                all_overlaps[pair_ind, :] = -1
                all_overlaps[:, gt_ind] = -1

            # append recorded iou coverage level
            gt_overlaps = np.hstack((gt_overlaps, _gt_overlaps))
            gt_sbj_overlaps = np.hstack((gt_sbj_overlaps, _gt_sbj_overlaps))
            gt_obj_overlaps = np.hstack((gt_obj_overlaps, _gt_obj_overlaps))
            gt_all_inds.append(_gt_all_inds)
            gt_all_ovrs.append(_gt_all_ovrs)
            bx_sbj_inds.append(_bx_sbj_inds)
            bx_sbj_ovrs.append(_bx_sbj_ovrs)
            bx_obj_inds.append(_bx_obj_inds)
            bx_obj_ovrs.append(_bx_obj_ovrs)

        gt_overlaps = np.sort(gt_overlaps)
        if thresholds is None:
            step = 0.05
            thresholds = np.arange(0.5, 0.95 + 1e-5, step)
        recalls = np.zeros_like(thresholds)
        # compute recall for each iou threshold
        num_pos = (sbj_num_pos + obj_num_pos) / 2
        for idx, t in enumerate(thresholds):
            inds = np.where((gt_sbj_overlaps >= t) & (gt_obj_overlaps >= t))[0]
            print('inds.size: ', inds.size)
            print('num_pos: ', num_pos)
            recalls[idx] = inds.size / float(num_pos)
        ar = np.mean(recalls)
        return {'ar': ar, 'recalls': recalls, 'thresholds': thresholds,
                'gt_all_inds': gt_all_inds, 'gt_all_ovrs': gt_all_ovrs,
                'bx_sbj_inds': bx_sbj_inds, 'bx_sbj_ovrs': bx_sbj_ovrs,
                'bx_obj_inds': bx_obj_inds, 'bx_obj_ovrs': bx_obj_ovrs}