# Copyright (C) 2020-2022 Intel Corporation
#
# SPDX-License-Identifier: MIT
import logging as log
import os
import os.path as osp
from collections import OrderedDict, defaultdict
from enum import Enum, auto
from itertools import chain
from typing import Dict, Optional, Set
from attrs import define, field
# Disable B410: import_lxml - the library is used for writing
from lxml import etree as ET # nosec
from datumaro.components.annotation import (
AnnotationType,
Bbox,
CompiledMask,
Label,
LabelCategories,
Mask,
)
from datumaro.components.dataset_base import DatasetItem
from datumaro.components.dataset_item_storage import ItemStatus
from datumaro.components.errors import DatasetExportError, InvalidAnnotationError, MediaTypeError
from datumaro.components.exporter import Exporter
from datumaro.components.media import Image
from datumaro.util import find, str_to_bool
from datumaro.util.annotation_util import make_label_id_mapping
from datumaro.util.image import save_image
from datumaro.util.mask_tools import paint_mask, remap_mask
from datumaro.util.meta_file_util import has_meta_file
from .format import (
VocInstColormap,
VocPath,
VocTask,
make_voc_categories,
make_voc_label_map,
parse_label_map,
parse_meta_file,
write_label_map,
write_meta_file,
)
def _convert_attr(name, attributes, type_conv, default=None):
d = object()
value = attributes.get(name, d)
if value is d:
return default
try:
return type_conv(value)
except Exception as e:
log.warning("Failed to convert attribute '%s'='%s': %s" % (name, value, e))
return default
def _write_xml_bbox(bbox, parent_elem):
x, y, w, h = bbox
bbox_elem = ET.SubElement(parent_elem, "bndbox")
ET.SubElement(bbox_elem, "xmin").text = str(x)
ET.SubElement(bbox_elem, "ymin").text = str(y)
ET.SubElement(bbox_elem, "xmax").text = str(x + w)
ET.SubElement(bbox_elem, "ymax").text = str(y + h)
return bbox_elem
[docs]
class LabelmapType(Enum):
voc = auto()
voc_classification = auto()
voc_detection = auto()
voc_segmentation = auto()
voc_instance_segmentation = auto()
voc_layout = auto()
voc_action = auto()
source = auto()
@define
class _SubsetLists:
class_lists: Dict[str, Optional[Set[int]]] = field(factory=dict)
clsdet_list: Dict[str, Optional[bool]] = field(factory=dict)
action_list: Dict[str, Optional[Dict[str, int]]] = field(factory=dict)
layout_list: Dict[str, Optional[int]] = field(factory=dict)
segm_list: Dict[str, Optional[bool]] = field(factory=dict)
[docs]
class VocExporter(Exporter):
DEFAULT_IMAGE_EXT = VocPath.IMAGE_EXT
BUILTIN_ATTRS = {"difficult", "pose", "truncated", "occluded"}
@staticmethod
def _split_task_string(s):
return [VocTask[i.strip()] for i in s.split(",")]
@staticmethod
def _get_labelmap(s):
if osp.isfile(s):
return s
try:
return LabelmapType[s].name
except KeyError:
import argparse
raise argparse.ArgumentTypeError()
[docs]
@classmethod
def build_cmdline_parser(cls, **kwargs):
parser = super().build_cmdline_parser(**kwargs)
parser.add_argument(
"--apply-colormap",
type=str_to_bool,
default=True,
help="Use colormap for class and instance masks " "(default: %(default)s)",
)
parser.add_argument(
"--label-map",
type=cls._get_labelmap,
default=None,
help="Labelmap file path or one of %s" % ", ".join(t.name for t in LabelmapType),
)
parser.add_argument(
"--allow-attributes",
type=str_to_bool,
default=True,
help="Allow export of attributes (default: %(default)s)",
)
parser.add_argument(
"--keep-empty",
type=str_to_bool,
default=False,
help="Write subset lists even if they are empty " "(default: %(default)s)",
)
parser.add_argument(
"--task",
type=cls._split_task_string,
default=VocTask.voc,
help="VOC task filter, one of list {%s} "
"(default: voc)" % ", ".join(t.name for t in VocTask),
)
return parser
def __init__(
self,
extractor,
save_dir,
task=None,
apply_colormap=True,
label_map=None,
allow_attributes=True,
keep_empty=False,
**kwargs,
):
super().__init__(extractor, save_dir, **kwargs)
task = VocTask.voc if task is None else task
if not isinstance(task, VocTask):
raise DatasetExportError(
f"The task must be an instance of {VocTask} but {task} is given."
)
self._task = task
self._apply_colormap = apply_colormap
self._allow_attributes = allow_attributes
self._keep_empty = keep_empty
if label_map is None:
label_map = LabelmapType.source.name
assert isinstance(label_map, (str, dict)), label_map
self._load_categories(label_map)
self._patch = None
def _apply_impl(self):
if self._extractor.media_type() and not issubclass(self._extractor.media_type(), Image):
raise MediaTypeError("Media type is not an image")
self.make_dirs()
self.save_subsets()
self.save_label_map()
[docs]
def make_dirs(self):
save_dir = self._save_dir
subsets_dir = osp.join(save_dir, VocPath.SUBSETS_DIR)
cls_subsets_dir = osp.join(subsets_dir, VocPath.TASK_DIR[VocTask.voc_classification])
action_subsets_dir = osp.join(subsets_dir, VocPath.TASK_DIR[VocTask.voc_action])
layout_subsets_dir = osp.join(subsets_dir, VocPath.TASK_DIR[VocTask.voc_layout])
segm_subsets_dir = osp.join(subsets_dir, VocPath.TASK_DIR[VocTask.voc_segmentation])
ann_dir = osp.join(save_dir, VocPath.ANNOTATIONS_DIR)
img_dir = osp.join(save_dir, VocPath.IMAGES_DIR)
segm_dir = osp.join(save_dir, VocPath.SEGMENTATION_DIR)
inst_dir = osp.join(save_dir, VocPath.INSTANCES_DIR)
images_dir = osp.join(save_dir, VocPath.IMAGES_DIR)
os.makedirs(subsets_dir, exist_ok=True)
os.makedirs(ann_dir, exist_ok=True)
os.makedirs(img_dir, exist_ok=True)
os.makedirs(segm_dir, exist_ok=True)
os.makedirs(inst_dir, exist_ok=True)
os.makedirs(images_dir, exist_ok=True)
self._subsets_dir = subsets_dir
self._cls_subsets_dir = cls_subsets_dir
self._action_subsets_dir = action_subsets_dir
self._layout_subsets_dir = layout_subsets_dir
self._segm_subsets_dir = segm_subsets_dir
self._ann_dir = ann_dir
self._img_dir = img_dir
self._segm_dir = segm_dir
self._inst_dir = inst_dir
self._images_dir = images_dir
[docs]
def get_label(self, label_id):
return self._extractor.categories()[AnnotationType.label].items[label_id].name
[docs]
def save_subsets(self):
subsets = self._extractor.subsets()
pbars = self._ctx.progress_reporter.split(len(subsets))
for pbar, (subset_name, subset) in zip(pbars, subsets.items()):
lists = _SubsetLists()
for item in pbar.iter(subset, desc=f"Exporting '{subset_name}'"):
log.debug("Converting item '%s'", item.id)
try:
image_filename = self._make_image_filename(item)
if self._save_media:
if item.media:
self._save_image(item, osp.join(self._images_dir, image_filename))
else:
log.debug("Item '%s' has no image", item.id)
self._export_annotations(item, image_filename=image_filename, lists=lists)
except Exception as e:
self._ctx.error_policy.report_item_error(e, item_id=(item.id, item.subset))
if self._task in [
VocTask.voc,
VocTask.voc_classification,
VocTask.voc_detection,
VocTask.voc_action,
VocTask.voc_layout,
VocTask.voc_instance_segmentation,
]:
self.save_clsdet_lists(subset_name, lists.clsdet_list)
if self._task in [VocTask.voc, VocTask.voc_classification]:
self.save_class_lists(subset_name, lists.class_lists)
if self._task in [VocTask.voc, VocTask.voc_action]:
self.save_action_lists(subset_name, lists.action_list)
if self._task in [VocTask.voc, VocTask.voc_layout]:
self.save_layout_lists(subset_name, lists.layout_list)
if self._task in [
VocTask.voc,
VocTask.voc_segmentation,
VocTask.voc_instance_segmentation,
]:
self.save_segm_lists(subset_name, lists.segm_list)
def _export_annotations(self, item: DatasetItem, *, image_filename: str, lists: _SubsetLists):
labels = []
bboxes = []
masks = []
for a in item.annotations:
if isinstance(a, Label):
labels.append(a)
elif isinstance(a, Bbox):
bboxes.append(a)
elif isinstance(a, Mask):
masks.append(a)
if self._task in [
VocTask.voc,
VocTask.voc_detection,
VocTask.voc_instance_segmentation,
VocTask.voc_layout,
VocTask.voc_action,
]:
root_elem = ET.Element("annotation")
if "_" in item.id:
folder = item.id[: item.id.find("_")]
else:
folder = ""
ET.SubElement(root_elem, "folder").text = folder
ET.SubElement(root_elem, "filename").text = image_filename
source_elem = ET.SubElement(root_elem, "source")
ET.SubElement(source_elem, "database").text = "Unknown"
ET.SubElement(source_elem, "annotation").text = "Unknown"
ET.SubElement(source_elem, "image").text = "Unknown"
if item.media and item.media.has_size:
h, w = item.media.size
size_elem = ET.SubElement(root_elem, "size")
ET.SubElement(size_elem, "width").text = str(w)
ET.SubElement(size_elem, "height").text = str(h)
depth = ""
if item.media.has_data:
depth = str(item.media.data.shape[-1])
ET.SubElement(size_elem, "depth").text = depth
item_segmented = 0 < len(masks)
ET.SubElement(root_elem, "segmented").text = str(int(item_segmented))
objects_with_parts = []
objects_with_actions = defaultdict(dict)
main_bboxes = []
layout_bboxes = []
for bbox in bboxes:
label = self.get_label(bbox.label)
if self._is_label(label):
main_bboxes.append(bbox)
elif self._is_part(label):
layout_bboxes.append(bbox)
for new_obj_id, obj in enumerate(main_bboxes):
attr = obj.attributes
obj_elem = ET.SubElement(root_elem, "object")
obj_label = self.get_label(obj.label)
ET.SubElement(obj_elem, "name").text = obj_label
if "pose" in attr:
ET.SubElement(obj_elem, "pose").text = str(attr["pose"])
ET.SubElement(obj_elem, "truncated").text = "%d" % _convert_attr(
"truncated", attr, int, 0
)
ET.SubElement(obj_elem, "occluded").text = "%d" % _convert_attr(
"occluded", attr, int, 0
)
ET.SubElement(obj_elem, "difficult").text = "%d" % _convert_attr(
"difficult", attr, int, 0
)
bbox = obj.get_bbox()
if bbox is not None:
_write_xml_bbox(bbox, obj_elem)
if self._task in [VocTask.voc, VocTask.voc_layout]:
for part_bbox in layout_bboxes:
if part_bbox.group != obj.group:
continue
part_elem = ET.SubElement(obj_elem, "part")
ET.SubElement(part_elem, "name").text = self.get_label(part_bbox.label)
_write_xml_bbox(part_bbox.get_bbox(), part_elem)
objects_with_parts.append(new_obj_id)
label_actions = self._get_actions(obj_label)
actions_elem = ET.Element("actions")
for action in label_actions:
present = 0
if action in attr:
present = _convert_attr(action, attr, lambda v: int(v is True), 0)
if action.isdigit():
action = "_" + action
action = action.replace(" ", "_")
ET.SubElement(actions_elem, action).text = "%d" % present
objects_with_actions[new_obj_id][action] = present
if len(actions_elem) != 0:
obj_elem.append(actions_elem)
if self._allow_attributes:
native_attrs = set(self.BUILTIN_ATTRS)
native_attrs.update(label_actions)
attrs_elem = ET.Element("attributes")
for k, v in attr.items():
if k in native_attrs:
continue
attr_elem = ET.SubElement(attrs_elem, "attribute")
ET.SubElement(attr_elem, "name").text = str(k)
ET.SubElement(attr_elem, "value").text = str(v)
if len(attrs_elem):
obj_elem.append(attrs_elem)
ann_path = osp.join(self._ann_dir, item.id + ".xml")
os.makedirs(osp.dirname(ann_path), exist_ok=True)
with open(ann_path, "w", encoding="utf-8") as f:
f.write(ET.tostring(root_elem, encoding="unicode", pretty_print=True))
lists.clsdet_list[item.id] = True
if self._task in [VocTask.voc, VocTask.voc_layout] and objects_with_parts:
lists.layout_list[item.id] = objects_with_parts
if self._task in [VocTask.voc, VocTask.voc_action] and objects_with_actions:
lists.action_list[item.id] = objects_with_actions
for label_ann in labels:
label = self.get_label(label_ann.label)
if not self._is_label(label):
continue
class_list = lists.class_lists.get(item.id, set())
class_list.add(label_ann.label)
lists.class_lists[item.id] = class_list
lists.clsdet_list[item.id] = True
if (
self._task in [VocTask.voc, VocTask.voc_segmentation, VocTask.voc_instance_segmentation]
and masks
):
compiled_mask = CompiledMask.from_instance_masks(
masks, instance_labels=[self._label_id_mapping(m.label) for m in masks]
)
self.save_segm(
osp.join(self._segm_dir, item.id + VocPath.SEGM_EXT), compiled_mask.class_mask
)
self.save_segm(
osp.join(self._inst_dir, item.id + VocPath.SEGM_EXT),
compiled_mask.instance_mask,
colormap=VocInstColormap,
)
lists.segm_list[item.id] = True
elif not masks and self._patch:
cls_mask_path = osp.join(self._segm_dir, item.id + VocPath.SEGM_EXT)
if osp.isfile(cls_mask_path):
os.remove(cls_mask_path)
inst_mask_path = osp.join(self._inst_dir, item.id + VocPath.SEGM_EXT)
if osp.isfile(inst_mask_path):
os.remove(inst_mask_path)
if len(item.annotations) == 0:
lists.clsdet_list[item.id] = None
lists.layout_list[item.id] = None
lists.action_list[item.id] = None
lists.segm_list[item.id] = None
@staticmethod
def _get_filtered_lines(path, patch, subset, items=None):
lines = {}
with open(path, encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
line_parts = line.split(maxsplit=1)
if len(line_parts) < 2:
line_parts.append("")
item, text = line_parts
if not patch or patch.updated_items.get((item, subset)) != ItemStatus.removed:
lines.setdefault(item, []).append(text)
if items is not None:
items.update((k, True) for k in lines)
return lines
[docs]
def save_action_lists(self, subset_name, action_list):
os.makedirs(self._action_subsets_dir, exist_ok=True)
ann_file = osp.join(self._action_subsets_dir, subset_name + ".txt")
items = {k: True for k in action_list}
if self._patch and osp.isfile(ann_file):
self._get_filtered_lines(ann_file, self._patch, subset_name, items)
if items or self._keep_empty:
with open(ann_file, "w", encoding="utf-8") as f:
for item in items:
f.write("%s\n" % item)
elif osp.isfile(ann_file):
os.remove(ann_file)
if not items and not self._patch and not self._keep_empty:
return
def _write_item(f, item, objs, action):
if not objs:
return
for obj_id, obj_actions in objs.items():
presented = obj_actions.get(action)
f.write("%s %s % d\n" % (item, 1 + obj_id, 1 if presented else -1))
all_actions = {
act: osp.join(self._action_subsets_dir, "%s_%s.txt" % (act, subset_name))
for act in chain(*(self._get_actions(l) for l in self._label_map))
}
for action, ann_file in all_actions.items():
if not items and not self._keep_empty:
if osp.isfile(ann_file):
os.remove(ann_file)
continue
lines = {}
if self._patch and osp.isfile(ann_file):
lines = self._get_filtered_lines(ann_file, None, subset_name)
with open(ann_file, "w", encoding="utf-8") as f:
for item in items:
if item in action_list:
_write_item(f, item, action_list[item], action)
elif item in lines:
print(item, *lines[item], file=f)
[docs]
def save_class_lists(self, subset_name, class_lists):
def _write_item(f, item, item_labels):
if not item_labels:
return
item_labels = [self.get_label(l) for l in item_labels]
presented = label in item_labels
f.write("%s % d\n" % (item, 1 if presented else -1))
os.makedirs(self._cls_subsets_dir, exist_ok=True)
for label in self._label_map:
ann_file = osp.join(self._cls_subsets_dir, "%s_%s.txt" % (label, subset_name))
items = {k: True for k in class_lists}
lines = {}
if self._patch and osp.isfile(ann_file):
lines = self._get_filtered_lines(ann_file, self._patch, subset_name, items)
if not items and not self._keep_empty:
if osp.isfile(ann_file):
os.remove(ann_file)
continue
with open(ann_file, "w", encoding="utf-8") as f:
for item in items:
if item in class_lists:
_write_item(f, item, class_lists[item])
elif item in lines:
print(item, *lines[item], file=f)
[docs]
def save_clsdet_lists(self, subset_name, clsdet_list):
os.makedirs(self._cls_subsets_dir, exist_ok=True)
ann_file = osp.join(self._cls_subsets_dir, subset_name + ".txt")
items = {k: True for k in clsdet_list}
if self._patch and osp.isfile(ann_file):
self._get_filtered_lines(ann_file, self._patch, subset_name, items)
if items or self._keep_empty:
with open(ann_file, "w", encoding="utf-8") as f:
for item in items:
f.write("%s\n" % item)
elif osp.isfile(ann_file):
os.remove(ann_file)
[docs]
def save_segm_lists(self, subset_name, segm_list):
os.makedirs(self._segm_subsets_dir, exist_ok=True)
ann_file = osp.join(self._segm_subsets_dir, subset_name + ".txt")
items = {k: True for k in segm_list}
if self._patch and osp.isfile(ann_file):
self._get_filtered_lines(ann_file, self._patch, subset_name, items)
if items or self._keep_empty:
with open(ann_file, "w", encoding="utf-8") as f:
for item in items:
f.write("%s\n" % item)
elif osp.isfile(ann_file):
os.remove(ann_file)
[docs]
def save_layout_lists(self, subset_name, layout_list):
def _write_item(f, item, item_layouts):
if 1 < len(item.split()):
item = '"' + item + '"'
if item_layouts:
for obj_id in item_layouts:
f.write("%s % d\n" % (item, 1 + obj_id))
else:
f.write("%s\n" % item)
os.makedirs(self._layout_subsets_dir, exist_ok=True)
ann_file = osp.join(self._layout_subsets_dir, subset_name + ".txt")
items = {k: True for k in layout_list}
lines = {}
if self._patch and osp.isfile(ann_file):
self._get_filtered_lines(ann_file, self._patch, subset_name, items)
if not items and not self._keep_empty:
if osp.isfile(ann_file):
os.remove(ann_file)
return
with open(ann_file, "w", encoding="utf-8") as f:
for item in items:
if item in layout_list:
_write_item(f, item, layout_list[item])
elif item in lines:
print(item, *lines[item], file=f)
[docs]
def save_segm(self, path, mask, colormap=None):
if self._apply_colormap:
if colormap is None:
colormap = self._categories[AnnotationType.mask].colormap
mask = paint_mask(mask, colormap)
save_image(path, mask, create_dir=True)
[docs]
def save_label_map(self):
if self._save_dataset_meta:
write_meta_file(self._save_dir, self._label_map)
else:
path = osp.join(self._save_dir, VocPath.LABELMAP_FILE)
write_label_map(path, self._label_map)
def _load_categories(self, label_map_source):
if (
label_map_source in [t.name for t in LabelmapType]
and label_map_source != LabelmapType.source.name
):
label_map = make_voc_label_map(task=self._task)
elif (
label_map_source == LabelmapType.source.name
and AnnotationType.mask not in self._extractor.categories()
):
# generate colormap for input labels
labels = self._extractor.categories().get(AnnotationType.label, LabelCategories())
label_map = OrderedDict((item.name, [None, [], []]) for item in labels.items)
elif (
label_map_source == LabelmapType.source.name
and AnnotationType.mask in self._extractor.categories()
):
# use source colormap
labels = self._extractor.categories()[AnnotationType.label]
colors = self._extractor.categories()[AnnotationType.mask]
label_map = OrderedDict()
for idx, item in enumerate(labels.items):
color = colors.colormap.get(idx)
if color is not None:
label_map[item.name] = [color, [], []]
elif isinstance(label_map_source, dict):
label_map = OrderedDict(sorted(label_map_source.items(), key=lambda e: e[0]))
elif isinstance(label_map_source, str) and osp.isfile(label_map_source):
if has_meta_file(label_map_source):
label_map = parse_meta_file(label_map_source)
else:
label_map = parse_label_map(label_map_source)
else:
raise InvalidAnnotationError(
"Wrong labelmap specified: '%s', "
"expected one of %s or a file path"
% (label_map_source, ", ".join(t.name for t in LabelmapType))
)
bg_label = find(label_map.items(), lambda x: x[1][0] == (0, 0, 0))
if bg_label is None:
bg_label = "background"
if bg_label not in label_map:
has_colors = any(v[0] is not None for v in label_map.values())
color = (0, 0, 0) if has_colors else None
label_map[bg_label] = [color, [], []]
label_map.move_to_end(bg_label, last=False)
self._categories = make_voc_categories(label_map, task=self._task)
# Update colors with assigned values
if label_map_source in [
LabelmapType.voc.name,
LabelmapType.voc_segmentation.name,
LabelmapType.voc_instance_segmentation.name,
]:
colormap = self._categories[AnnotationType.mask].colormap
for label_id, color in colormap.items():
if label_id:
label_desc = label_map[
self._categories[AnnotationType.label].items[label_id].name
]
label_desc[0] = color
self._label_map = label_map
self._label_id_mapping = self._make_label_id_map()
def _is_label(self, s):
return self._label_map.get(s) is not None
def _is_part(self, s):
for label_desc in self._label_map.values():
if s in label_desc[1]:
return True
return False
def _is_action(self, label, s):
return s in self._get_actions(label)
def _get_actions(self, label):
label_desc = self._label_map.get(label)
if not label_desc:
return []
return label_desc[2]
def _make_label_id_map(self):
map_id, id_mapping, src_labels, dst_labels = make_label_id_mapping(
self._extractor.categories().get(AnnotationType.label),
self._categories[AnnotationType.label],
)
void_labels = [
src_label for src_label in src_labels.values() if src_label not in dst_labels
]
if void_labels:
log.warning(
"The following labels are remapped to background: %s" % ", ".join(void_labels)
)
log.debug(
"Saving segmentations with the following label mapping: \n%s"
% "\n".join(
[
"#%s '%s' -> #%s '%s'"
% (
src_id,
src_label,
id_mapping[src_id],
self._categories[AnnotationType.label].items[id_mapping[src_id]].name,
)
for src_id, src_label in src_labels.items()
]
)
)
return map_id
def _remap_mask(self, mask):
return remap_mask(mask, self._label_id_mapping)
[docs]
@classmethod
def patch(cls, dataset, patch, save_dir, **kwargs):
conv = cls(patch.as_dataset(dataset), save_dir=save_dir, **kwargs)
conv._patch = patch
conv.apply()
for filename in os.listdir(conv._cls_subsets_dir):
if "_" not in filename or not filename.endswith(".txt"):
continue
label, subset = osp.splitext(filename)[0].split("_", maxsplit=1)
if label not in conv._label_map or subset not in dataset.subsets():
os.remove(osp.join(conv._cls_subsets_dir, filename))
# Find images that need to be removed
# images from different subsets are stored in the common directory
# Avoid situations like:
# (a, test): added
# (a, train): removed
# where the second line removes images from the first.
ids_to_remove = {}
for (item_id, subset), status in patch.updated_items.items():
if status != ItemStatus.removed:
item = patch.data.get(item_id, subset)
else:
item = DatasetItem(item_id, subset=subset)
if not (status == ItemStatus.removed or not item.media):
ids_to_remove[item_id] = (item, False)
else:
ids_to_remove.setdefault(item_id, (item, True))
for item, to_remove in ids_to_remove.values():
if not to_remove:
continue
if conv._task in [
VocTask.voc,
VocTask.voc_detection,
VocTask.voc_instance_segmentation,
VocTask.voc_action,
VocTask.voc_layout,
]:
ann_path = osp.join(conv._ann_dir, item.id + ".xml")
if osp.isfile(ann_path):
os.remove(ann_path)
image_path = osp.join(conv._images_dir, conv._make_image_filename(item))
if osp.isfile(image_path):
os.unlink(image_path)
if not [a for a in item.annotations if a.type is AnnotationType.mask]:
path = osp.join(save_dir, VocPath.SEGMENTATION_DIR, item.id + VocPath.SEGM_EXT)
if osp.isfile(path):
os.unlink(path)
path = osp.join(save_dir, VocPath.INSTANCES_DIR, item.id + VocPath.SEGM_EXT)
if osp.isfile(path):
os.unlink(path)
@property
def can_stream(self) -> bool:
return True
[docs]
class VocClassificationExporter(VocExporter):
def __init__(self, *args, **kwargs):
kwargs["task"] = VocTask.voc_classification
super().__init__(*args, **kwargs)
[docs]
class VocDetectionExporter(VocExporter):
def __init__(self, *args, **kwargs):
kwargs["task"] = VocTask.voc_detection
super().__init__(*args, **kwargs)
[docs]
class VocSegmentationExporter(VocExporter):
def __init__(self, *args, **kwargs):
kwargs["task"] = VocTask.voc_segmentation
super().__init__(*args, **kwargs)
[docs]
class VocInstanceSegmentationExporter(VocExporter):
def __init__(self, *args, **kwargs):
kwargs["task"] = VocTask.voc_instance_segmentation
super().__init__(*args, **kwargs)
[docs]
class VocLayoutExporter(VocExporter):
def __init__(self, *args, **kwargs):
kwargs["task"] = VocTask.voc_layout
super().__init__(*args, **kwargs)
[docs]
class VocActionExporter(VocExporter):
def __init__(self, *args, **kwargs):
kwargs["task"] = VocTask.voc_action
super().__init__(*args, **kwargs)