diff --git a/cvat/apps/annotation/annotation.py b/cvat/apps/annotation/annotation.py index 70054255c242..97066fd40324 100644 --- a/cvat/apps/annotation/annotation.py +++ b/cvat/apps/annotation/annotation.py @@ -102,12 +102,12 @@ def reset(self): class Annotation: Attribute = namedtuple('Attribute', 'name, value') - LabeledShape = namedtuple('LabeledShape', 'type, frame, label, points, occluded, attributes, group, z_order') + LabeledShape = namedtuple('LabeledShape', 'type, frame, label, points, occluded, attributes, group, z_order, annotation_type') LabeledShape.__new__.__defaults__ = (0, 0) - TrackedShape = namedtuple('TrackedShape', 'type, points, occluded, frame, attributes, outside, keyframe, z_order') + TrackedShape = namedtuple('TrackedShape', 'type, points, occluded, frame, attributes, outside, keyframe, z_order, annotation_type') TrackedShape.__new__.__defaults__ = (0, ) Track = namedtuple('Track', 'label, group, shapes') - Tag = namedtuple('Tag', 'frame, label, attributes, group') + Tag = namedtuple('Tag', 'frame, label, attributes, group, annotation_type') Tag.__new__.__defaults__ = (0, ) Frame = namedtuple('Frame', 'frame, name, width, height, labeled_shapes, tags') @@ -278,6 +278,7 @@ def _export_tracked_shape(self, shape): keyframe=shape.get("keyframe", True), z_order=shape["z_order"], attributes=self._export_attributes(shape["attributes"]), + annotation_type=shape.get("annotation_type", "Manual"), ) def _export_labeled_shape(self, shape): @@ -290,6 +291,7 @@ def _export_labeled_shape(self, shape): z_order=shape.get("z_order", 0), group=shape.get("group", 0), attributes=self._export_attributes(shape["attributes"]), + annotation_type=shape.get("annotation_type", "Manual"), ) def _export_tag(self, tag): @@ -298,6 +300,7 @@ def _export_tag(self, tag): label=self._get_label_name(tag["label_id"]), group=tag.get("group", 0), attributes=self._export_attributes(tag["attributes"]), + annotation_type=tag.get("annotation_type", "Manual"), ) def group_by_frame(self): diff --git a/cvat/apps/annotation/cvat.py b/cvat/apps/annotation/cvat.py index 4e89f2a437c1..4048ae409bd1 100644 --- a/cvat/apps/annotation/cvat.py +++ b/cvat/apps/annotation/cvat.py @@ -202,6 +202,7 @@ def dump_as_cvat_annotation(file_object, annotations): dump_data = OrderedDict([ ("label", shape.label), ("occluded", str(int(shape.occluded))), + ("annotation_type", shape.annotation_type), ]) if shape.type == "rectangle": @@ -281,6 +282,7 @@ def dump_as_cvat_annotation(file_object, annotations): for tag in frame_annotation.tags: tag_data = OrderedDict([ ("label", tag.label), + ("annotation_type", tag.annotation_type), ]) if tag.group: tag_data["group_id"] = str(tag.group) @@ -407,6 +409,7 @@ def dump_track(idx, track): z_order=shape.z_order, frame=shape.frame, attributes=shape.attributes, + annotation_type=shape.annotation_type, ), annotations.TrackedShape( type=shape.type, @@ -417,6 +420,7 @@ def dump_track(idx, track): z_order=shape.z_order, frame=shape.frame + annotations.frame_step, attributes=shape.attributes, + annotation_type=shape.annotation_type, ), ], )) @@ -461,6 +465,7 @@ def load(file_object, annotations): 'label': el.attrib['label'], 'group': int(el.attrib.get('group_id', 0)), 'attributes': attributes, + 'annotation_type': el.attrib["annotation_type"], } elif ev == 'end': if el.tag == 'attribute' and attributes is not None: @@ -481,6 +486,7 @@ def load(file_object, annotations): shape['type'] = 'rectangle' if el.tag == 'box' else el.tag shape['occluded'] = el.attrib['occluded'] == '1' shape['z_order'] = int(el.attrib.get('z_order', 0)) + shape['annotation_type'] = el.attrib.get('annotation_type', 'Manual') if el.tag == 'box': shape['points'].append(el.attrib['xtl']) diff --git a/cvat/apps/engine/annotation.py b/cvat/apps/engine/annotation.py index acb9a6d5e349..10aac8d62514 100644 --- a/cvat/apps/engine/annotation.py +++ b/cvat/apps/engine/annotation.py @@ -479,6 +479,7 @@ def _init_tags_from_db(self): 'frame', 'label_id', 'group', + 'annotation_type', 'labeledimageattributeval__spec_id', 'labeledimageattributeval__value', 'labeledimageattributeval__id', @@ -516,6 +517,7 @@ def _init_shapes_from_db(self): 'occluded', 'z_order', 'points', + 'annotation_type', 'labeledshapeattributeval__spec_id', 'labeledshapeattributeval__value', 'labeledshapeattributeval__id', @@ -549,6 +551,7 @@ def _init_tracks_from_db(self): "frame", "label_id", "group", + "annotation_type", "labeledtrackattributeval__spec_id", "labeledtrackattributeval__value", "labeledtrackattributeval__id", diff --git a/cvat/apps/engine/models.py b/cvat/apps/engine/models.py index a513cf5a107e..afaca544549a 100644 --- a/cvat/apps/engine/models.py +++ b/cvat/apps/engine/models.py @@ -258,12 +258,24 @@ def choices(self): def __str__(self): return self.value +class AnnotationType(str, Enum): + AUTO = 'Auto' + MANUAL = 'Manual' + + @classmethod + def choices(self): + return tuple((x.value, x.name) for x in self) + + def __str__(self): + return self.value + class Annotation(models.Model): id = models.BigAutoField(primary_key=True) job = models.ForeignKey(Job, on_delete=models.CASCADE) label = models.ForeignKey(Label, on_delete=models.CASCADE) frame = models.PositiveIntegerField() group = models.PositiveIntegerField(null=True) + annotation_type = models.CharField(max_length=16, choices=AnnotationType.choices(), default="Manual", null=True) class Meta: abstract = True diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index e225dd23da6f..a8e3e2cde8f2 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -363,6 +363,7 @@ class AnnotationSerializer(serializers.Serializer): frame = serializers.IntegerField(min_value=0) label_id = serializers.IntegerField(min_value=0) group = serializers.IntegerField(min_value=0, allow_null=True) + annotation_type = serializers.CharField(default = 'Manual') class LabeledImageSerializer(AnnotationSerializer): attributes = AttributeValSerializer(many=True, diff --git a/cvat/apps/tf_annotation/views.py b/cvat/apps/tf_annotation/views.py index 4aa0589cae63..0ccf90e1962a 100644 --- a/cvat/apps/tf_annotation/views.py +++ b/cvat/apps/tf_annotation/views.py @@ -188,6 +188,7 @@ def convert_to_cvat_format(data): "group": None, "occluded": False, "attributes": [], + "annotation_type": "Auto", }) return result