示例#1
0
    def test_cache_works(self):
        with TestDir() as test_dir:
            image = np.ones((100, 100, 3), dtype=np.uint8)
            image_path = osp.join(test_dir, 'image.jpg')
            save_image(image_path, image)

            caching_loader = lazy_image(image_path, cache=True)
            self.assertTrue(caching_loader() is caching_loader())

            non_caching_loader = lazy_image(image_path, cache=False)
            self.assertFalse(non_caching_loader() is non_caching_loader())
示例#2
0
    def test_cache_works(self):
        with TestDir() as test_dir:
            image = np.ones((100, 100, 3), dtype=np.uint8)
            image = Image.fromarray(image).convert('RGB')

            image_path = osp.join(test_dir.path, 'image.jpg')
            image.save(image_path)

            caching_loader = lazy_image(image_path, cache=None)
            self.assertTrue(caching_loader() is caching_loader())

            non_caching_loader = lazy_image(image_path, cache=False)
            self.assertFalse(non_caching_loader() is non_caching_loader())
示例#3
0
    def __init__(self,
                 data: Union[bytes, Callable[[str], bytes], None] = None,
                 *,
                 path: Optional[str] = None,
                 ext: Optional[str] = None,
                 size: Optional[Tuple[int, int]] = None):
        if not isinstance(data, bytes):
            assert path or callable(data), "Image can not be empty"
            assert data is None or callable(data)
            if path and osp.isfile(path) or data:
                data = lazy_image(path, loader=data)

        self._bytes_data = data

        if ext is None and path is None and isinstance(data, bytes):
            ext = self._guess_ext(data)

        super().__init__(path=path,
                         ext=ext,
                         size=size,
                         data=lambda _: decode_image(self.get_bytes()))
        if data is None:
            # We don't expect decoder to produce images from nothing,
            # otherwise using this class makes no sense. We undefine
            # data to avoid using default image loader for loading binaries
            # from the path, when no data is provided.
            self._data = None
    def _load_items(self, subset):
        labels = self._categories.setdefault(AnnotationType.label,
                                             LabelCategories())
        path = osp.join(self._path, subset)

        images = [i for i in find_images(path, recursive=True)]

        for image_path in sorted(images):
            item_id = osp.splitext(osp.relpath(image_path, path))[0]

            if Ade20k2017Path.MASK_PATTERN.fullmatch(osp.basename(item_id)):
                continue

            item_annotations = []

            item_info = self._load_item_info(image_path)
            for item in item_info:
                label_idx = labels.find(item['label_name'])[0]
                if label_idx is None:
                    labels.add(item['label_name'])

            mask_path = osp.splitext(image_path)[0] + '_seg.png'
            if not osp.isfile(mask_path):
                log.warning("Can't find mask for image: %s" % image_path)

            part_level = 0
            max_part_level = max([p['part_level'] for p in item_info])
            for part_level in range(max_part_level + 1):
                if not osp.exists(mask_path):
                    log.warning('Can`t find part level %s mask for %s' \
                        % (part_level, image_path))
                    continue

                mask = lazy_image(mask_path, loader=self._load_instance_mask)
                mask = CompiledMask(instance_mask=mask)

                for v in item_info:
                    if v['part_level'] != part_level:
                        continue

                    label_id = labels.find(v['label_name'])[0]
                    instance_id = v['id']
                    attributes = {k: True for k in v['attributes']}

                    item_annotations.append(
                        Mask(label=label_id,
                             image=mask.lazy_extract(instance_id),
                             id=instance_id,
                             attributes=attributes,
                             z_order=part_level,
                             group=instance_id))

                mask_path = osp.splitext(image_path)[0] \
                    + '_parts_%s.png' % (part_level + 1)

            self._items.append(
                DatasetItem(item_id,
                            subset=subset,
                            image=image_path,
                            annotations=item_annotations))
示例#5
0
    def __init__(self,
                 data: Union[np.ndarray, Callable[[str], np.ndarray],
                             None] = None,
                 *,
                 path: Optional[str] = None,
                 ext: Optional[str] = None,
                 size: Optional[Tuple[int, int]] = None) -> None:
        """
        Creates an image.

        Any combination of the `data`, `path` and `size` is possible,
        but at least one of these arguments must be provided.
        The `ext` parameter cannot be used as a single argument for
        construction.

        Args:
            data - Image pixels or a function to retrieve them. The expected
                image shape is (H, W [, C]). If a function is provided,
                it must accept image path as the first argument.
            path - Image path
            ext - Image extension. Cannot be used together with `path`. It can
                be used for saving with a custom extension - in that case,
                the image need to have the `data` and `ext` fields defined.
            size - A pair (H, W), which represents image size.
        """

        if size is not None:
            assert len(size) == 2 and 0 < size[0] and 0 < size[1], \
                f"Invalid image size info '{size}'"
            size = tuple(map(int, size))
        self._size = size  # (H, W)

        if path is None:
            path = ''
        elif path:
            path = path.replace('\\', '/')
        self._path = path

        if ext:
            assert not path, "Can't specify both 'path' and 'ext' for image"

            if not ext.startswith('.'):
                ext = '.' + ext
            ext = ext.lower()
        else:
            ext = None
        self._ext = ext

        if not isinstance(data, np.ndarray):
            assert path or callable(data) or size, "Image can not be empty"
            assert data is None or callable(data), \
                f"Image data has unexpected type '{type(data)}'"
            if data or path and osp.isfile(path):
                data = lazy_image(path, loader=data)
        self._data = data
示例#6
0
文件: voc.py 项目: benhoff/cvat
    def _get(self, item, subset_name):
        image = None
        image_path = osp.join(self._path, VocPath.IMAGES_DIR,
                              item + VocPath.IMAGE_EXT)
        if osp.isfile(image_path):
            image = lazy_image(image_path)

        annotations = self._get_annotations(item, subset_name)

        return DatasetItem(annotations=annotations,
                           id=item,
                           subset=subset_name,
                           image=image)
示例#7
0
    def test_cache_fifo_displacement(self):
        capacity = 2
        cache = ImageCache(capacity)

        loaders = [lazy_image(None, loader=lambda p: object(), cache=cache)
            for _ in range(capacity + 1)]

        first_request = [loader() for loader in loaders[1 : ]]
        loaders[0]() # pop something from the cache

        second_request = [loader() for loader in loaders[2 : ]]
        second_request.insert(0, loaders[1]())

        matches = sum([a is b for a, b in zip(first_request, second_request)])
        self.assertEqual(matches, len(first_request) - 1)
示例#8
0
文件: datumaro.py 项目: benhoff/cvat
    def _get(self, index, subset_name):
        item = self._annotations[subset_name]['items'][index]

        item_id = item.get('id')

        image_path = osp.join(self._path, DatumaroPath.IMAGES_DIR,
            item_id + DatumaroPath.IMAGE_EXT)
        image = None
        if osp.isfile(image_path):
            image = lazy_image(image_path)

        annotations = self._load_annotations(item)

        return DatasetItem(id=item_id, subset=subset_name,
            annotations=annotations, image=image)
示例#9
0
    def __init__(self, url):
        super().__init__()

        items = []
        for (dirpath, _, filenames) in os.walk(url):
            for name in filenames:
                path = osp.join(dirpath, name)
                if self._is_image(path):
                    item_id = Task.get_image_frame(path)
                    item = datumaro.DatasetItem(id=item_id,
                                                image=lazy_image(path))
                    items.append((item.id, item))

        items = sorted(items, key=lambda e: e[0])
        items = OrderedDict(items)
        self._items = items

        self._subsets = None
示例#10
0
    def _load_panoptic_ann(self, ann, parsed_annotations=None):
        if parsed_annotations is None:
            parsed_annotations = []

        # For the panoptic task, each annotation struct is a per-image
        # annotation rather than a per-object annotation.
        mask_path = osp.join(self._mask_dir, ann['file_name'])
        mask = lazy_image(mask_path, loader=self._load_pan_mask)
        mask = CompiledMask(instance_mask=mask)
        for segm_info in ann['segments_info']:
            cat_id = self._get_label_id(segm_info)
            segm_id = segm_info['id']
            attributes = {'is_crowd': bool(segm_info['iscrowd'])}
            parsed_annotations.append(
                Mask(image=mask.lazy_extract(segm_id),
                     label=cat_id,
                     id=segm_id,
                     group=segm_id,
                     attributes=attributes))

        return parsed_annotations
示例#11
0
    def _load_panoptic_items(self, config):
        items = {}

        images_info = {
            img['id']: {
                'path': osp.join(self._images_dir, img['file_name']),
                'height': img.get('height'),
                'width': img.get('width')
            }
            for img in config['images']
        }

        for item_ann in config['annotations']:
            item_id = item_ann['image_id']
            image = None
            if images_info.get(item_id):
                image = Image(
                    path=images_info[item_id]['path'],
                    size=self._get_image_size(images_info[item_id])
                )

            annotations = []
            mask_path = osp.join(self._annotations_dir,
                MapillaryVistasPath.PANOPTIC_DIR, item_ann['file_name'])
            mask = lazy_image(mask_path, loader=self._load_pan_mask)
            mask = CompiledMask(instance_mask=mask)

            for segment_info in item_ann['segments_info']:
                cat_id = self._get_label_id(segment_info)
                segment_id = segment_info['id']
                attributes = { 'is_crowd': bool(segment_info['iscrowd']) }
                annotations.append(Mask(image=mask.lazy_extract(segment_id),
                    label=cat_id, id=segment_id,
                    group=segment_id, attributes=attributes))

            items[item_id] = DatasetItem(id=item_id, subset=self._subset,
                annotations=annotations, image=image)

        self._load_polygons(items)
        return items.values()
示例#12
0
    def _parse_tfrecord_file(cls, filepath, subset, images_dir):
        dataset = tf.data.TFRecordDataset(filepath)
        features = {
            'image/filename': tf.io.FixedLenFeature([], tf.string),
            'image/source_id': tf.io.FixedLenFeature([], tf.string),
            'image/height': tf.io.FixedLenFeature([], tf.int64),
            'image/width': tf.io.FixedLenFeature([], tf.int64),
            'image/encoded': tf.io.FixedLenFeature([], tf.string),
            'image/format': tf.io.FixedLenFeature([], tf.string),

            # use varlen to avoid errors when this field is missing
            'image/key/sha256': tf.io.VarLenFeature(tf.string),

            # Object boxes and classes.
            'image/object/bbox/xmin': tf.io.VarLenFeature(tf.float32),
            'image/object/bbox/xmax': tf.io.VarLenFeature(tf.float32),
            'image/object/bbox/ymin': tf.io.VarLenFeature(tf.float32),
            'image/object/bbox/ymax': tf.io.VarLenFeature(tf.float32),
            'image/object/class/label': tf.io.VarLenFeature(tf.int64),
            'image/object/class/text': tf.io.VarLenFeature(tf.string),
            'image/object/mask': tf.io.VarLenFeature(tf.string),
        }

        dataset_labels = OrderedDict()
        labelmap_path = osp.join(osp.dirname(filepath),
                                 DetectionApiPath.LABELMAP_FILE)
        if osp.exists(labelmap_path):
            with open(labelmap_path, 'r', encoding='utf-8') as f:
                labelmap_text = f.read()
            dataset_labels.update({
                label: id - 1
                for label, id in cls._parse_labelmap(labelmap_text).items()
            })

        dataset_items = []

        for record in dataset:
            parsed_record = tf.io.parse_single_example(record, features)
            frame_id = parsed_record['image/source_id'].numpy().decode('utf-8')
            frame_filename = \
                parsed_record['image/filename'].numpy().decode('utf-8')
            frame_height = tf.cast(parsed_record['image/height'],
                                   tf.int64).numpy().item()
            frame_width = tf.cast(parsed_record['image/width'],
                                  tf.int64).numpy().item()
            frame_image = parsed_record['image/encoded'].numpy()
            xmins = tf.sparse.to_dense(
                parsed_record['image/object/bbox/xmin']).numpy()
            ymins = tf.sparse.to_dense(
                parsed_record['image/object/bbox/ymin']).numpy()
            xmaxs = tf.sparse.to_dense(
                parsed_record['image/object/bbox/xmax']).numpy()
            ymaxs = tf.sparse.to_dense(
                parsed_record['image/object/bbox/ymax']).numpy()
            label_ids = tf.sparse.to_dense(
                parsed_record['image/object/class/label']).numpy()
            labels = tf.sparse.to_dense(
                parsed_record['image/object/class/text'],
                default_value=b'').numpy()
            masks = tf.sparse.to_dense(parsed_record['image/object/mask'],
                                       default_value=b'').numpy()

            for label, label_id in zip(labels, label_ids):
                label = label.decode('utf-8')
                if not label:
                    continue
                if label_id <= 0:
                    continue
                if label in dataset_labels:
                    continue
                dataset_labels[label] = label_id - 1

            item_id = osp.splitext(frame_filename)[0]

            annotations = []
            for shape_id, shape in enumerate(
                    np.dstack((labels, xmins, ymins, xmaxs, ymaxs))[0]):
                label = shape[0].decode('utf-8')

                mask = None
                if len(masks) != 0:
                    mask = masks[shape_id]

                if mask is not None:
                    if isinstance(mask, bytes):
                        mask = lazy_image(mask, decode_image)
                    annotations.append(
                        Mask(image=mask, label=dataset_labels.get(label)))
                else:
                    x = clamp(shape[1] * frame_width, 0, frame_width)
                    y = clamp(shape[2] * frame_height, 0, frame_height)
                    w = clamp(shape[3] * frame_width, 0, frame_width) - x
                    h = clamp(shape[4] * frame_height, 0, frame_height) - y
                    annotations.append(
                        Bbox(x, y, w, h, label=dataset_labels.get(label)))

            image_size = None
            if frame_height and frame_width:
                image_size = (frame_height, frame_width)

            image_params = {}
            if frame_image:
                image_params['data'] = frame_image
            if frame_filename:
                image_params['path'] = osp.join(images_dir, frame_filename)

            image = None
            if image_params:
                image = ByteImage(**image_params, size=image_size)

            dataset_items.append(
                DatasetItem(id=item_id,
                            subset=subset,
                            image=image,
                            annotations=annotations,
                            attributes={'source_id': frame_id}))

        return dataset_items, dataset_labels
示例#13
0
    def test_global_cache_is_accessible(self):
        loader = lazy_image(None, loader=lambda p: object())

        self.assertTrue(loader() is loader())
        self.assertEqual(ImageCache.get_instance().size(), 1)
示例#14
0
文件: datumaro.py 项目: benhoff/cvat
    def _load_annotations(self, item):
        parsed = item['annotations']
        loaded = []

        for ann in parsed:
            ann_id = ann.get('id')
            ann_type = AnnotationType[ann['type']]
            attributes = ann.get('attributes')
            group = ann.get('group')

            if ann_type == AnnotationType.label:
                label_id = ann.get('label_id')
                loaded.append(LabelObject(label=label_id,
                    id=ann_id, attributes=attributes, group=group))

            elif ann_type == AnnotationType.mask:
                label_id = ann.get('label_id')
                mask_id = str(ann.get('mask_id'))

                mask_path = osp.join(self._path, DatumaroPath.ANNOTATIONS_DIR,
                    DatumaroPath.MASKS_DIR, mask_id + DatumaroPath.MASK_EXT)
                mask = None

                if osp.isfile(mask_path):
                    mask_cat = self._categories.get(AnnotationType.mask)
                    if mask_cat is not None:
                        mask = lazy_mask(mask_path, mask_cat.inverse_colormap)
                    else:
                        mask = lazy_image(mask_path)

                loaded.append(MaskObject(label=label_id, image=mask,
                    id=ann_id, attributes=attributes, group=group))

            elif ann_type == AnnotationType.polyline:
                label_id = ann.get('label_id')
                points = ann.get('points')
                loaded.append(PolyLineObject(points, label=label_id,
                    id=ann_id, attributes=attributes, group=group))

            elif ann_type == AnnotationType.polygon:
                label_id = ann.get('label_id')
                points = ann.get('points')
                loaded.append(PolygonObject(points, label=label_id,
                    id=ann_id, attributes=attributes, group=group))

            elif ann_type == AnnotationType.bbox:
                label_id = ann.get('label_id')
                x, y, w, h = ann.get('bbox')
                loaded.append(BboxObject(x, y, w, h, label=label_id,
                    id=ann_id, attributes=attributes, group=group))

            elif ann_type == AnnotationType.points:
                label_id = ann.get('label_id')
                points = ann.get('points')
                loaded.append(PointsObject(points, label=label_id,
                    id=ann_id, attributes=attributes, group=group))

            elif ann_type == AnnotationType.caption:
                caption = ann.get('caption')
                loaded.append(CaptionObject(caption,
                    id=ann_id, attributes=attributes, group=group))

            else:
                raise NotImplementedError()

        return loaded
示例#15
0
    def _load_items(self, subset):
        labels = self._categories.setdefault(AnnotationType.label,
                                             LabelCategories())
        path = osp.join(self._path, subset)

        images = [i for i in find_images(path, recursive=True)]

        for image_path in sorted(images):
            item_id = osp.splitext(osp.relpath(image_path, path))[0]

            if Ade20k2020Path.MASK_PATTERN.fullmatch(osp.basename(item_id)):
                continue

            item_annotations = []
            item_info = self._load_item_info(image_path)
            for item in item_info:
                label_idx = labels.find(item['label_name'])[0]
                if label_idx is None:
                    labels.add(item['label_name'])

            mask_path = osp.splitext(image_path)[0] + '_seg.png'
            max_part_level = max([p['part_level'] for p in item_info])
            for part_level in range(max_part_level + 1):
                if not osp.exists(mask_path):
                    log.warning('Can`t find part level %s mask for %s' \
                        % (part_level, image_path))
                    continue

                mask = lazy_image(mask_path, loader=self._load_class_mask)
                mask = CompiledMask(instance_mask=mask)

                classes = {(v['class_idx'], v['label_name'])
                           for v in item_info if v['part_level'] == part_level}

                for class_idx, label_name in classes:
                    label_id = labels.find(label_name)[0]
                    item_annotations.append(
                        Mask(label=label_id,
                             id=class_idx,
                             image=mask.lazy_extract(class_idx),
                             group=class_idx,
                             z_order=part_level))

                mask_path = osp.splitext(image_path)[0] \
                    + '_parts_%s.png' % (part_level + 1)

            for item in item_info:
                instance_path = osp.join(osp.dirname(image_path),
                                         item['instance_mask'])
                if not osp.isfile(instance_path):
                    log.warning('Can`t find instance mask: %s' % instance_path)
                    continue

                mask = lazy_image(instance_path,
                                  loader=self._load_instance_mask)
                mask = CompiledMask(instance_mask=mask)

                label_id = labels.find(item['label_name'])[0]
                instance_id = item['id']
                attributes = {k: True for k in item['attributes']}
                polygon_points = item['polygon_points']

                item_annotations.append(
                    Mask(label=label_id,
                         image=mask.lazy_extract(1),
                         id=instance_id,
                         attributes=attributes,
                         z_order=item['part_level'],
                         group=instance_id))

                if (len(item['polygon_points']) % 2 == 0 \
                        and 3 <= len(item['polygon_points']) // 2):
                    item_annotations.append(
                        Polygon(polygon_points,
                                label=label_id,
                                attributes=attributes,
                                id=instance_id,
                                z_order=item['part_level'],
                                group=instance_id))

            self._items.append(
                DatasetItem(item_id,
                            subset=subset,
                            image=image_path,
                            annotations=item_annotations))
示例#16
0
 def _make_image_loader(self, item_id):
     return lazy_image(item_id,
                       lambda item_id: self._image_loader(item_id, self))
示例#17
0
    def _load_masks(self, items_by_id, normalized_coords):
        label_categories = self._categories[AnnotationType.label]

        for mask_path in self._glob_annotations(
            '*' + OpenImagesPath.MASK_DESCRIPTION_FILE_SUFFIX
        ):
            with self._open_csv_annotation(mask_path) as mask_reader:
                for mask_description in mask_reader:
                    mask_path = mask_description['MaskPath']
                    if _RE_INVALID_PATH_COMPONENT.fullmatch(mask_path):
                        raise UnsupportedMaskPathError(item_id=item.id,
                            mask_path=mask_path)

                    image_id = mask_description['ImageID']
                    item = items_by_id.get(image_id)
                    if item is None:
                        item = items_by_id.setdefault(
                            image_id, self._add_item(image_id,
                                self._get_subset_name(mask_path))
                        )


                    label_name = mask_description['LabelName']
                    label_index, _ = label_categories.find(label_name)
                    if label_index is None:
                        raise UndefinedLabel(
                            item_id=item.id, subset=item.subset,
                            label_name=label_name, severity=Severity.error)

                    if item.has_image and item.image.has_size:
                        image_size = item.image.size
                    elif self._image_meta.get(item.id):
                        image_size = self._image_meta.get(item.id)
                    else:
                        log.warning(
                            "Can't decode mask for item '%s' due to missing image file",
                            item.id)
                        continue

                    attributes = {}

                    # The box IDs are rather useless, because the _box_ annotations
                    # don't include them, so they cannot be used to match masks to boxes.
                    # However, it is still desirable to record them, because they are
                    # included in the mask file names, so in order to save each mask to the
                    # file it was loaded from when saving in-places, we need to know
                    # the original box ID.
                    box_id = mask_description['BoxID']
                    if _RE_INVALID_PATH_COMPONENT.fullmatch(box_id):
                        raise UnsupportedBoxIdError(
                            item_id=item.id, box_id=box_id)
                    attributes['box_id'] = box_id

                    group = 0

                    box_coord_fields = ('BoxXMin', 'BoxXMax', 'BoxYMin', 'BoxYMax')

                    # The original OID has box coordinates for all masks, but
                    # a dataset converted from another dataset might not.
                    if all(mask_description[f] for f in box_coord_fields):
                        # Try to find the box annotation corresponding to the
                        # current mask.
                        mask_box_coords = np.array([
                            float(mask_description[field])
                            for field in box_coord_fields
                        ])

                        for annotation in item.annotations:
                            if (
                                annotation.type is AnnotationType.bbox
                                and annotation.label == label_index
                            ):
                                # In the original OID, mask box coordinates are stored
                                # with 6 digit precision, hence the tolerance.
                                if np.allclose(
                                    mask_box_coords, normalized_coords[id(annotation)],
                                    rtol=0, atol=1e-6,
                                ):
                                    group = annotation.group

                    if mask_description['PredictedIoU']:
                        attributes['predicted_iou'] = float(mask_description['PredictedIoU'])

                    item.annotations.append(Mask(
                        image=lazy_image(
                            osp.join(
                                self._dataset_dir, OpenImagesPath.MASKS_DIR,
                                item.subset, mask_path,
                            ),
                            loader=functools.partial(
                                self._load_and_resize_mask, size=image_size),
                        ),
                        label=label_index,
                        attributes=attributes,
                        group=group,
                    ))
示例#18
0
def lazy_mask(path, inverse_colormap=None):
    return lazy_image(path, lambda path: load_mask(path, inverse_colormap))
示例#19
0
def lazy_mask(path, inverse_colormap=None):
    return lazy_image(path,
                      partial(load_mask, inverse_colormap=inverse_colormap))