Update Datumaro version (#4984)

main
Anastasia Yasakova 3 years ago committed by GitHub
parent be5f9773d0
commit 9e67bcb53c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- `api/docs`, `api/swagger`, `api/schema` endpoints now allow unauthorized access (<https://github.com/opencv/cvat/pull/4928>)
- Datumaro version (<https://github.com/opencv/cvat/pull/4984>)
### Deprecated
- TDB
@ -20,9 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- TDB
### Fixed
- Removed a possibly duplicated encodeURI() calls in `server-proxy.ts` to prevent doubly encoding
- Removed a possibly duplicated encodeURI() calls in `server-proxy.ts` to prevent doubly encoding
non-ascii paths while adding files from "Connected file share" (issue #4428)
- Removed unnecessary volumes defined in docker-compose.serverless.yml
- Removed unnecessary volumes defined in docker-compose.serverless.yml
(<https://github.com/openvinotoolkit/cvat/pull/4659>)
### Security

@ -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()):

@ -1,4 +1,5 @@
# Copyright (C) 2018-2022 Intel Corporation
# Copyright (C) 2022 CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT
@ -409,7 +410,7 @@ class CvatExtractor(Extractor):
di.subset = subset or DEFAULT_SUBSET_NAME
di.annotations = item_desc.get('annotations')
di.attributes = {'frame': int(frame_id)}
di.image = image if isinstance(image, Image) else di.image
di.media = image if isinstance(image, Image) else di.media
image_items[(subset, osp.splitext(name)[0])] = di
return image_items

@ -1,4 +1,5 @@
# Copyright (C) 2021-2022 Intel Corporation
# Copyright (C) 2022 CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT
@ -90,7 +91,7 @@ def _import(src_file, instance_data, load_data_callback=None):
with TemporaryDirectory() as tmp_dir:
zipfile.ZipFile(src_file).extractall(tmp_dir)
dataset = Dataset.import_from(tmp_dir, 'icdar_word_recognition', env=dm_env)
dataset.transform(CaptionToLabel, 'icdar')
dataset.transform(CaptionToLabel, label='icdar')
if load_data_callback is not None:
load_data_callback(dataset, instance_data)
import_dm_annotations(dataset, instance_data)
@ -110,7 +111,7 @@ def _import(src_file, instance_data, load_data_callback=None):
zipfile.ZipFile(src_file).extractall(tmp_dir)
dataset = Dataset.import_from(tmp_dir, 'icdar_text_localization', env=dm_env)
dataset.transform(AddLabelToAnns, 'icdar')
dataset.transform(AddLabelToAnns, label='icdar')
if load_data_callback is not None:
load_data_callback(dataset, instance_data)
import_dm_annotations(dataset, instance_data)
@ -133,7 +134,7 @@ def _import(src_file, instance_data, load_data_callback=None):
with TemporaryDirectory() as tmp_dir:
zipfile.ZipFile(src_file).extractall(tmp_dir)
dataset = Dataset.import_from(tmp_dir, 'icdar_text_segmentation', env=dm_env)
dataset.transform(AddLabelToAnns, 'icdar')
dataset.transform(AddLabelToAnns, label='icdar')
dataset.transform('masks_to_polygons')
if load_data_callback is not None:
load_data_callback(dataset, instance_data)

@ -1,4 +1,5 @@
# Copyright (C) 2021-2022 Intel Corporation
# Copyright (C) 2022 CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT
@ -65,7 +66,7 @@ def _export(dst_file, instance_data, save_images=False):
dataset = Dataset.from_extractors(GetCVATDataExtractor(
instance_data, include_images=save_images), env=dm_env)
with TemporaryDirectory() as temp_dir:
dataset.transform(LabelAttrToAttr, 'market-1501')
dataset.transform(LabelAttrToAttr, label='market-1501')
dataset.export(temp_dir, 'market1501', save_images=save_images)
make_zip_archive(temp_dir, dst_file)
@ -75,7 +76,7 @@ def _import(src_file, instance_data, load_data_callback=None):
zipfile.ZipFile(src_file).extractall(tmp_dir)
dataset = Dataset.import_from(tmp_dir, 'market1501', env=dm_env)
dataset.transform(AttrToLabelAttr, 'market-1501')
dataset.transform(AttrToLabelAttr, label='market-1501')
if load_data_callback is not None:
load_data_callback(dataset, instance_data)
import_dm_annotations(dataset, instance_data)

@ -9,7 +9,7 @@ from itertools import chain
from pycocotools import mask as mask_utils
from datumaro.components.extractor import ItemTransform
import datumaro.components.annotation as datum_annotation
import datumaro.components.annotation as dm
class RotatedBoxesToPolygons(ItemTransform):
def _rotate_point(self, p, angle, cx, cy):
@ -20,7 +20,7 @@ class RotatedBoxesToPolygons(ItemTransform):
def transform_item(self, item):
annotations = item.annotations[:]
anns = [p for p in annotations if p.type == datum_annotation.AnnotationType.bbox and p.attributes['rotation']]
anns = [p for p in annotations if p.type == dm.AnnotationType.bbox and p.attributes['rotation']]
for ann in anns:
rotation = math.radians(ann.attributes['rotation'])
x0, y0, x1, y1 = ann.points
@ -30,7 +30,7 @@ class RotatedBoxesToPolygons(ItemTransform):
))
annotations.remove(ann)
annotations.append(datum_annotation.Polygon(anno_points,
annotations.append(dm.Polygon(anno_points,
label=ann.label, attributes=ann.attributes, group=ann.group,
z_order=ann.z_order))
@ -48,5 +48,5 @@ class EllipsesToMasks:
mat = np.zeros((img_h, img_w), dtype=np.uint8)
cv2.ellipse(mat, center, axis, angle, 0, 360, 255, thickness=-1)
rle = mask_utils.encode(np.asfortranarray(mat))
return datum_annotation.RleMask(rle=rle, label=ellipse.label, z_order=ellipse.z_order,
return dm.RleMask(rle=rle, label=ellipse.label, z_order=ellipse.z_order,
attributes=ellipse.attributes, group=ellipse.group)

@ -1,4 +1,5 @@
# Copyright (C) 2021-2022 Intel Corporation
# Copyright (C) 2022 CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT
@ -29,7 +30,7 @@ def _import(src_file, instance_data, load_data_callback=None):
zipfile.ZipFile(src_file).extractall(tmp_dir)
dataset = Dataset.import_from(tmp_dir, 'vgg_face2', env=dm_env)
dataset.transform('rename', r"|([^/]+/)?(.+)|\2|")
dataset.transform('rename', regex=r"|([^/]+/)?(.+)|\2|")
if load_data_callback is not None:
load_data_callback(dataset, instance_data)
import_dm_annotations(dataset, instance_data)

@ -533,15 +533,7 @@
},
"Market-1501 1.0": {
"version": 0,
"tags": [
{
"frame": 1,
"label_id": null,
"group": 0,
"source": "manual",
"attributes": []
}
],
"tags": [],
"shapes": [],
"tracks": []
},

@ -336,7 +336,14 @@
"name": "skeleton",
"color": "#2080c0",
"type": "skeleton",
"attributes": [],
"attributes": [
{
"name": "attr",
"mutable": false,
"input_type": "select",
"values": ["0", "1", "2"]
}
],
"sublabels": [
{
"name": "1",
@ -353,14 +360,7 @@
{
"name": "3",
"color": "#479ffe",
"attributes": [
{
"name": "attr",
"mutable": false,
"input_type": "select",
"values": ["0", "1", "2"]
}
],
"attributes": [],
"type": "points"
}
],

@ -1,5 +1,6 @@
# Copyright (C) 2020-2022 Intel Corporation
# Copyright (C) 2022 CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT
@ -617,6 +618,14 @@ class TaskAnnotationsImportTest(_DbTestBase):
images["image_quality"] = 75
return images
def _generate_task_images_by_names(self, names, **image_params):
images = {
f"client_files[{i}]": generate_image_file(f"{name}.jpg", **image_params)
for i, name in enumerate(names)
}
images["image_quality"] = 75
return images
def _generate_task(self, images, annotation_format, **overrides):
labels = []
if annotation_format in ["ICDAR Recognition 1.0",
@ -911,7 +920,10 @@ class TaskAnnotationsImportTest(_DbTestBase):
for f in dm.views.get_import_formats():
format_name = f.DISPLAY_NAME
images = self._generate_task_images(3, "img0.0.0")
if format_name == "Market-1501 1.0":
images = self._generate_task_images_by_names(["img0.0.0_0", "1.0_c3s1_000000_00", "img0.0.0_1"])
else:
images = self._generate_task_images(3, "img0.0.0")
task = self._generate_task(images, format_name)
self._generate_annotations(task, format_name)

@ -45,9 +45,7 @@ diskcache==5.0.2
boto3==1.17.61
azure-storage-blob==12.13.0
google-cloud-storage==1.42.0
# --no-binary=datumaro: workaround for pip to install
# opencv-headless instead of regular opencv, to actually run setup script
datumaro==0.2.0 --no-binary=datumaro
git+https://github.com/cvat-ai/datumaro.git@bac20235bd6c792b4d068a54fd3ad14be50bb26f
urllib3>=1.26.5 # not directly required, pinned by Snyk to avoid a vulnerability
natsort==8.0.0
mistune>=2.0.1 # not directly required, pinned by Snyk to avoid a vulnerability

Loading…
Cancel
Save