예제 #1
0
    def get_segmentation(self,gt_segmentation,box,max_ind,imsize):
        segmentation=[];
        gts=gt_segmentation[max_ind]
        if type(gts) == list:
            assert (type(gts[0]) != dict)
            prle= mask.frPyObjects(gts,imsize[0],imsize[1])
        elif type(gts) == dict and type(gts['counts']) == list:
            prle= mask.frPyObjects([gts],imsize[0],imsize[1])
        elif type(gts) == dict and \
                     type(gts['counts'] == unicode or type(gts['counts']) == str):
            prle = [gts]
        else:
            return segmentation
        if len(prle)==1:
            prle=prle[0]
        else:
            prle= mask.merge(prle)
        grle=mask.frPyObjects([[box[0],box[1],box[2],box[1],box[2],box[3],box[0],box[3],box[0],box[1]]],imsize[0],imsize[1])
        #print grle,'----'
        pmask=mask.merge([prle,grle[0]],intersect=True)
        segmentation=pmask
#            for sm in gts:
#                poly=Polygon(zip(sm(::2),sm(1::2)))
#                bpoly=Polygon([(box[0],box[1]),(box[0],box[3]),(box[2],box[3]),(box[2],boxes[1]),(box[0],box[1])])
#                bpoly=bpoly.intersection(poly)
#                coords=array(bpoly.exterior.coords)
#                coords=coords-[box[0],box[1]]
#                segmentation.append(coords.ravel().tolist())
        return segmentation
예제 #2
0
def crop_mask(boxes,segmentations,flipped, imsize):
    assert (boxes.shape[0]==len(segmentations))
    psegmentations=[]
    for i in xrange(len(segmentations)):
        gts=segmentations[i]
        box=boxes[i,:]
        if type(gts) == list and gts:
            assert (type(gts[0]) != dict)
            prle= mask.frPyObjects(gts,imsize[1],imsize[0])
        elif type(gts) == dict and type(gts['counts']) == list:
            prle= mask.frPyObjects([gts],imsize[1],imsize[0])
        elif type(gts) == dict and \
                     type(gts['counts'] == unicode or type(gts['counts']) == str):
            prle = [gts]
        else:
            print '{} box has no segmentation'.format(i)
            psegmentations.append([])
            continue
        if len(prle)==1:
            prle=prle[0]
        else:
            prle= mask.merge(prle)
        pmask=mask.decode([prle])
        if flipped:
            pmask=pmask[:,::-1,:]
        pmask=np.copy(pmask[box[1]:box[3],box[0]:box[2],:],order='F')
        psegmentations.append(mask.encode(pmask))
    return psegmentations
예제 #3
0
    def load_dataset(self):
        dataset  = self.cfg.dataset
        dataset_phase = self.cfg.dataset_phase
        dataset_ann = self.cfg.dataset_ann

        # initialize COCO api
        annFile = '%s/annotations/%s_%s.json'%(dataset,dataset_ann,dataset_phase)
        self.coco = COCO(annFile)

        imgIds = self.coco.getImgIds()

        data = []

        # loop through each image
        for imgId in imgIds:
            item = DataItem()

            img = self.coco.loadImgs(imgId)[0]
            item.im_path = "%s/images/%s/%s"%(dataset, dataset_phase, img["file_name"])
            item.im_size = [3, img["height"], img["width"]]
            item.coco_id = imgId
            annIds = self.coco.getAnnIds(imgIds=img['id'], iscrowd=False)
            anns = self.coco.loadAnns(annIds)

            all_person_keypoints = []
            masked_persons_RLE = []
            visible_persons_RLE = []
            all_visibilities = []

            # Consider only images with people
            has_people = len(anns) > 0
            if not has_people and self.cfg.coco_only_images_with_people:
                continue

            for ann in anns: # loop through each person
                person_keypoints = []
                visibilities = []
                if ann["num_keypoints"] != 0:
                    for i in range(self.cfg.num_joints):
                        x_coord = ann["keypoints"][3 * i]
                        y_coord = ann["keypoints"][3 * i + 1]
                        visibility = ann["keypoints"][3 * i + 2]
                        visibilities.append(visibility)
                        if visibility != 0: # i.e. if labeled
                            person_keypoints.append([i, x_coord, y_coord])
                    all_person_keypoints.append(np.array(person_keypoints))
                    visible_persons_RLE.append(maskUtils.decode(self.coco.annToRLE(ann)))
                    all_visibilities.append(visibilities)
                if ann["num_keypoints"] == 0:
                    masked_persons_RLE.append(self.coco.annToRLE(ann))

            item.joints = all_person_keypoints
            item.im_neg_mask = maskUtils.merge(masked_persons_RLE)
            if self.cfg.use_gt_segm:
                item.gt_segm = np.moveaxis(np.array(visible_persons_RLE), 0, -1)
                item.visibilities = all_visibilities
            data.append(item)

        self.has_gt = self.cfg.dataset is not "image_info"
        return data
 def convert(self, mode):
     width, height = self.size
     if mode == "mask":
         rles = mask_utils.frPyObjects(
             [p.numpy() for p in self.polygons], height, width
         )
         rle = mask_utils.merge(rles)
         mask = mask_utils.decode(rle)
         mask = torch.from_numpy(mask)
         # TODO add squeeze?
         return mask
예제 #5
0
파일: common.py 프로젝트: wu-yy/tensorpack
def segmentation_to_mask(polys, height, width):
    """
    Convert polygons to binary masks.

    Args:
        polys: a list of nx2 float array

    Returns:
        a binary matrix of (height, width)
    """
    polys = [p.flatten().tolist() for p in polys]
    rles = cocomask.frPyObjects(polys, height, width)
    rle = cocomask.merge(rles)
    return cocomask.decode(rle)
예제 #6
0
        def _getIgnoreRegion(iid, coco):
            img = coco.imgs[iid]

            if not 'ignore_regions_x' in img.keys():
                return None

            if len(img['ignore_regions_x']) == 0:
                return None

            rgns_merged = []
            for region_x, region_y in zip(img['ignore_regions_x'], img['ignore_regions_y']):
                rgns = [iter(region_x), iter(region_y)]
                rgns_merged.append(list(it.next() for it in itertools.cycle(rgns)))
            rles = maskUtils.frPyObjects(rgns_merged, img['height'], img['width'])
            rle = maskUtils.merge(rles)
            return maskUtils.decode(rle)
 def annToRLE(self, ann, height, width):
     """
     Convert annotation which can be polygons, uncompressed RLE to RLE.
     :return: binary mask (numpy 2D array)
     """
     segm = ann['segmentation']
     if isinstance(segm, list):
         # polygon -- a single object might consist of multiple parts
         # we merge all parts into one mask rle code
         rles = maskUtils.frPyObjects(segm, height, width)
         rle = maskUtils.merge(rles)
     elif isinstance(segm['counts'], list):
         # uncompressed RLE
         rle = maskUtils.frPyObjects(segm, height, width)
     else:
         # rle
         rle = ann['segmentation']
     return rle
예제 #8
0
 def annToRLE(self, ann):
     """
     Convert annotation which can be polygons, uncompressed RLE to RLE.
     :return: binary mask (numpy 2D array)
     """
     t = self.imgs[ann['image_id']]
     h, w = t['height'], t['width']
     segm = ann['segmentation']
     if type(segm) == list:
         # polygon -- a single object might consist of multiple parts
         # we merge all parts into one mask rle code
         rles = maskUtils.frPyObjects(segm, h, w)
         rle = maskUtils.merge(rles)
     elif type(segm['counts']) == list:
         # uncompressed RLE
         rle = maskUtils.frPyObjects(segm, h, w)
     else:
         # rle
         rle = ann['segmentation']
     return rle
예제 #9
0
def to_mask(polys, size):
    """Convert list of polygons to full size binary mask

    Parameters
    ----------
    polys : list of numpy.ndarray
        Numpy.ndarray with shape (N, 2) where N is the number of bounding boxes.
        The second axis represents points of the polygons.
        Specifically, these are :math:`(x, y)`.
    size : tuple
        Tuple of length 2: (width, height).

    Returns
    -------
    numpy.ndarray
        Full size binary mask of shape (height, width)
    """
    try_import_pycocotools()
    import pycocotools.mask as cocomask
    width, height = size
    polys = [p.flatten().tolist() for p in polys]
    rles = cocomask.frPyObjects(polys, height, width)
    rle = cocomask.merge(rles)
    return cocomask.decode(rle)
예제 #10
0
def polys_to_mask(polygons, height, width):
    rles = cocomask.frPyObjects(polygons, height, width)
    rle = cocomask.merge(rles)
    mask = cocomask.decode(rle)
    return mask
예제 #11
0
 def polygons_to_mask(self, polygons):
     rle = mask_util.frPyObjects(polygons, self.height, self.width)
     rle = mask_util.merge(rle)
     return mask_util.decode(rle)[:, :]
        os.mkdir(os.path.join("data/gt",
                              vid))  #Mask ground truth directory by names

        for frame_id in range(len(frames_list)):
            im_gt = cv2.imread(os.path.join(train_dir, frames_list[frame_id]))
            ht, wt = im_gt.shape[:2]  #height , width

            segm = pancreas[i]
            if segm:
                rles = maskUtils.frPyObjects(segm, ht, wt)
                """
				What we have is list of polygons: [ polygon ]
				[[x1,...xn] , [y1,...yn]]
				rles: list of rle
				"""
                rle = maskUtils.merge(
                    rles)  # combined rle format for the image
                mask = maskUtils.decode(rle)  # decode the rle
                padded_mask = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2),
                                       dtype=np.uint8)
                padded_mask[1:-1, 1:-1] = mask
                im_gt = apply_mask(im_gt, mask, (0.0, 1, 0.0)).astype(
                    np.uint8)  # Test Padded Mask

            segm = cancer[i]
            if segm:
                rles = maskUtils.frPyObjects(segm, ht, wt)
                rle = maskUtils.merge(rles)
                mask = maskUtils.decode(rle)
                padded_mask = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2),
                                       dtype=np.uint8)
                padded_mask[1:-1, 1:-1] = mask
def combine_to_panoptic(proc_id, img_ids, img_id2img, inst_by_image,
                        sem_by_image, segmentations_folder, overlap_thr,
                        stuff_area_limit, categories):
    panoptic_json = []
    id_generator = IdGenerator(categories)

    for idx, img_id in enumerate(img_ids):
        img = img_id2img[img_id]

        if idx % 100 == 0:
            print('Core: {}, {} from {} images processed.'.format(
                proc_id, idx, len(img_ids)))

        pan_segm_id = np.zeros((img['height'], img['width']), dtype=np.uint32)
        used = None
        annotation = {}
        annotation['image_id'] = img_id
        annotation['file_name'] = img['file_name'].replace('.jpg', '.png')

        segments_info = []
        for ann in inst_by_image[img_id]:
            area = COCOmask.area(ann['segmentation'])
            if area == 0:
                continue
            if used is None:
                intersect = 0
                used = copy.deepcopy(ann['segmentation'])
            else:
                intersect = COCOmask.area(
                    COCOmask.merge([used, ann['segmentation']],
                                   intersect=True))
            if intersect / area > overlap_thr:
                continue
            used = COCOmask.merge([used, ann['segmentation']], intersect=False)

            mask = COCOmask.decode(ann['segmentation']) == 1
            if intersect != 0:
                mask = np.logical_and(pan_segm_id == 0, mask)
            segment_id = id_generator.get_id(ann['category_id'])
            panoptic_ann = {}
            panoptic_ann['id'] = segment_id
            panoptic_ann['category_id'] = ann['category_id']
            pan_segm_id[mask] = segment_id
            segments_info.append(panoptic_ann)

        for ann in sem_by_image[img_id]:
            mask = COCOmask.decode(ann['segmentation']) == 1
            mask_left = np.logical_and(pan_segm_id == 0, mask)
            if mask_left.sum() < stuff_area_limit:
                continue
            segment_id = id_generator.get_id(ann['category_id'])
            panoptic_ann = {}
            panoptic_ann['id'] = segment_id
            panoptic_ann['category_id'] = ann['category_id']
            pan_segm_id[mask_left] = segment_id
            segments_info.append(panoptic_ann)

        annotation['segments_info'] = segments_info
        panoptic_json.append(annotation)

        Image.fromarray(id2rgb(pan_segm_id)).save(
            os.path.join(segmentations_folder, annotation['file_name']))

    return panoptic_json
def overlapping_percentage(mask1, mask2):
    areas = min(mask.area([mask1, mask2]))
    if areas == 0:
        return 0
    percentage = mask.area(mask.merge([mask1, mask2], intersect=True)) / areas
    return percentage
예제 #15
0
def get_segmentation_area_and_bbox(segmentation, image_height, image_width):
    # Convert into rle
    rles = mask.frPyObjects(segmentation, image_height, image_width)
    rle = mask.merge(rles)

    return mask.area(rle), mask.toBbox(rle)
예제 #16
0
 def polys2mask(polygons, width, height):
     rles = mask_util.frPyObjects(polygons, height, width)
     rle = mask_util.merge(rles)
     mask = np.array(mask_util.decode(rle), dtype=np.float32)
     return mask
예제 #17
0
    def get_preprocessed_seq_data(self, raw_data, cls):
        """ Preprocess data for a single sequence for a single class ready for evaluation.
        Inputs:
             - raw_data is a dict containing the data for the sequence already read in by get_raw_seq_data().
             - cls is the class to be evaluated.
        Outputs:
             - data is a dict containing all of the information that metrics need to perform evaluation.
                It contains the following fields:
                    [num_timesteps, num_gt_ids, num_tracker_ids, num_gt_dets, num_tracker_dets] : integers.
                    [gt_ids, tracker_ids, tracker_confidences]: list (for each timestep) of 1D NDArrays (for each det).
                    [gt_dets, tracker_dets]: list (for each timestep) of lists of detections.
                    [similarity_scores]: list (for each timestep) of 2D NDArrays.
        Notes:
            Preprocessing (preproc) occurs in 3 steps.
                1) Extract only detections relevant for the class to be evaluated.
                2) Match gt dets and tracker dets. Tracker dets that are to a gt det (TPs) are marked as not to be
                    removed.
                3) Remove unmatched tracker dets if they fall within an ignore region or are too small, or if that class
                    is marked as an ignore class for that sequence.
            After the above preprocessing steps, this function also calculates the number of gt and tracker detections
                and unique track ids. It also relabels gt and tracker ids to be contiguous and checks that ids are
                unique within each timestep.
            Note that there is a special 'all' class, which evaluates all of the COCO classes together in a
                'class agnostic' fashion.
        """
        # import to reduce minimum requirements
        from pycocotools import mask as mask_utils

        # Check that input data has unique ids
        self._check_unique_ids(raw_data)

        cls_id = self.class_name_to_class_id[cls]
        ignore_class_id = cls_id + 100
        seq = raw_data['seq']

        data_keys = [
            'gt_ids', 'tracker_ids', 'gt_dets', 'tracker_dets',
            'tracker_confidences', 'similarity_scores'
        ]
        data = {key: [None] * raw_data['num_timesteps'] for key in data_keys}
        unique_gt_ids = []
        unique_tracker_ids = []
        num_gt_dets = 0
        num_tracker_dets = 0

        for t in range(raw_data['num_timesteps']):

            # Only extract relevant dets for this class
            if cls == 'all':
                gt_class_mask = raw_data['gt_classes'][t] < 100
            # For waymo, combine predictions for [car, truck, bus, motorcycle] into car, because they are all annotated
            # together as one 'vehicle' class.
            elif self.sub_benchmark == 'waymo' and cls == 'car':
                waymo_vehicle_classes = np.array([3, 4, 6, 8])
                gt_class_mask = np.isin(raw_data['gt_classes'][t],
                                        waymo_vehicle_classes)
            else:
                gt_class_mask = raw_data['gt_classes'][t] == cls_id
            gt_class_mask = gt_class_mask.astype(np.bool)
            gt_ids = raw_data['gt_ids'][t][gt_class_mask]
            if cls == 'all':
                ignore_regions_mask = raw_data['gt_classes'][t] >= 100
            else:
                ignore_regions_mask = raw_data['gt_classes'][
                    t] == ignore_class_id
                ignore_regions_mask = np.logical_or(
                    ignore_regions_mask, raw_data['gt_classes'][t] == 100)
            if self.sub_benchmark in self.box_gt_benchmarks:
                gt_dets = raw_data['gt_dets'][t][gt_class_mask]
                ignore_regions_box = raw_data['gt_dets'][t][
                    ignore_regions_mask]
                if len(ignore_regions_box) > 0:
                    ignore_regions_box[:,
                                       2] = ignore_regions_box[:,
                                                               2] - ignore_regions_box[:,
                                                                                       0]
                    ignore_regions_box[:,
                                       3] = ignore_regions_box[:,
                                                               3] - ignore_regions_box[:,
                                                                                       1]
                    ignore_regions = mask_utils.frPyObjects(
                        ignore_regions_box, self.seq_sizes[seq][0],
                        self.seq_sizes[seq][1])
                else:
                    ignore_regions = []
            else:
                gt_dets = [
                    raw_data['gt_dets'][t][ind]
                    for ind in range(len(gt_class_mask)) if gt_class_mask[ind]
                ]
                ignore_regions = [
                    raw_data['gt_dets'][t][ind]
                    for ind in range(len(ignore_regions_mask))
                    if ignore_regions_mask[ind]
                ]

            if cls == 'all':
                tracker_class_mask = np.ones_like(
                    raw_data['tracker_classes'][t])
            else:
                tracker_class_mask = np.atleast_1d(
                    raw_data['tracker_classes'][t] == cls_id)
            tracker_class_mask = tracker_class_mask.astype(np.bool)
            tracker_ids = raw_data['tracker_ids'][t][tracker_class_mask]
            tracker_dets = [
                raw_data['tracker_dets'][t][ind]
                for ind in range(len(tracker_class_mask))
                if tracker_class_mask[ind]
            ]
            tracker_confidences = raw_data['tracker_confidences'][t][
                tracker_class_mask]
            similarity_scores = raw_data['similarity_scores'][t][
                gt_class_mask, :][:, tracker_class_mask]
            tracker_classes = raw_data['tracker_classes'][t][
                tracker_class_mask]

            # Only do preproc if there are ignore regions defined to remove
            if tracker_ids.shape[0] > 0:

                # Match tracker and gt dets (with hungarian algorithm)
                unmatched_indices = np.arange(tracker_ids.shape[0])
                if gt_ids.shape[0] > 0 and tracker_ids.shape[0] > 0:
                    matching_scores = similarity_scores.copy()
                    matching_scores[matching_scores < 0.5 -
                                    np.finfo('float').eps] = 0
                    match_rows, match_cols = linear_sum_assignment(
                        -matching_scores)
                    actually_matched_mask = matching_scores[
                        match_rows, match_cols] > 0 + np.finfo('float').eps
                    # match_rows = match_rows[actually_matched_mask]
                    match_cols = match_cols[actually_matched_mask]
                    unmatched_indices = np.delete(unmatched_indices,
                                                  match_cols,
                                                  axis=0)

                # For unmatched tracker dets remove those that are greater than 50% within an ignore region.
                # unmatched_tracker_dets = tracker_dets[unmatched_indices, :]
                # crowd_ignore_regions = raw_data['gt_ignore_regions'][t]
                # intersection_with_ignore_region = self. \
                #     _calculate_box_ious(unmatched_tracker_dets, crowd_ignore_regions, box_format='x0y0x1y1',
                #                         do_ioa=True)

                if cls_id in self.seq_ignore_class_ids[seq]:
                    # Remove unmatched detections for classes that are marked as 'ignore' for the whole sequence.
                    to_remove_tracker = unmatched_indices
                else:
                    unmatched_tracker_dets = [
                        tracker_dets[i] for i in range(len(tracker_dets))
                        if i in unmatched_indices
                    ]

                    # For unmatched tracker dets remove those that are too small.
                    tracker_boxes_t = mask_utils.toBbox(unmatched_tracker_dets)
                    unmatched_widths = tracker_boxes_t[:, 2]
                    unmatched_heights = tracker_boxes_t[:, 3]
                    unmatched_size = np.maximum(unmatched_heights,
                                                unmatched_widths)
                    min_size = np.min(self.seq_sizes[seq]) / 8
                    is_too_small = unmatched_size <= min_size + np.finfo(
                        'float').eps

                    # For unmatched tracker dets remove those that are greater than 50% within an ignore region.
                    if ignore_regions:
                        ignore_region_merged = ignore_regions[0]
                        for mask in ignore_regions[1:]:
                            ignore_region_merged = mask_utils.merge(
                                [ignore_region_merged, mask], intersect=False)
                        intersection_with_ignore_region = self. \
                            _calculate_mask_ious(unmatched_tracker_dets, [ignore_region_merged], is_encoded=True, do_ioa=True)
                        is_within_ignore_region = np.any(
                            intersection_with_ignore_region >
                            0.5 + np.finfo('float').eps,
                            axis=1)
                        to_remove_tracker = unmatched_indices[np.logical_or(
                            is_too_small, is_within_ignore_region)]
                    else:
                        to_remove_tracker = unmatched_indices[is_too_small]

                # For the special 'all' class, you need to remove unmatched detections from all ignore classes and
                #   non-evaluated classes.
                if cls == 'all':
                    unmatched_tracker_classes = [
                        tracker_classes[i] for i in range(len(tracker_classes))
                        if i in unmatched_indices
                    ]
                    is_ignore_class = np.isin(unmatched_tracker_classes,
                                              self.seq_ignore_class_ids[seq])
                    is_not_evaled_class = np.logical_not(
                        np.isin(unmatched_tracker_classes,
                                self.valid_class_ids))
                    to_remove_all = unmatched_indices[np.logical_or(
                        is_ignore_class, is_not_evaled_class)]
                    to_remove_tracker = np.concatenate(
                        [to_remove_tracker, to_remove_all], axis=0)
            else:
                to_remove_tracker = np.array([], dtype=np.int)

            # remove all unwanted tracker detections
            data['tracker_ids'][t] = np.delete(tracker_ids,
                                               to_remove_tracker,
                                               axis=0)
            data['tracker_dets'][t] = np.delete(tracker_dets,
                                                to_remove_tracker,
                                                axis=0)
            data['tracker_confidences'][t] = np.delete(tracker_confidences,
                                                       to_remove_tracker,
                                                       axis=0)
            similarity_scores = np.delete(similarity_scores,
                                          to_remove_tracker,
                                          axis=1)

            # keep all ground truth detections
            data['gt_ids'][t] = gt_ids
            data['gt_dets'][t] = gt_dets
            data['similarity_scores'][t] = similarity_scores

            unique_gt_ids += list(np.unique(data['gt_ids'][t]))
            unique_tracker_ids += list(np.unique(data['tracker_ids'][t]))
            num_tracker_dets += len(data['tracker_ids'][t])
            num_gt_dets += len(data['gt_ids'][t])

        # Re-label IDs such that there are no empty IDs
        if len(unique_gt_ids) > 0:
            unique_gt_ids = np.unique(unique_gt_ids)
            gt_id_map = np.nan * np.ones((np.max(unique_gt_ids) + 1))
            gt_id_map[unique_gt_ids] = np.arange(len(unique_gt_ids))
            for t in range(raw_data['num_timesteps']):
                if len(data['gt_ids'][t]) > 0:
                    data['gt_ids'][t] = gt_id_map[data['gt_ids'][t]].astype(
                        np.int)
        if len(unique_tracker_ids) > 0:
            unique_tracker_ids = np.unique(unique_tracker_ids)
            tracker_id_map = np.nan * np.ones((np.max(unique_tracker_ids) + 1))
            tracker_id_map[unique_tracker_ids] = np.arange(
                len(unique_tracker_ids))
            for t in range(raw_data['num_timesteps']):
                if len(data['tracker_ids'][t]) > 0:
                    data['tracker_ids'][t] = tracker_id_map[data['tracker_ids']
                                                            [t]].astype(np.int)

        # Record overview statistics.
        data['num_tracker_dets'] = num_tracker_dets
        data['num_gt_dets'] = num_gt_dets
        data['num_tracker_ids'] = len(unique_tracker_ids)
        data['num_gt_ids'] = len(unique_gt_ids)
        data['num_timesteps'] = raw_data['num_timesteps']
        data['seq'] = raw_data['seq']
        data['frame_size'] = raw_data['frame_size']

        # Ensure that ids are unique per timestep.
        self._check_unique_ids(data, after_preproc=True)

        return data
예제 #18
0
    def _load_raw_file(self, tracker, seq, is_gt):
        """Load a file (gt or tracker) in the unified RobMOTS format.

        If is_gt, this returns a dict which contains the fields:
        [gt_ids, gt_classes] : list (for each timestep) of 1D NDArrays (for each det).
        [gt_dets, gt_crowd_ignore_regions]: list (for each timestep) of lists of detections.

        if not is_gt, this returns a dict which contains the fields:
        [tracker_ids, tracker_classes, tracker_confidences] : list (for each timestep) of 1D NDArrays (for each det).
        [tracker_dets]: list (for each timestep) of lists of detections.
        """
        # import to reduce minimum requirements
        from pycocotools import mask as mask_utils

        # File location
        if self.data_is_zipped:
            if is_gt:
                zip_file = os.path.join(self.gt_fol, self.split,
                                        self.sub_benchmark, 'data.zip')
            else:
                zip_file = os.path.join(self.tracker_fol, tracker, 'data.zip')
            file = seq + '.txt'
        else:
            zip_file = None
            if is_gt:
                file = os.path.join(self.gt_fol, self.split,
                                    self.sub_benchmark, 'data', seq + '.txt')
            else:
                file = os.path.join(self.tracker_fol, tracker,
                                    self.tracker_sub_fol, self.sub_benchmark,
                                    seq + '.txt')

        # Load raw data from text file
        read_data, ignore_data = self._load_simple_text_file(
            file,
            is_zipped=self.data_is_zipped,
            zip_file=zip_file,
            force_delimiters=' ')

        # Convert data to required format
        num_timesteps = self.seq_lengths[seq]
        data_keys = ['ids', 'classes', 'dets']
        if not is_gt:
            data_keys += ['tracker_confidences']
        raw_data = {key: [None] * num_timesteps for key in data_keys}
        for t in range(num_timesteps):
            time_key = str(t)
            # list to collect all masks of a timestep to check for overlapping areas (for segmentation datasets)
            all_valid_masks = []
            if time_key in read_data.keys():
                try:
                    raw_data['ids'][t] = np.atleast_1d(
                        [det[1] for det in read_data[time_key]]).astype(int)
                    raw_data['classes'][t] = np.atleast_1d(
                        [det[2] for det in read_data[time_key]]).astype(int)
                    if (not is_gt) or (self.sub_benchmark
                                       not in self.box_gt_benchmarks):
                        raw_data['dets'][t] = [{
                            'size': [int(region[4]),
                                     int(region[5])],
                            'counts':
                            region[6].encode(encoding='UTF-8')
                        } for region in read_data[time_key]]
                        all_valid_masks += [
                            mask for mask, cls in zip(raw_data['dets'][t],
                                                      raw_data['classes'][t])
                            if cls < 100
                        ]
                    else:
                        raw_data['dets'][t] = np.atleast_2d([
                            det[4:8] for det in read_data[time_key]
                        ]).astype(float)

                    if not is_gt:
                        raw_data['tracker_confidences'][t] = np.atleast_1d([
                            det[3] for det in read_data[time_key]
                        ]).astype(float)
                except IndexError:
                    self._raise_index_error(is_gt, self.sub_benchmark, seq)
                except ValueError:
                    self._raise_value_error(is_gt, self.sub_benchmark, seq)
            # no detection in this timestep
            else:
                if (not is_gt) or (self.sub_benchmark
                                   not in self.box_gt_benchmarks):
                    raw_data['dets'][t] = []
                else:
                    raw_data['dets'][t] = np.empty((0, 4)).astype(float)
                raw_data['ids'][t] = np.empty(0).astype(int)
                raw_data['classes'][t] = np.empty(0).astype(int)
                if not is_gt:
                    raw_data['tracker_confidences'][t] = np.empty(0).astype(
                        float)

            # check for overlapping masks
            if all_valid_masks:
                masks_merged = all_valid_masks[0]
                for mask in all_valid_masks[1:]:
                    if mask_utils.area(
                            mask_utils.merge([masks_merged, mask],
                                             intersect=True)) != 0.0:
                        err = 'Overlapping masks in frame %d' % t
                        raise TrackEvalException(err)
                    masks_merged = mask_utils.merge([masks_merged, mask],
                                                    intersect=False)

        if is_gt:
            key_map = {
                'ids': 'gt_ids',
                'classes': 'gt_classes',
                'dets': 'gt_dets'
            }
        else:
            key_map = {
                'ids': 'tracker_ids',
                'classes': 'tracker_classes',
                'dets': 'tracker_dets'
            }

        for k, v in key_map.items():
            raw_data[v] = raw_data.pop(k)

        raw_data['num_timesteps'] = num_timesteps
        raw_data['frame_size'] = self.seq_sizes[seq]
        raw_data['seq'] = seq
        return raw_data
예제 #19
0
    def _load_raw_file(self, tracker, seq, is_gt):
        """Load a file (gt or tracker) in the KITTI MOTS format

        If is_gt, this returns a dict which contains the fields:
        [gt_ids, gt_classes] : list (for each timestep) of 1D NDArrays (for each det).
        [gt_dets]: list (for each timestep) of lists of detections.
        [gt_ignore_region]: list (for each timestep) of masks for the ignore regions

        if not is_gt, this returns a dict which contains the fields:
        [tracker_ids, tracker_classes] : list (for each timestep) of 1D NDArrays (for each det).
        [tracker_dets]: list (for each timestep) of lists of detections.
        """
        # File location
        if self.data_is_zipped:
            if is_gt:
                zip_file = os.path.join(self.gt_fol, 'data.zip')
            else:
                zip_file = os.path.join(self.tracker_fol, tracker,
                                        self.tracker_sub_fol + '.zip')
            file = seq + '.txt'
        else:
            zip_file = None
            if is_gt:
                file = self.config["GT_LOC_FORMAT"].format(
                    gt_folder=self.gt_fol, seq=seq)
            else:
                file = os.path.join(self.tracker_fol, tracker,
                                    self.tracker_sub_fol, seq + '.txt')

        # Ignore regions
        if is_gt:
            crowd_ignore_filter = {2: ['10']}
        else:
            crowd_ignore_filter = None

        # Load raw data from text file
        read_data, ignore_data = self._load_simple_text_file(
            file,
            crowd_ignore_filter=crowd_ignore_filter,
            is_zipped=self.data_is_zipped,
            zip_file=zip_file,
            force_delimiters=' ')

        # Convert data to required format
        num_timesteps = self.seq_lengths[seq]
        data_keys = ['ids', 'classes', 'dets']
        if is_gt:
            data_keys += ['gt_ignore_region']
        raw_data = {key: [None] * num_timesteps for key in data_keys}
        for t in range(num_timesteps):
            time_key = str(t)
            # list to collect all masks of a timestep to check for overlapping areas
            all_masks = []
            if time_key in read_data.keys():
                try:
                    raw_data['dets'][t] = [{
                        'size': [int(region[3]),
                                 int(region[4])],
                        'counts':
                        region[5].encode(encoding='UTF-8')
                    } for region in read_data[time_key]]
                    raw_data['ids'][t] = np.atleast_1d([
                        region[1] for region in read_data[time_key]
                    ]).astype(int)
                    raw_data['classes'][t] = np.atleast_1d([
                        region[2] for region in read_data[time_key]
                    ]).astype(int)
                    all_masks += raw_data['dets'][t]
                except IndexError:
                    self._raise_index_error(is_gt, tracker, seq)
                except ValueError:
                    self._raise_value_error(is_gt, tracker, seq)
            else:
                raw_data['dets'][t] = []
                raw_data['ids'][t] = np.empty(0).astype(int)
                raw_data['classes'][t] = np.empty(0).astype(int)
            if is_gt:
                if time_key in ignore_data.keys():
                    try:
                        time_ignore = [{
                            'size': [int(region[3]),
                                     int(region[4])],
                            'counts':
                            region[5].encode(encoding='UTF-8')
                        } for region in ignore_data[time_key]]
                        raw_data['gt_ignore_region'][t] = mask_utils.merge(
                            [mask for mask in time_ignore], intersect=False)
                        all_masks += [raw_data['gt_ignore_region'][t]]
                    except IndexError:
                        self._raise_index_error(is_gt, tracker, seq)
                    except ValueError:
                        self._raise_value_error(is_gt, tracker, seq)
                else:
                    raw_data['gt_ignore_region'][t] = mask_utils.merge(
                        [], intersect=False)
            # check for overlapping masks
            if all_masks:
                masks_merged = all_masks[0]
                for mask in all_masks[1:]:
                    assert mask_utils.area(mask_utils.merge([masks_merged, mask], intersect=True)) == 0.0, \
                        "Objects with overlapping masks in frame " + str(t)
                    masks_merged = mask_utils.merge([masks_merged, mask],
                                                    intersect=False)

        if is_gt:
            key_map = {
                'ids': 'gt_ids',
                'classes': 'gt_classes',
                'dets': 'gt_dets'
            }
        else:
            key_map = {
                'ids': 'tracker_ids',
                'classes': 'tracker_classes',
                'dets': 'tracker_dets'
            }
        for k, v in key_map.items():
            raw_data[v] = raw_data.pop(k)
        raw_data["num_timesteps"] = num_timesteps
        raw_data['seq'] = seq
        return raw_data
예제 #20
0
def _rle_satellite_match(particles, satellites, match_thresh=0.5):
    r"""
    Match satellites in an image to their corresponding particles.

    Convert particle and satellite masks to RLE format. For each satellite,
    compute the intersection (fraction of satellite mask overlapping with particle mask)
     score with all particle masks. If the maximum intersection is above *match_thresh*,
     the satellite is considered to match with that particle. Otherwise, the satellite
     is considered unmatched.


    Parameters
    -----------
    particles, satellites: InstanceSet or Instances object
        Contains the masks for the powder particles and satellites, respectively.
    match_thresh: float
        Float between 0 and 1. If intersection score for potential matches is not
        above this threshold, then the satellite will not match with a particle.
    Returns
    ----------
    results: dict
        Dictionary containing the results in the following format:
        {'satellite_matches': n_match x 2 array. satellite_matches[i]
                              contains [satellite_idx, particle_idx],
                              the integer indices of the satellite,
                              and particle that the satellite matches with,
                              respectively.
         'satellites_unmatched': n_satellite_unmatched element array containing
                                the indices of unmatched satellites.
         'particles_unmatched': n_particles_unmatched element array containing
                                the indices of unmatched particles.
         'intersection_scores': n_match element array of intersection scores
                                for each of the matches in satellite_matches.
         'match_pairs': dictionary. Keys of the dictionary are integer indices of
                        particles that matched with satellites. Values of the
                        dictionary are lists of integer indices of satellites that
                        the particle matched with. Note that a particle can match
                        with multiple satellites, but satellites can only match
                        with a single particle.
         }

    """

    particles = masks_to_rle(particles)
    satellites = masks_to_rle(satellites)

    satellite_matches = []
    intersection_scores = []

    particles_matched_bool = np.zeros(len(particles), dtype=np.bool)
    satellites_unmatched = []

    for satellite_idx, satellite_mask in enumerate(satellites):

        intersects = RLE.area([RLE.merge([satellite_mask, pmask], intersect=True) for pmask in particles]) \
            / RLE.area(satellite_mask)

        iscore_amax = np.argmax(intersects)
        iscore_max = intersects[iscore_amax]

        if iscore_max > match_thresh:
            satellite_matches.append([satellite_idx, iscore_amax])
            particles_matched_bool[iscore_amax] = True
            intersection_scores.append(iscore_max)

        else:
            satellites_unmatched.append(satellite_idx)

    particles_unmatched = np.array(
        [i for i, matched in enumerate(particles_matched_bool) if not matched],
        np.int)
    satellite_matches = np.asarray(satellite_matches, np.int)
    satellites_unmatched = np.asarray(satellites_unmatched, np.int)
    intersection_scores = np.asarray(intersection_scores)

    match_pairs = {x: [] for x in np.unique(satellite_matches[:, 1])}
    for match in satellite_matches:
        match_pairs[match[1]].append(match[0])

    results = {
        'satellite_matches': satellite_matches,
        'satellites_unmatched': satellites_unmatched,
        'particles_unmatched': particles_unmatched,
        'intersection_scores': intersection_scores,
        'match_pairs': match_pairs
    }

    return results
def ann_to_mask(segm, h, w):
    rles = maskUtils.frPyObjects(segm, h, w)
    rle = maskUtils.merge(rles)
    m = maskUtils.decode(rle)
    return m
예제 #22
0
    def _load_raw_file(self, tracker, seq, is_gt):
        """Load a file (gt or tracker) in the MOTS Challenge format

        If is_gt, this returns a dict which contains the fields:
        [gt_ids, gt_classes] : list (for each timestep) of 1D NDArrays (for each det).
        [gt_dets]: list (for each timestep) of lists of detections.
        [gt_ignore_region]: list (for each timestep) of masks for the ignore regions

        if not is_gt, this returns a dict which contains the fields:
        [tracker_ids, tracker_classes] : list (for each timestep) of 1D NDArrays (for each det).
        [tracker_dets]: list (for each timestep) of lists of detections.
        """

        # Only loaded when run to reduce minimum requirements
        from pycocotools import mask as mask_utils

        # File location
        if self.data_is_zipped:
            if is_gt:
                zip_file = os.path.join(self.gt_fol, 'data.zip')
            else:
                zip_file = os.path.join(self.tracker_fol, tracker,
                                        self.tracker_sub_fol + '.zip')
            file = seq + '.txt'
        else:
            zip_file = None
            if is_gt:
                file = self.config["GT_LOC_FORMAT"].format(
                    gt_folder=self.gt_fol, seq=seq)
            else:
                file = os.path.join(self.tracker_fol, tracker,
                                    self.tracker_sub_fol, seq + '.txt')

        # Ignore regions
        if is_gt:
            crowd_ignore_filter = {2: ['10']}
        else:
            crowd_ignore_filter = None

        # Load raw data from text file
        read_data, ignore_data = self._load_simple_text_file(
            file,
            crowd_ignore_filter=crowd_ignore_filter,
            is_zipped=self.data_is_zipped,
            zip_file=zip_file,
            force_delimiters=' ')

        # Convert data to required format
        num_timesteps = self.seq_lengths[seq]
        data_keys = ['ids', 'classes', 'dets']
        if is_gt:
            data_keys += ['gt_ignore_region']
        raw_data = {key: [None] * num_timesteps for key in data_keys}

        # Check for any extra time keys
        extra_time_keys = [
            x for x in read_data.keys()
            if x not in [str(t + 1) for t in range(num_timesteps)]
        ]
        if len(extra_time_keys) > 0:
            if is_gt:
                text = 'Ground-truth'
            else:
                text = 'Tracking'
            raise TrackEvalException(
                text +
                ' data contains the following invalid timesteps in seq %s: ' %
                seq + ', '.join([str(x) + ', ' for x in extra_time_keys]))

        for t in range(num_timesteps):
            time_key = str(t + 1)
            # list to collect all masks of a timestep to check for overlapping areas
            all_masks = []
            if time_key in read_data.keys():
                try:
                    raw_data['dets'][t] = [{
                        'size': [int(region[3]),
                                 int(region[4])],
                        'counts':
                        region[5].encode(encoding='UTF-8')
                    } for region in read_data[time_key]]
                    raw_data['ids'][t] = np.atleast_1d([
                        region[1] for region in read_data[time_key]
                    ]).astype(int)
                    raw_data['classes'][t] = np.atleast_1d([
                        region[2] for region in read_data[time_key]
                    ]).astype(int)
                    all_masks += raw_data['dets'][t]
                except IndexError:
                    self._raise_index_error(is_gt, tracker, seq)
                except ValueError:
                    self._raise_value_error(is_gt, tracker, seq)
            else:
                raw_data['dets'][t] = []
                raw_data['ids'][t] = np.empty(0).astype(int)
                raw_data['classes'][t] = np.empty(0).astype(int)
            if is_gt:
                if time_key in ignore_data.keys():
                    try:
                        time_ignore = [{
                            'size': [int(region[3]),
                                     int(region[4])],
                            'counts':
                            region[5].encode(encoding='UTF-8')
                        } for region in ignore_data[time_key]]
                        raw_data['gt_ignore_region'][t] = mask_utils.merge(
                            [mask for mask in time_ignore], intersect=False)
                        all_masks += [raw_data['gt_ignore_region'][t]]
                    except IndexError:
                        self._raise_index_error(is_gt, tracker, seq)
                    except ValueError:
                        self._raise_value_error(is_gt, tracker, seq)
                else:
                    raw_data['gt_ignore_region'][t] = mask_utils.merge(
                        [], intersect=False)

            # check for overlapping masks
            if all_masks:
                masks_merged = all_masks[0]
                for mask in all_masks[1:]:
                    if mask_utils.area(
                            mask_utils.merge([masks_merged, mask],
                                             intersect=True)) != 0.0:
                        raise TrackEvalException(
                            'Tracker has overlapping masks. Tracker: ' +
                            tracker + ' Seq: ' + seq + ' Timestep: ' + str(t))
                    masks_merged = mask_utils.merge([masks_merged, mask],
                                                    intersect=False)

        if is_gt:
            key_map = {
                'ids': 'gt_ids',
                'classes': 'gt_classes',
                'dets': 'gt_dets'
            }
        else:
            key_map = {
                'ids': 'tracker_ids',
                'classes': 'tracker_classes',
                'dets': 'tracker_dets'
            }
        for k, v in key_map.items():
            raw_data[v] = raw_data.pop(k)
        raw_data['num_timesteps'] = num_timesteps
        raw_data['seq'] = seq
        return raw_data
예제 #23
0
파일: dataset.py 프로젝트: unerue/boda
    def __getitem__(self, index):
        """
        Returns:
            image (ndarray[C, H, W])
            boxes [xyxy]
        """
        image_id = self.image_ids[index]
        targets = self.coco.get_annots(image_id)

        image = self.coco.get_file_name(image_id)
        # image = Image.open(os.path.join(self.image_dir, image)).convert('RGB')
        image = image.replace('\\', '/')
        # print(os.path.join(self.image_dir, image))
        image = cv2.imread(os.path.join(self.image_dir, image),
                           cv2.COLOR_BGR2RGB)
        # print(image)
        h, w, _ = image.shape

        boxes = []
        labels = []
        masks = []
        crowds = []
        areas = []

        for target in targets:
            boxes.append(target['bbox'])
            # labels.append(target['category_id'])
            # print(target['category_id'])
            labels.append(self.label_map.get(target['category_id']) - 1)
            crowds.append(target['iscrowd'])
            areas.append(target['area'])

            if self.use_mask:
                if target['segmentation'] is not None:
                    segment = target['segmentation']
                    if isinstance(segment, list):
                        rles = mask.frPyObjects(segment, h, w)
                        rle = mask.merge(rles)
                    elif isinstance(segment['counts'], list):
                        rle = mask.frPyObjects(segment, h, w)
                    else:
                        rle = segment

                    masks.append(mask.decode(rle))
        masks = np.vstack(masks).reshape(-1, h, w)

        boxes = np.asarray(boxes, dtype=np.float32)
        # xywh to xyxy
        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]
        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]

        labels = np.asarray(labels, dtype=np.int64)
        crowds = np.asarray(crowds, dtype=np.int64)

        # masks = np.vstack(masks).reshape(-1, h, w)
        # image = image.transpose((2, 0, 1))

        if self.use_mask:
            targets = {
                'boxes': boxes,
                'masks': masks,
                'labels': labels,
                'crowds': crowds,
            }
        else:
            targets = {
                'boxes': boxes,
                'labels': labels,
                'crowds': crowds,
            }

        if self.transforms is not None:
            image, targets = self.transforms(image, targets)

        # image = np.array(image).transpose(2, 0, 1)
        # image = image / 255.0

        # image = torch.as_tensor(image, dtype=torch.float32)
        if self.mode == 'train':
            return image, targets
        else:
            return image, targets, h, w
예제 #24
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("infile", type=str, help="Input predictions")
    parser.add_argument("outfile", type=str, help="Path to write predictions")
    args = parser.parse_args()
    params = vars(args)

    image_index = get_image_id_info_index()

    in_predictions = json.load(open(params['infile']))
    out_predictions = []

    # Since each image has multiple predictions, but we always predict the same saliency mask, group them first
    image_id_to_predictions = defaultdict(list)
    for inpred in in_predictions:
        image_id = inpred['image_id']
        image_id_to_predictions[image_id].append(inpred)

    # --- Load Location of Text images----------------------------------------------------------------------------------
    image_id_to_textdets = dict()
    image_ids = image_id_to_predictions.keys()

    print 'Loading text regions in images...'
    for image_id in tqdm(image_ids):
        # fold = image_index[image_id]['fold']
        fold = 'test2017'
        text_anno_path = osp.join(Paths.ANNO_EXTRA_ROOT,
                                  '{}/{}.json'.format(fold, image_id))
        g_anno = json.load(open(text_anno_path))

        text_dets = []
        if 'fullTextAnnotation' in g_anno:
            # Aggregate all text blocks in this image
            for page in g_anno['fullTextAnnotation']['pages']:
                for block in page['blocks']:
                    vrts = bb_to_verts(block['boundingBox'])
                    text_dets.append(vrts)
        image_id_to_textdets[image_id] = text_dets

    # --- Process ------------------------------------------------------------------------------------------------------
    print 'Processing predictions...'
    for image_id, inpreds in tqdm(image_id_to_predictions.items()):
        image_path = image_index[image_id]['image_path']
        h, w = get_image_size(image_path)

        # What's the RLE for the text boxes in this image?
        text_dets = image_id_to_textdets[image_id]
        if len(text_dets) > 0:
            verts = None
            # Get a list of (x_i, y_i) indicating vertices of all boxes in the image
            for _det in text_dets:
                # Convert from 10x1 vector to 5x2 matrix
                det = _det.reshape([5, 2])
                if verts is None:
                    verts = det
                else:
                    verts = np.concatenate([verts, det])

            # Find the convex hull of these points
            hull = ConvexHull(verts)
            hull_x, hull_y = verts[hull.vertices, 0], verts[hull.vertices, 1]
            hull_vrts = np.concatenate([hull_x[:, None], hull_y[:, None]],
                                       axis=1)  # N x 2 matrix
            hull_vrts = np.concatenate([hull_vrts, hull_vrts[0, None]
                                        ])  # Append first point to the end
            hull_vrts = np.ndarray.flatten(hull_vrts)

            # Convert to rle
            rles = mask_utils.frPyObjects([
                hull_vrts.tolist(),
            ], h, w)
            rle = mask_utils.merge(rles)

            # Perform CRF smoothing
            image_path = image_index[image_id]['image_path']
            im = Image.open(image_path)
            try:
                rle = refine_rle(im,
                                 rle,
                                 inference_steps=40,
                                 relax_precision=True)
            except ValueError:
                pass
            del im
        else:
            # Predict the entire image
            bimask = np.ones((h, w), order='F', dtype='uint8')
            rle = mask_utils.encode(bimask)
            del bimask

        for inpred in inpreds:
            image_id = inpred['image_id']
            attr_id = inpred['attr_id']
            score = inpred['score']

            out_predictions.append({
                'image_id': image_id,
                'attr_id': attr_id,
                'segmentation': rle,
                'score': score
            })

    print
    out_path = params['outfile']
    print 'Writing {} predictions to {}'.format(len(out_predictions), out_path)
    json.dump(out_predictions, open(out_path, 'wb'), indent=2)
예제 #25
0
def crop_covered_segments(segments,
                          width,
                          height,
                          iou_threshold=0.0,
                          ratio_tolerance=0.001,
                          area_threshold=1,
                          return_masks=False):
    """
    Find all segments occluded by others and crop them to the visible part only.
    Input segments are expected to be sorted from background to foreground.

    Args:
        segments: 1d list of segment RLEs (in COCO format)
        width: width of the image
        height: height of the image
        iou_threshold: IoU threshold for objects to be counted as intersected
            By default is set to 0 to process any intersected objects
        ratio_tolerance: an IoU "handicap" value for a situation
            when an object is (almost) fully covered by another one and we
            don't want make a "hole" in the background object
        area_threshold: minimal area of included segments

    Returns:
        A list of input segments' parts (in the same order as input):
            [
                [[x1,y1, x2,y2 ...], ...], # input segment #0 parts
                mask1, # input segment #1 mask (if source segment is mask)
                [], # when source segment is too small
                ...
            ]
    """
    from pycocotools import mask as mask_utils

    segments = [[s] for s in segments]
    input_rles = [mask_utils.frPyObjects(s, height, width) for s in segments]

    for i, rle_bottom in enumerate(input_rles):
        area_bottom = sum(mask_utils.area(rle_bottom))
        if area_bottom < area_threshold:
            segments[i] = [] if not return_masks else None
            continue

        rles_top = []
        for j in range(i + 1, len(input_rles)):
            rle_top = input_rles[j]
            iou = sum(mask_utils.iou(rle_bottom, rle_top, [0, 0]))[0]

            if iou <= iou_threshold:
                continue

            area_top = sum(mask_utils.area(rle_top))
            area_ratio = area_top / area_bottom

            # If a segment is fully inside another one, skip this segment
            if abs(area_ratio - iou) < ratio_tolerance:
                continue

            # Check if the bottom segment is fully covered by the top one.
            # There is a mistake in the annotation, keep the background one
            if abs(1 / area_ratio - iou) < ratio_tolerance:
                rles_top = []
                break

            rles_top += rle_top

        if not rles_top and not isinstance(segments[i][0], dict) \
                and not return_masks:
            continue

        rle_bottom = rle_bottom[0]
        bottom_mask = mask_utils.decode(rle_bottom).astype(np.uint8)

        if rles_top:
            rle_top = mask_utils.merge(rles_top)
            top_mask = mask_utils.decode(rle_top).astype(np.uint8)

            bottom_mask -= top_mask
            bottom_mask[bottom_mask != 1] = 0

        if not return_masks and not isinstance(segments[i][0], dict):
            segments[i] = mask_to_polygons(bottom_mask,
                                           area_threshold=area_threshold)
        else:
            segments[i] = bottom_mask

    return segments
예제 #26
0
파일: eval.py 프로젝트: shiyoi/PointTrack
def compute_MOTS_metrics_per_sequence(seq_name, gt_seq, results_seq, max_frames, class_id,
                                      ignore_class, overlap_function):
    results_obj = MOTSResults()
    results_obj.total_num_frames = max_frames + 1
    seq_trajectories = defaultdict(list)

    # To count number of track ids
    gt_track_ids = set()
    tr_track_ids = set()

    # Statistics over the current sequence
    seqtp = 0
    seqfn = 0
    seqfp = 0
    seqitr = 0

    n_gts = 0
    n_trs = 0

    # Iterate over frames in this sequence
    for f in range(max_frames + 1):
        g = []
        dc = []
        t = []

        if f in gt_seq:
            for obj in gt_seq[f]:
                if obj.class_id == ignore_class:
                    dc.append(obj)
                elif obj.class_id == class_id:
                    g.append(obj)
                    gt_track_ids.add(obj.track_id)
        if f in results_seq:
            for obj in results_seq[f]:
                if obj.class_id == class_id:
                    t.append(obj)
                    tr_track_ids.add(obj.track_id)

        # Handle ignore regions as one large ignore region
        dc = SegmentedObject(mask=rletools.merge([d.mask for d in dc], intersect=False),
                             class_id=ignore_class, track_id=ignore_class)

        tracks_valid = [False for _ in range(len(t))]

        # counting total number of ground truth and tracker objects
        results_obj.n_gt += len(g)
        results_obj.n_tr += len(t)

        n_gts += len(g)
        n_trs += len(t)

        # tmp variables for sanity checks and MODSP computation
        tmptp = 0
        tmpfp = 0
        tmpfn = 0
        tmpc = 0  # this will sum up the overlaps for all true positives
        tmpcs = [0] * len(g)  # this will save the overlaps for all true positives
        # the reason is that some true positives might be ignored
        # later such that the corrsponding overlaps can
        # be subtracted from tmpc for MODSP computation

        # To associate, simply take for each ground truth the (unique!) detection with IoU>0.5 if it exists

        # all ground truth trajectories are initially not associated
        # extend groundtruth trajectories lists (merge lists)
        for gg in g:
            seq_trajectories[gg.track_id].append(-1)
        num_associations = 0
        for row, gg in enumerate(g):
            for col, tt in enumerate(t):
                c = overlap_function(gg, tt)
                if c > 0.5:
                    tracks_valid[col] = True
                    results_obj.total_cost += c
                    tmpc += c
                    tmpcs[row] = c
                    seq_trajectories[g[row].track_id][-1] = t[col].track_id

                    # true positives are only valid associations
                    results_obj.tp += 1
                    tmptp += 1

                    num_associations += 1

        # associate tracker and DontCare areas
        # ignore tracker in neighboring classes
        nignoredtracker = 0  # number of ignored tracker detections

        for i, tt in enumerate(t):
            overlap = overlap_function(tt, dc, "a")
            if overlap > 0.5 and not tracks_valid[i]:
                nignoredtracker += 1

        # count the number of ignored tracker objects
        results_obj.n_itr += nignoredtracker

        # false negatives = non-associated gt instances
        #
        tmpfn += len(g) - num_associations
        results_obj.fn += len(g) - num_associations

        # false positives = tracker instances - associated tracker instances
        # mismatches (mme_t)
        tmpfp += len(t) - tmptp - nignoredtracker
        results_obj.fp += len(t) - tmptp - nignoredtracker
        # tmpfp   = len(t) - tmptp - nignoredtp # == len(t) - (tp - ignoredtp) - ignoredtp
        # self.fp += len(t) - tmptp - nignoredtp

        # update sequence data
        seqtp += tmptp
        seqfp += tmpfp
        seqfn += tmpfn
        seqitr += nignoredtracker

        # sanity checks
        # - the number of true positives minus ignored true positives
        #   should be greater or equal to 0
        # - the number of false negatives should be greater or equal to 0
        # - the number of false positives needs to be greater or equal to 0
        #   otherwise ignored detections might be counted double
        # - the number of counted true positives (plus ignored ones)
        #   and the number of counted false negatives (plus ignored ones)
        #   should match the total number of ground truth objects
        # - the number of counted true positives (plus ignored ones)
        #   and the number of counted false positives
        #   plus the number of ignored tracker detections should
        #   match the total number of tracker detections
        if tmptp < 0:
            print(tmptp)
            raise NameError("Something went wrong! TP is negative")
        if tmpfn < 0:
            print(tmpfn, len(g), num_associations)
            raise NameError("Something went wrong! FN is negative")
        if tmpfp < 0:
            print(tmpfp, len(t), tmptp, nignoredtracker)
            raise NameError("Something went wrong! FP is negative")
        if tmptp + tmpfn != len(g):
            print("seqname", seq_name)
            print("frame ", f)
            print("TP    ", tmptp)
            print("FN    ", tmpfn)
            print("FP    ", tmpfp)
            print("nGT   ", len(g))
            print("nAss  ", num_associations)
            raise NameError("Something went wrong! nGroundtruth is not TP+FN")
        if tmptp + tmpfp + nignoredtracker != len(t):
            print(seq_name, f, len(t), tmptp, tmpfp)
            print(num_associations)
            raise NameError("Something went wrong! nTracker is not TP+FP")

        # compute MODSP
        MODSP_f = 1
        if tmptp != 0:
            MODSP_f = tmpc / float(tmptp)
        results_obj.MODSP += MODSP_f

    assert len(seq_trajectories) == len(gt_track_ids)
    results_obj.n_gt_trajectories = len(gt_track_ids)
    results_obj.n_tr_trajectories = len(tr_track_ids)

    # compute MT/PT/ML, fragments, idswitches for all groundtruth trajectories
    if len(seq_trajectories) != 0:
        for g in seq_trajectories.values():
            # all frames of this gt trajectory are not assigned to any detections
            if all([this == -1 for this in g]):
                results_obj.ML += 1
                continue
            # compute tracked frames in trajectory
            last_id = g[0]
            # first detection (necessary to be in gt_trajectories) is always tracked
            tracked = 1 if g[0] >= 0 else 0
            for f in range(1, len(g)):
                if last_id != g[f] and last_id != -1 and g[f] != -1:
                    results_obj.id_switches += 1
                if f < len(g) - 1 and g[f - 1] != g[f] and last_id != -1 and g[f] != -1 and g[f + 1] != -1:
                    results_obj.fragments += 1
                if g[f] != -1:
                    tracked += 1
                    last_id = g[f]
            # handle last frame; tracked state is handled in for loop (g[f]!=-1)
            if len(g) > 1 and g[f - 1] != g[f] and last_id != -1 and g[f] != -1:
                results_obj.fragments += 1

            # compute MT/PT/ML
            tracking_ratio = tracked / float(len(g))
            if tracking_ratio > 0.8:
                results_obj.MT += 1
            elif tracking_ratio < 0.2:
                results_obj.ML += 1
            else:  # 0.2 <= tracking_ratio <= 0.8
                results_obj.PT += 1

    return results_obj