|
|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
|
|
|
|
|
# Copyright (C) 2019-2022 Intel Corporation
|
|
|
|
|
# Copyright (C) 2022 CVAT.ai Corporation
|
|
|
|
|
#
|
|
|
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
|
|
@ -12,13 +13,10 @@ from types import SimpleNamespace
|
|
|
|
|
from typing import (Any, Callable, DefaultDict, Dict, List, Literal, Mapping,
|
|
|
|
|
NamedTuple, OrderedDict, Set, Tuple, Union)
|
|
|
|
|
|
|
|
|
|
import datumaro.components.annotation as datum_annotation
|
|
|
|
|
import datumaro.components.extractor as datum_extractor
|
|
|
|
|
import datumaro as dm
|
|
|
|
|
import rq
|
|
|
|
|
from attr import attrib, attrs
|
|
|
|
|
from datumaro.components.dataset import Dataset
|
|
|
|
|
from datumaro.util import cast
|
|
|
|
|
from datumaro.util.image import ByteImage, Image
|
|
|
|
|
from datumaro.components.media import PointCloud
|
|
|
|
|
from django.utils import timezone
|
|
|
|
|
|
|
|
|
|
from cvat.apps.dataset_manager.formats.utils import get_label_color
|
|
|
|
|
@ -241,7 +239,7 @@ class TaskData(InstanceLabelData):
|
|
|
|
|
("bugtracker", db_task.bug_tracker),
|
|
|
|
|
("created", str(timezone.localtime(db_task.created_date))),
|
|
|
|
|
("updated", str(timezone.localtime(db_task.updated_date))),
|
|
|
|
|
("subset", db_task.subset or datum_extractor.DEFAULT_SUBSET_NAME),
|
|
|
|
|
("subset", db_task.subset or dm.DEFAULT_SUBSET_NAME),
|
|
|
|
|
("start_frame", str(db_task.data.start_frame)),
|
|
|
|
|
("stop_frame", str(db_task.data.stop_frame)),
|
|
|
|
|
("frame_filter", db_task.data.frame_filter),
|
|
|
|
|
@ -781,7 +779,7 @@ class ProjectData(InstanceLabelData):
|
|
|
|
|
) for db_task in self._db_tasks.values()
|
|
|
|
|
]),
|
|
|
|
|
|
|
|
|
|
("subsets", '\n'.join([s if s else datum_extractor.DEFAULT_SUBSET_NAME for s in self._subsets])),
|
|
|
|
|
("subsets", '\n'.join([s if s else dm.DEFAULT_SUBSET_NAME for s in self._subsets])),
|
|
|
|
|
|
|
|
|
|
("owner", OrderedDict([
|
|
|
|
|
("username", self._db_project.owner.username),
|
|
|
|
|
@ -1024,7 +1022,7 @@ class ProjectData(InstanceLabelData):
|
|
|
|
|
def _get_filename(path):
|
|
|
|
|
return osp.splitext(path)[0]
|
|
|
|
|
|
|
|
|
|
def match_frame(self, path: str, subset: str=datum_extractor.DEFAULT_SUBSET_NAME, root_hint: str=None, path_has_ext: bool=True):
|
|
|
|
|
def match_frame(self, path: str, subset: str=dm.DEFAULT_SUBSET_NAME, root_hint: str=None, path_has_ext: bool=True):
|
|
|
|
|
if path_has_ext:
|
|
|
|
|
path = self._get_filename(path)
|
|
|
|
|
match_task, match_frame = self._frame_mapping.get((subset, path), (None, None))
|
|
|
|
|
@ -1040,11 +1038,11 @@ class ProjectData(InstanceLabelData):
|
|
|
|
|
return frame_number
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def split_dataset(self, dataset: Dataset):
|
|
|
|
|
def split_dataset(self, dataset: dm.Dataset):
|
|
|
|
|
for task_data in self.task_data:
|
|
|
|
|
if task_data._db_task.id not in self.new_tasks:
|
|
|
|
|
continue
|
|
|
|
|
subset_dataset: Dataset = dataset.subsets()[task_data.db_task.subset].as_dataset()
|
|
|
|
|
subset_dataset: dm.Dataset = dataset.subsets()[task_data.db_task.subset].as_dataset()
|
|
|
|
|
yield subset_dataset, task_data
|
|
|
|
|
|
|
|
|
|
def add_labels(self, labels: List[dict]):
|
|
|
|
|
@ -1060,7 +1058,7 @@ class ProjectData(InstanceLabelData):
|
|
|
|
|
self._project_annotation.add_task(task, files, self)
|
|
|
|
|
|
|
|
|
|
class CVATDataExtractorMixin:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
def __init__(self, media_type=dm.Image):
|
|
|
|
|
super().__init__()
|
|
|
|
|
|
|
|
|
|
def categories(self) -> dict:
|
|
|
|
|
@ -1068,28 +1066,27 @@ class CVATDataExtractorMixin:
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def _load_categories(labels: list):
|
|
|
|
|
categories: Dict[datum_annotation.AnnotationType,
|
|
|
|
|
datum_annotation.Categories] = {}
|
|
|
|
|
categories: Dict[dm.AnnotationType,
|
|
|
|
|
dm.Categories] = {}
|
|
|
|
|
|
|
|
|
|
label_categories = datum_annotation.LabelCategories(attributes=['occluded'])
|
|
|
|
|
point_categories = datum_annotation.PointsCategories()
|
|
|
|
|
label_categories = dm.LabelCategories(attributes=['occluded'])
|
|
|
|
|
point_categories = dm.PointsCategories()
|
|
|
|
|
|
|
|
|
|
for _, label in labels:
|
|
|
|
|
if label.get('parent') is None:
|
|
|
|
|
label_id = label_categories.add(label['name'])
|
|
|
|
|
for _, attr in label['attributes']:
|
|
|
|
|
label_categories.attributes.add(attr['name'])
|
|
|
|
|
label_id = label_categories.add(label['name'], label.get('parent'))
|
|
|
|
|
for _, attr in label['attributes']:
|
|
|
|
|
label_categories.attributes.add(attr['name'])
|
|
|
|
|
|
|
|
|
|
if label['type'] == str(LabelType.SKELETON):
|
|
|
|
|
labels_from = list(map(int, re.findall(r'data-node-from="(\d+)"', label['svg'])))
|
|
|
|
|
labels_to = list(map(int, re.findall(r'data-node-to="(\d+)"', label['svg'])))
|
|
|
|
|
sublabels = re.findall(r'data-label-name="(\w+)"', label['svg'])
|
|
|
|
|
joints = zip(labels_from, labels_to)
|
|
|
|
|
if label['type'] == str(LabelType.SKELETON):
|
|
|
|
|
labels_from = list(map(int, re.findall(r'data-node-from="(\d+)"', label['svg'])))
|
|
|
|
|
labels_to = list(map(int, re.findall(r'data-node-to="(\d+)"', label['svg'])))
|
|
|
|
|
sublabels = re.findall(r'data-label-name="(\w+)"', label['svg'])
|
|
|
|
|
joints = zip(labels_from, labels_to)
|
|
|
|
|
|
|
|
|
|
point_categories.add(label_id, sublabels, joints)
|
|
|
|
|
point_categories.add(label_id, sublabels, joints)
|
|
|
|
|
|
|
|
|
|
categories[datum_annotation.AnnotationType.label] = label_categories
|
|
|
|
|
categories[datum_annotation.AnnotationType.points] = point_categories
|
|
|
|
|
categories[dm.AnnotationType.label] = label_categories
|
|
|
|
|
categories[dm.AnnotationType.points] = point_categories
|
|
|
|
|
|
|
|
|
|
return categories
|
|
|
|
|
|
|
|
|
|
@ -1103,7 +1100,7 @@ class CVATDataExtractorMixin:
|
|
|
|
|
|
|
|
|
|
def _read_cvat_anno(self, cvat_frame_anno: Union[ProjectData.Frame, TaskData.Frame], labels: list):
|
|
|
|
|
categories = self.categories()
|
|
|
|
|
label_cat = categories[datum_annotation.AnnotationType.label]
|
|
|
|
|
label_cat = categories[dm.AnnotationType.label]
|
|
|
|
|
def map_label(name): return label_cat.find(name)[0]
|
|
|
|
|
label_attrs = {
|
|
|
|
|
label['name']: label['attributes']
|
|
|
|
|
@ -1113,9 +1110,9 @@ class CVATDataExtractorMixin:
|
|
|
|
|
return convert_cvat_anno_to_dm(cvat_frame_anno, label_attrs, map_label)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CvatTaskDataExtractor(datum_extractor.SourceExtractor, CVATDataExtractorMixin):
|
|
|
|
|
class CvatTaskDataExtractor(dm.SourceExtractor, CVATDataExtractorMixin):
|
|
|
|
|
def __init__(self, task_data, include_images=False, format_type=None, dimension=DimensionType.DIM_2D):
|
|
|
|
|
super().__init__()
|
|
|
|
|
super().__init__(media_type=dm.Image if dimension == DimensionType.DIM_2D else PointCloud)
|
|
|
|
|
self._categories = self._load_categories(task_data.meta['task']['labels'])
|
|
|
|
|
self._user = self._load_user_info(task_data.meta['task']) if dimension == DimensionType.DIM_3D else {}
|
|
|
|
|
self._dimension = dimension
|
|
|
|
|
@ -1148,14 +1145,14 @@ class CvatTaskDataExtractor(datum_extractor.SourceExtractor, CVATDataExtractorMi
|
|
|
|
|
loader = lambda _: frame_provider.get_frame(i,
|
|
|
|
|
quality=frame_provider.Quality.ORIGINAL,
|
|
|
|
|
out_type=frame_provider.Type.NUMPY_ARRAY)[0]
|
|
|
|
|
return Image(loader=loader, **kwargs)
|
|
|
|
|
return dm.Image(data=loader, **kwargs)
|
|
|
|
|
else:
|
|
|
|
|
# for images use encoded data to avoid recoding
|
|
|
|
|
def _make_image(i, **kwargs):
|
|
|
|
|
loader = lambda _: frame_provider.get_frame(i,
|
|
|
|
|
quality=frame_provider.Quality.ORIGINAL,
|
|
|
|
|
out_type=frame_provider.Type.BUFFER)[0].getvalue()
|
|
|
|
|
return ByteImage(data=loader, **kwargs)
|
|
|
|
|
return dm.ByteImage(data=loader, **kwargs)
|
|
|
|
|
|
|
|
|
|
for frame_data in task_data.group_by_frame(include_empty=True):
|
|
|
|
|
image_args = {
|
|
|
|
|
@ -1168,13 +1165,13 @@ class CvatTaskDataExtractor(datum_extractor.SourceExtractor, CVATDataExtractorMi
|
|
|
|
|
elif include_images:
|
|
|
|
|
dm_image = _make_image(frame_data.idx, **image_args)
|
|
|
|
|
else:
|
|
|
|
|
dm_image = Image(**image_args)
|
|
|
|
|
dm_image = dm.Image(**image_args)
|
|
|
|
|
dm_anno = self._read_cvat_anno(frame_data, task_data.meta['task']['labels'])
|
|
|
|
|
|
|
|
|
|
if dimension == DimensionType.DIM_2D:
|
|
|
|
|
dm_item = datum_extractor.DatasetItem(
|
|
|
|
|
dm_item = dm.DatasetItem(
|
|
|
|
|
id=osp.splitext(frame_data.name)[0],
|
|
|
|
|
annotations=dm_anno, image=dm_image,
|
|
|
|
|
annotations=dm_anno, media=dm_image,
|
|
|
|
|
attributes={'frame': frame_data.frame
|
|
|
|
|
})
|
|
|
|
|
elif dimension == DimensionType.DIM_3D:
|
|
|
|
|
@ -1188,9 +1185,9 @@ class CvatTaskDataExtractor(datum_extractor.SourceExtractor, CVATDataExtractorMi
|
|
|
|
|
attributes["labels"].append({"label_id": idx, "name": label["name"], "color": label["color"], "type": label["type"]})
|
|
|
|
|
attributes["track_id"] = -1
|
|
|
|
|
|
|
|
|
|
dm_item = datum_extractor.DatasetItem(
|
|
|
|
|
dm_item = dm.DatasetItem(
|
|
|
|
|
id=osp.splitext(osp.split(frame_data.name)[-1])[0],
|
|
|
|
|
annotations=dm_anno, point_cloud=dm_image[0], related_images=dm_image[1],
|
|
|
|
|
annotations=dm_anno, media=PointCloud(dm_image[0]), related_images=dm_image[1],
|
|
|
|
|
attributes=attributes
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@ -1200,24 +1197,24 @@ class CvatTaskDataExtractor(datum_extractor.SourceExtractor, CVATDataExtractorMi
|
|
|
|
|
|
|
|
|
|
def _read_cvat_anno(self, cvat_frame_anno: TaskData.Frame, labels: list):
|
|
|
|
|
categories = self.categories()
|
|
|
|
|
label_cat = categories[datum_annotation.AnnotationType.label]
|
|
|
|
|
def map_label(name): return label_cat.find(name)[0]
|
|
|
|
|
label_cat = categories[dm.AnnotationType.label]
|
|
|
|
|
def map_label(name, parent=""): return label_cat.find(name, parent)[0]
|
|
|
|
|
label_attrs = {
|
|
|
|
|
label['name']: label['attributes']
|
|
|
|
|
label.get("parent", "") + label['name']: label['attributes']
|
|
|
|
|
for _, label in labels
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return convert_cvat_anno_to_dm(cvat_frame_anno, label_attrs, map_label, self._format_type, self._dimension)
|
|
|
|
|
|
|
|
|
|
class CVATProjectDataExtractor(datum_extractor.Extractor, CVATDataExtractorMixin):
|
|
|
|
|
class CVATProjectDataExtractor(dm.Extractor, CVATDataExtractorMixin):
|
|
|
|
|
def __init__(self, project_data: ProjectData, include_images: bool = False, format_type: str = None, dimension: DimensionType = DimensionType.DIM_2D):
|
|
|
|
|
super().__init__()
|
|
|
|
|
super().__init__(media_type=dm.Image if dimension == DimensionType.DIM_2D else PointCloud)
|
|
|
|
|
self._categories = self._load_categories(project_data.meta['project']['labels'])
|
|
|
|
|
self._user = self._load_user_info(project_data.meta['project']) if dimension == DimensionType.DIM_3D else {}
|
|
|
|
|
self._dimension = dimension
|
|
|
|
|
self._format_type = format_type
|
|
|
|
|
|
|
|
|
|
dm_items: List[datum_extractor.DatasetItem] = []
|
|
|
|
|
dm_items: List[dm.DatasetItem] = []
|
|
|
|
|
|
|
|
|
|
ext_per_task: Dict[int, str] = {}
|
|
|
|
|
image_maker_per_task: Dict[int, Callable] = {}
|
|
|
|
|
@ -1251,7 +1248,7 @@ class CVATProjectDataExtractor(datum_extractor.Extractor, CVATDataExtractorMixin
|
|
|
|
|
loader = lambda _: frame_provider.get_frame(i,
|
|
|
|
|
quality=frame_provider.Quality.ORIGINAL,
|
|
|
|
|
out_type=frame_provider.Type.NUMPY_ARRAY)[0]
|
|
|
|
|
return Image(loader=loader, **kwargs)
|
|
|
|
|
return dm.Image(data=loader, **kwargs)
|
|
|
|
|
return _make_image
|
|
|
|
|
else:
|
|
|
|
|
# for images use encoded data to avoid recoding
|
|
|
|
|
@ -1261,7 +1258,7 @@ class CVATProjectDataExtractor(datum_extractor.Extractor, CVATDataExtractorMixin
|
|
|
|
|
loader = lambda _: frame_provider.get_frame(i,
|
|
|
|
|
quality=frame_provider.Quality.ORIGINAL,
|
|
|
|
|
out_type=frame_provider.Type.BUFFER)[0].getvalue()
|
|
|
|
|
return ByteImage(data=loader, **kwargs)
|
|
|
|
|
return dm.ByteImage(data=loader, **kwargs)
|
|
|
|
|
return _make_image
|
|
|
|
|
image_maker_per_task[task.id] = image_maker_factory(task)
|
|
|
|
|
|
|
|
|
|
@ -1275,12 +1272,12 @@ class CVATProjectDataExtractor(datum_extractor.Extractor, CVATDataExtractorMixin
|
|
|
|
|
elif include_images:
|
|
|
|
|
dm_image = image_maker_per_task[frame_data.task_id](frame_data.idx, **image_args)
|
|
|
|
|
else:
|
|
|
|
|
dm_image = Image(**image_args)
|
|
|
|
|
dm_image = dm.Image(**image_args)
|
|
|
|
|
dm_anno = self._read_cvat_anno(frame_data, project_data.meta['project']['labels'])
|
|
|
|
|
if self._dimension == DimensionType.DIM_2D:
|
|
|
|
|
dm_item = datum_extractor.DatasetItem(
|
|
|
|
|
dm_item = dm.DatasetItem(
|
|
|
|
|
id=osp.splitext(frame_data.name)[0],
|
|
|
|
|
annotations=dm_anno, image=dm_image,
|
|
|
|
|
annotations=dm_anno, media=dm_image,
|
|
|
|
|
subset=frame_data.subset,
|
|
|
|
|
attributes={'frame': frame_data.frame}
|
|
|
|
|
)
|
|
|
|
|
@ -1295,9 +1292,9 @@ class CVATProjectDataExtractor(datum_extractor.Extractor, CVATDataExtractorMixin
|
|
|
|
|
attributes["labels"].append({"label_id": idx, "name": label["name"], "color": label["color"], "type": label["type"]})
|
|
|
|
|
attributes["track_id"] = -1
|
|
|
|
|
|
|
|
|
|
dm_item = datum_extractor.DatasetItem(
|
|
|
|
|
dm_item = dm.DatasetItem(
|
|
|
|
|
id=osp.splitext(osp.split(frame_data.name)[-1])[0],
|
|
|
|
|
annotations=dm_anno, point_cloud=dm_image[0], related_images=dm_image[1],
|
|
|
|
|
annotations=dm_anno, media=PointCloud(dm_image[0]), related_images=dm_image[1],
|
|
|
|
|
attributes=attributes, subset=frame_data.subset
|
|
|
|
|
)
|
|
|
|
|
dm_items.append(dm_item)
|
|
|
|
|
@ -1348,13 +1345,13 @@ def get_defaulted_subset(subset: str, subsets: List[str]) -> str:
|
|
|
|
|
if subset:
|
|
|
|
|
return subset
|
|
|
|
|
else:
|
|
|
|
|
if datum_extractor.DEFAULT_SUBSET_NAME not in subsets:
|
|
|
|
|
return datum_extractor.DEFAULT_SUBSET_NAME
|
|
|
|
|
if dm.DEFAULT_SUBSET_NAME not in subsets:
|
|
|
|
|
return dm.DEFAULT_SUBSET_NAME
|
|
|
|
|
else:
|
|
|
|
|
i = 1
|
|
|
|
|
while i < sys.maxsize:
|
|
|
|
|
if f'{datum_extractor.DEFAULT_SUBSET_NAME}_{i}' not in subsets:
|
|
|
|
|
return f'{datum_extractor.DEFAULT_SUBSET_NAME}_{i}'
|
|
|
|
|
if f'{dm.DEFAULT_SUBSET_NAME}_{i}' not in subsets:
|
|
|
|
|
return f'{dm.DEFAULT_SUBSET_NAME}_{i}'
|
|
|
|
|
i += 1
|
|
|
|
|
raise Exception('Cannot find default name for subset')
|
|
|
|
|
|
|
|
|
|
@ -1385,7 +1382,7 @@ def convert_cvat_anno_to_dm(cvat_frame_anno, label_attrs, map_label, format_name
|
|
|
|
|
anno_label = map_label(tag_obj.label)
|
|
|
|
|
anno_attr = convert_attrs(tag_obj.label, tag_obj.attributes)
|
|
|
|
|
|
|
|
|
|
anno = datum_annotation.Label(label=anno_label,
|
|
|
|
|
anno = dm.Label(label=anno_label,
|
|
|
|
|
attributes=anno_attr, group=anno_group)
|
|
|
|
|
item_anno.append(anno)
|
|
|
|
|
|
|
|
|
|
@ -1408,7 +1405,7 @@ def convert_cvat_anno_to_dm(cvat_frame_anno, label_attrs, map_label, format_name
|
|
|
|
|
|
|
|
|
|
anno_points = shape_obj.points
|
|
|
|
|
if shape_obj.type == ShapeType.POINTS:
|
|
|
|
|
anno = datum_annotation.Points(anno_points,
|
|
|
|
|
anno = dm.Points(anno_points,
|
|
|
|
|
label=anno_label, attributes=anno_attr, group=anno_group,
|
|
|
|
|
z_order=shape_obj.z_order)
|
|
|
|
|
elif shape_obj.type == ShapeType.ELLIPSE:
|
|
|
|
|
@ -1424,16 +1421,16 @@ def convert_cvat_anno_to_dm(cvat_frame_anno, label_attrs, map_label, format_name
|
|
|
|
|
"attributes": anno_attr,
|
|
|
|
|
}), cvat_frame_anno.height, cvat_frame_anno.width)
|
|
|
|
|
elif shape_obj.type == ShapeType.POLYLINE:
|
|
|
|
|
anno = datum_annotation.PolyLine(anno_points,
|
|
|
|
|
anno = dm.PolyLine(anno_points,
|
|
|
|
|
label=anno_label, attributes=anno_attr, group=anno_group,
|
|
|
|
|
z_order=shape_obj.z_order)
|
|
|
|
|
elif shape_obj.type == ShapeType.POLYGON:
|
|
|
|
|
anno = datum_annotation.Polygon(anno_points,
|
|
|
|
|
anno = dm.Polygon(anno_points,
|
|
|
|
|
label=anno_label, attributes=anno_attr, group=anno_group,
|
|
|
|
|
z_order=shape_obj.z_order)
|
|
|
|
|
elif shape_obj.type == ShapeType.RECTANGLE:
|
|
|
|
|
x0, y0, x1, y1 = anno_points
|
|
|
|
|
anno = datum_annotation.Bbox(x0, y0, x1 - x0, y1 - y0,
|
|
|
|
|
anno = dm.Bbox(x0, y0, x1 - x0, y1 - y0,
|
|
|
|
|
label=anno_label, attributes=anno_attr, group=anno_group,
|
|
|
|
|
z_order=shape_obj.z_order)
|
|
|
|
|
elif shape_obj.type == ShapeType.CUBOID:
|
|
|
|
|
@ -1443,27 +1440,30 @@ def convert_cvat_anno_to_dm(cvat_frame_anno, label_attrs, map_label, format_name
|
|
|
|
|
else:
|
|
|
|
|
anno_id = index
|
|
|
|
|
position, rotation, scale = anno_points[0:3], anno_points[3:6], anno_points[6:9]
|
|
|
|
|
anno = datum_annotation.Cuboid3d(
|
|
|
|
|
anno = dm.Cuboid3d(
|
|
|
|
|
id=anno_id, position=position, rotation=rotation, scale=scale,
|
|
|
|
|
label=anno_label, attributes=anno_attr, group=anno_group
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
continue
|
|
|
|
|
elif shape_obj.type == ShapeType.SKELETON:
|
|
|
|
|
points = []
|
|
|
|
|
vis = []
|
|
|
|
|
elements = []
|
|
|
|
|
for element in shape_obj.elements:
|
|
|
|
|
points.extend(element.points)
|
|
|
|
|
element_vis = datum_annotation.Points.Visibility.visible
|
|
|
|
|
element_attr = convert_attrs(shape_obj.label + element.label, element.attributes)
|
|
|
|
|
|
|
|
|
|
if hasattr(element, 'track_id'):
|
|
|
|
|
element_attr['track_id'] = element.track_id
|
|
|
|
|
element_attr['keyframe'] = element.keyframe
|
|
|
|
|
element_vis = dm.Points.Visibility.visible
|
|
|
|
|
if element.outside:
|
|
|
|
|
element_vis = datum_annotation.Points.Visibility.absent
|
|
|
|
|
element_vis = dm.Points.Visibility.absent
|
|
|
|
|
elif element.occluded:
|
|
|
|
|
element_vis = datum_annotation.Points.Visibility.hidden
|
|
|
|
|
vis.append(element_vis)
|
|
|
|
|
element_vis = dm.Points.Visibility.hidden
|
|
|
|
|
elements.append(dm.Points(element.points, [element_vis],
|
|
|
|
|
label=map_label(element.label, shape_obj.label), attributes=element_attr))
|
|
|
|
|
|
|
|
|
|
anno = datum_annotation.Points(points, vis,
|
|
|
|
|
label=anno_label, attributes=anno_attr, group=anno_group,
|
|
|
|
|
z_order=shape_obj.z_order)
|
|
|
|
|
anno = dm.Skeleton(elements, label=anno_label,
|
|
|
|
|
attributes=anno_attr, group=anno_group, z_order=shape_obj.z_order)
|
|
|
|
|
else:
|
|
|
|
|
raise Exception("Unknown shape type '%s'" % shape_obj.type)
|
|
|
|
|
|
|
|
|
|
@ -1480,9 +1480,9 @@ def match_dm_item(item, task_data, root_hint=None):
|
|
|
|
|
if frame_number is None:
|
|
|
|
|
frame_number = task_data.match_frame(item.id, root_hint, path_has_ext=False)
|
|
|
|
|
if frame_number is None:
|
|
|
|
|
frame_number = cast(item.attributes.get('frame', item.id), int)
|
|
|
|
|
frame_number = dm.util.cast(item.attributes.get('frame', item.id), int)
|
|
|
|
|
if frame_number is None and is_video:
|
|
|
|
|
frame_number = cast(osp.basename(item.id)[len('frame_'):], int)
|
|
|
|
|
frame_number = dm.util.cast(osp.basename(item.id)[len('frame_'):], int)
|
|
|
|
|
|
|
|
|
|
if not frame_number in task_data.frame_info:
|
|
|
|
|
raise CvatImportError("Could not match item id: "
|
|
|
|
|
@ -1505,7 +1505,7 @@ def find_dataset_root(dm_dataset, instance_data: Union[TaskData, ProjectData]):
|
|
|
|
|
prefix = prefix[:-1]
|
|
|
|
|
return prefix
|
|
|
|
|
|
|
|
|
|
def import_dm_annotations(dm_dataset: Dataset, instance_data: Union[TaskData, ProjectData]):
|
|
|
|
|
def import_dm_annotations(dm_dataset: dm.Dataset, instance_data: Union[TaskData, ProjectData]):
|
|
|
|
|
if len(dm_dataset) == 0:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
@ -1518,15 +1518,15 @@ def import_dm_annotations(dm_dataset: Dataset, instance_data: Union[TaskData, Pr
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
shapes = {
|
|
|
|
|
datum_annotation.AnnotationType.bbox: ShapeType.RECTANGLE,
|
|
|
|
|
datum_annotation.AnnotationType.polygon: ShapeType.POLYGON,
|
|
|
|
|
datum_annotation.AnnotationType.polyline: ShapeType.POLYLINE,
|
|
|
|
|
datum_annotation.AnnotationType.points: ShapeType.POINTS,
|
|
|
|
|
datum_annotation.AnnotationType.cuboid_3d: ShapeType.CUBOID
|
|
|
|
|
dm.AnnotationType.bbox: ShapeType.RECTANGLE,
|
|
|
|
|
dm.AnnotationType.polygon: ShapeType.POLYGON,
|
|
|
|
|
dm.AnnotationType.polyline: ShapeType.POLYLINE,
|
|
|
|
|
dm.AnnotationType.points: ShapeType.POINTS,
|
|
|
|
|
dm.AnnotationType.cuboid_3d: ShapeType.CUBOID,
|
|
|
|
|
dm.AnnotationType.skeleton: ShapeType.SKELETON
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
label_cat = dm_dataset.categories()[datum_annotation.AnnotationType.label]
|
|
|
|
|
point_cat = dm_dataset.categories().get(datum_annotation.AnnotationType.points)
|
|
|
|
|
label_cat = dm_dataset.categories()[dm.AnnotationType.label]
|
|
|
|
|
|
|
|
|
|
root_hint = find_dataset_root(dm_dataset, instance_data)
|
|
|
|
|
|
|
|
|
|
@ -1563,54 +1563,57 @@ def import_dm_annotations(dm_dataset: Dataset, instance_data: Union[TaskData, Pr
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
if ann.type in shapes:
|
|
|
|
|
if ann.type == datum_annotation.AnnotationType.cuboid_3d:
|
|
|
|
|
try:
|
|
|
|
|
ann.points = [*ann.position,*ann.rotation,*ann.scale,0,0,0,0,0,0,0]
|
|
|
|
|
except Exception:
|
|
|
|
|
ann.points = ann.points
|
|
|
|
|
ann.z_order = 0
|
|
|
|
|
points = []
|
|
|
|
|
if ann.type == dm.AnnotationType.cuboid_3d:
|
|
|
|
|
points = [*ann.position, *ann.rotation, *ann.scale, 0, 0, 0, 0, 0, 0, 0]
|
|
|
|
|
elif ann.type != dm.AnnotationType.skeleton:
|
|
|
|
|
points = ann.points
|
|
|
|
|
|
|
|
|
|
# Use safe casting to bool instead of plain reading
|
|
|
|
|
# because in some formats return type can be different
|
|
|
|
|
# from bool / None
|
|
|
|
|
# https://github.com/openvinotoolkit/datumaro/issues/719
|
|
|
|
|
occluded = cast(ann.attributes.pop('occluded', None), bool) is True
|
|
|
|
|
keyframe = cast(ann.attributes.get('keyframe', None), bool) is True
|
|
|
|
|
outside = cast(ann.attributes.pop('outside', None), bool) is True
|
|
|
|
|
occluded = dm.util.cast(ann.attributes.pop('occluded', None), bool) is True
|
|
|
|
|
keyframe = dm.util.cast(ann.attributes.get('keyframe', None), bool) is True
|
|
|
|
|
outside = dm.util.cast(ann.attributes.pop('outside', None), bool) is True
|
|
|
|
|
|
|
|
|
|
track_id = ann.attributes.pop('track_id', None)
|
|
|
|
|
source = ann.attributes.pop('source').lower() \
|
|
|
|
|
if ann.attributes.get('source', '').lower() in {'auto', 'manual'} else 'manual'
|
|
|
|
|
|
|
|
|
|
shape_type = shapes[ann.type]
|
|
|
|
|
elements = []
|
|
|
|
|
if point_cat and shape_type == ShapeType.POINTS:
|
|
|
|
|
labels = point_cat.items[ann.label].labels
|
|
|
|
|
shape_type = ShapeType.SKELETON
|
|
|
|
|
for i in range(len(ann.points) // 2):
|
|
|
|
|
label = None
|
|
|
|
|
if i < len(labels):
|
|
|
|
|
label = labels[i]
|
|
|
|
|
elements.append(instance_data.LabeledShape(
|
|
|
|
|
type=ShapeType.POINTS,
|
|
|
|
|
frame=frame_number,
|
|
|
|
|
points=ann.points[2 * i : 2 * i + 2],
|
|
|
|
|
label=label,
|
|
|
|
|
occluded=ann.visibility[i] == datum_annotation.Points.Visibility.hidden,
|
|
|
|
|
source=source,
|
|
|
|
|
attributes=[],
|
|
|
|
|
outside=ann.visibility[i] == datum_annotation.Points.Visibility.absent,
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if track_id is None or dm_dataset.format != 'cvat' :
|
|
|
|
|
elements = []
|
|
|
|
|
if ann.type == dm.AnnotationType.skeleton:
|
|
|
|
|
for element in ann.elements:
|
|
|
|
|
element_attributes = [
|
|
|
|
|
instance_data.Attribute(name=n, value=str(v))
|
|
|
|
|
for n, v in element.attributes.items()
|
|
|
|
|
]
|
|
|
|
|
element_occluded = element.visibility[0] == dm.Points.Visibility.hidden
|
|
|
|
|
element_outside = element.visibility[0] == dm.Points.Visibility.absent
|
|
|
|
|
element_source = element.attributes.pop('source').lower() \
|
|
|
|
|
if element.attributes.get('source', '').lower() in {'auto', 'manual'} else 'manual'
|
|
|
|
|
elements.append(instance_data.LabeledShape(
|
|
|
|
|
type=shapes[element.type],
|
|
|
|
|
frame=frame_number,
|
|
|
|
|
points=element.points,
|
|
|
|
|
label=label_cat.items[element.label].name,
|
|
|
|
|
occluded=element_occluded,
|
|
|
|
|
z_order=ann.z_order,
|
|
|
|
|
group=group_map.get(ann.group, 0),
|
|
|
|
|
source=element_source,
|
|
|
|
|
attributes=element_attributes,
|
|
|
|
|
elements=[],
|
|
|
|
|
outside=element_outside,
|
|
|
|
|
))
|
|
|
|
|
instance_data.add_shape(instance_data.LabeledShape(
|
|
|
|
|
type=shape_type,
|
|
|
|
|
frame=frame_number,
|
|
|
|
|
points=ann.points,
|
|
|
|
|
points=points,
|
|
|
|
|
label=label_cat.items[ann.label].name,
|
|
|
|
|
occluded=occluded,
|
|
|
|
|
z_order=ann.z_order,
|
|
|
|
|
z_order=ann.z_order if ann.type != dm.AnnotationType.cuboid_3d else 0,
|
|
|
|
|
group=group_map.get(ann.group, 0),
|
|
|
|
|
source=source,
|
|
|
|
|
attributes=attributes,
|
|
|
|
|
@ -1619,29 +1622,59 @@ def import_dm_annotations(dm_dataset: Dataset, instance_data: Union[TaskData, Pr
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if keyframe or outside:
|
|
|
|
|
if track_id not in tracks:
|
|
|
|
|
tracks[track_id] = {
|
|
|
|
|
'label': label_cat.items[ann.label].name,
|
|
|
|
|
'group': group_map.get(ann.group, 0),
|
|
|
|
|
'source': source,
|
|
|
|
|
'shapes': [],
|
|
|
|
|
'elements':{},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track = instance_data.TrackedShape(
|
|
|
|
|
type=shapes[ann.type],
|
|
|
|
|
frame=frame_number,
|
|
|
|
|
occluded=occluded,
|
|
|
|
|
outside=outside,
|
|
|
|
|
keyframe=keyframe,
|
|
|
|
|
points=ann.points,
|
|
|
|
|
z_order=ann.z_order,
|
|
|
|
|
points=points,
|
|
|
|
|
z_order=ann.z_order if ann.type != dm.AnnotationType.cuboid_3d else 0,
|
|
|
|
|
source=source,
|
|
|
|
|
attributes=attributes,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if track_id not in tracks:
|
|
|
|
|
tracks[track_id] = instance_data.Track(
|
|
|
|
|
label=label_cat.items[ann.label].name,
|
|
|
|
|
group=group_map.get(ann.group, 0),
|
|
|
|
|
source=source,
|
|
|
|
|
shapes=[],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
tracks[track_id].shapes.append(track)
|
|
|
|
|
|
|
|
|
|
elif ann.type == datum_annotation.AnnotationType.label:
|
|
|
|
|
tracks[track_id]['shapes'].append(track)
|
|
|
|
|
|
|
|
|
|
if ann.type == dm.AnnotationType.skeleton:
|
|
|
|
|
for element in ann.elements:
|
|
|
|
|
if element.label not in tracks[track_id]['elements']:
|
|
|
|
|
tracks[track_id]['elements'][element.label] = instance_data.Track(
|
|
|
|
|
label=label_cat.items[element.label].name,
|
|
|
|
|
group=0,
|
|
|
|
|
source=source,
|
|
|
|
|
shapes=[],
|
|
|
|
|
)
|
|
|
|
|
element_attributes = [
|
|
|
|
|
instance_data.Attribute(name=n, value=str(v))
|
|
|
|
|
for n, v in element.attributes.items()
|
|
|
|
|
]
|
|
|
|
|
element_occluded = dm.util.cast(element.attributes.pop('occluded', None), bool) is True
|
|
|
|
|
element_outside = dm.util.cast(element.attributes.pop('outside', None), bool) is True
|
|
|
|
|
element_source = element.attributes.pop('source').lower() \
|
|
|
|
|
if element.attributes.get('source', '').lower() in {'auto', 'manual'} else 'manual'
|
|
|
|
|
tracks[track_id]['elements'][element.label].shapes.append(instance_data.TrackedShape(
|
|
|
|
|
type=shapes[element.type],
|
|
|
|
|
frame=frame_number,
|
|
|
|
|
occluded=element_occluded,
|
|
|
|
|
outside=element_outside,
|
|
|
|
|
keyframe=keyframe,
|
|
|
|
|
points=element.points,
|
|
|
|
|
z_order=element.z_order,
|
|
|
|
|
source=element_source,
|
|
|
|
|
attributes=element_attributes,
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
elif ann.type == dm.AnnotationType.label:
|
|
|
|
|
instance_data.add_tag(instance_data.Tag(
|
|
|
|
|
frame=frame_number,
|
|
|
|
|
label=label_cat.items[ann.label].name,
|
|
|
|
|
@ -1654,13 +1687,14 @@ def import_dm_annotations(dm_dataset: Dataset, instance_data: Union[TaskData, Pr
|
|
|
|
|
"#{} ({}): {}".format(item.id, idx, ann.type.name, e)) from e
|
|
|
|
|
|
|
|
|
|
for track in tracks.values():
|
|
|
|
|
instance_data.add_track(track)
|
|
|
|
|
track['elements'] = list(track['elements'].values())
|
|
|
|
|
instance_data.add_track(instance_data.Track(**track))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def import_labels_to_project(project_annotation, dataset: Dataset):
|
|
|
|
|
def import_labels_to_project(project_annotation, dataset: dm.Dataset):
|
|
|
|
|
labels = []
|
|
|
|
|
label_colors = []
|
|
|
|
|
for label in dataset.categories()[datum_annotation.AnnotationType.label].items:
|
|
|
|
|
for label in dataset.categories()[dm.AnnotationType.label].items:
|
|
|
|
|
db_label = Label(
|
|
|
|
|
name=label.name,
|
|
|
|
|
color=get_label_color(label.name, label_colors),
|
|
|
|
|
@ -1670,11 +1704,11 @@ def import_labels_to_project(project_annotation, dataset: Dataset):
|
|
|
|
|
label_colors.append(db_label.color)
|
|
|
|
|
project_annotation.add_labels(labels)
|
|
|
|
|
|
|
|
|
|
def load_dataset_data(project_annotation, dataset: Dataset, project_data):
|
|
|
|
|
def load_dataset_data(project_annotation, dataset: dm.Dataset, project_data):
|
|
|
|
|
if not project_annotation.db_project.label_set.count():
|
|
|
|
|
import_labels_to_project(project_annotation, dataset)
|
|
|
|
|
else:
|
|
|
|
|
for label in dataset.categories()[datum_annotation.AnnotationType.label].items:
|
|
|
|
|
for label in dataset.categories()[dm.AnnotationType.label].items:
|
|
|
|
|
if not project_annotation.db_project.label_set.filter(name=label.name).exists():
|
|
|
|
|
raise CvatImportError(f'Target project does not have label with name "{label.name}"')
|
|
|
|
|
for subset_id, subset in enumerate(dataset.subsets().values()):
|
|
|
|
|
|