diff --git a/CHANGELOG.md b/CHANGELOG.md index 431512d1eac8..101f5a8483db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.1.0-beta] - Unreleased ### Added -- +- Source type support for tags, shapes and tracks () +- Source type support for CVAT Dumper/Loader () ### Changed - Smaller object details () diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 6a99b7b06299..7194b0da767d 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -189,7 +189,7 @@ export class CanvasViewImpl implements CanvasView, Listener { } private onEditDone(state: any, points: number[]): void { - if (state && points) { + if (state && points) { const event: CustomEvent = new CustomEvent('canvas.edited', { bubbles: false, cancelable: true, @@ -1732,14 +1732,14 @@ export class CanvasViewImpl implements CanvasView, Listener { private addText(state: any): SVG.Text { const { undefinedAttrValue } = this.configuration; - const { label, clientID, attributes } = state; + const { label, clientID, attributes, source } = state; const attrNames = label.attributes.reduce((acc: any, val: any): void => { acc[val.id] = val.name; return acc; }, {}); return this.adoptedText.text((block): void => { - block.tspan(`${label.name} ${clientID}`).style('text-transform', 'uppercase'); + block.tspan(`${label.name} ${clientID} (${source})`).style('text-transform', 'uppercase'); for (const attrID of Object.keys(attributes)) { const value = attributes[attrID] === undefinedAttrValue ? '' : attributes[attrID]; diff --git a/cvat-core/src/annotations-collection.js b/cvat-core/src/annotations-collection.js index 5dd851074d44..ed338f6b37bd 100644 --- a/cvat-core/src/annotations-collection.js +++ b/cvat-core/src/annotations-collection.js @@ -402,6 +402,7 @@ frame: Math.min.apply(null, Object.keys(keyframes).map((frame) => +frame)), shapes: Object.values(keyframes), group: 0, + source: objectStates[0].source, label_id: label.id, attributes: Object.keys(objectStates[0].attributes) .reduce((accumulator, attrID) => { @@ -763,6 +764,7 @@ points: [...state.points], type: state.shapeType, z_order: state.zOrder, + source: state.source, }); } else if (state.objectType === 'track') { constructed.tracks.push({ @@ -770,6 +772,7 @@ .filter((attr) => !labelAttributes[attr.spec_id].mutable), frame: state.frame, group: 0, + source: state.source, label_id: state.label.id, shapes: [{ attributes: attributes diff --git a/cvat-core/src/annotations-objects.js b/cvat-core/src/annotations-objects.js index cb86542e75e6..de02f8de6a65 100644 --- a/cvat-core/src/annotations-objects.js +++ b/cvat-core/src/annotations-objects.js @@ -183,6 +183,7 @@ this.removed = false; this.lock = false; this.color = color; + this.source = data.source; this.updated = Date.now(); this.attributes = data.attributes.reduce((attributeAccumulator, attr) => { attributeAccumulator[attr.spec_id] = attr.value; @@ -295,6 +296,21 @@ }, [this.clientID], frame); } + _saveSource(source, frame) { + const undoSource = this.source; + const redoSource = source; + + this.history.do(HistoryActions.CHANGED_SOURCE, () => { + this.source = undoSource; + this.updated = Date.now(); + }, () => { + this.source = redoSource; + this.updated = Date.now(); + }, [this.clientID], frame); + + this.source = source; + } + _validateStateBeforeSave(frame, data, updated) { let fittedPoints = []; @@ -381,6 +397,10 @@ } } + if (updated.source) { + checkObjectType('source', data.source, 'string', null); + } + return fittedPoints; } @@ -396,7 +416,8 @@ updateTimestamp(updated) { const anyChanges = updated.label || updated.attributes || updated.points || updated.outside || updated.occluded || updated.keyframe - || updated.zOrder || updated.hidden || updated.lock || updated.pinned; + || updated.zOrder || updated.hidden || updated.lock || updated.pinned + || updated.source; if (anyChanges) { this.updated = Date.now(); @@ -492,6 +513,7 @@ frame: this.frame, label_id: this.label.id, group: this.group, + source: this.source, }; } @@ -520,6 +542,7 @@ updated: this.updated, pinned: this.pinned, frame, + source: this.source, }; } @@ -619,6 +642,10 @@ this._saveHidden(data.hidden, frame); } + if (updated.source) { + this._saveSource(data.source, frame); + } + this.updateTimestamp(updated); updated.reset(); @@ -659,6 +686,7 @@ frame: this.frame, label_id: this.label.id, group: this.group, + source: this.source, attributes: Object.keys(this.attributes).reduce((attributeAccumulator, attrId) => { if (!labelAttributes[attrId].mutable) { attributeAccumulator.push({ @@ -726,6 +754,7 @@ last, }, frame, + source: this.source, }; } @@ -1034,6 +1063,7 @@ outside: current.outside, occluded: current.occluded, attributes: {}, + source: current.source, } : undefined; if (redoShape) { @@ -1098,6 +1128,10 @@ this._saveAttributes(data.attributes, frame); } + if (updated.source) { + this._saveSource(data.source, frame); + } + if (updated.keyframe) { this._saveKeyframe(frame, data.keyframe); } @@ -1164,6 +1198,7 @@ frame: this.frame, label_id: this.label.id, group: this.group, + source: this.source, attributes: Object.keys(this.attributes).reduce((attributeAccumulator, attrId) => { attributeAccumulator.push({ spec_id: attrId, @@ -1194,6 +1229,7 @@ color: this.color, updated: this.updated, frame, + source: this.source, }; } @@ -1228,6 +1264,10 @@ this._saveColor(data.color, frame); } + if (updated.source) { + this._saveSource(data.source, frame); + } + this.updateTimestamp(updated); updated.reset(); diff --git a/cvat-core/src/annotations-saver.js b/cvat-core/src/annotations-saver.js index 42a07ecb39d4..779db776c0a5 100644 --- a/cvat-core/src/annotations-saver.js +++ b/cvat-core/src/annotations-saver.js @@ -104,7 +104,7 @@ const keys = ['id', 'label_id', 'group', 'frame', 'occluded', 'z_order', 'points', 'type', 'shapes', - 'attributes', 'value', 'spec_id', 'outside']; + 'attributes', 'value', 'spec_id', 'source', 'outside']; // Find created and updated objects for (const type of Object.keys(exported)) { diff --git a/cvat-core/src/api.js b/cvat-core/src/api.js index 0e04c5c8fc64..df6622f57610 100644 --- a/cvat-core/src/api.js +++ b/cvat-core/src/api.js @@ -31,6 +31,7 @@ function build() { LogType, HistoryActions, colors, + source, } = require('./enums'); const { @@ -531,6 +532,7 @@ function build() { LogType, HistoryActions, colors, + source, }, /** * Namespace is used for access to exceptions diff --git a/cvat-core/src/enums.js b/cvat-core/src/enums.js index 1c91de235ebc..894760cfee32 100644 --- a/cvat-core/src/enums.js +++ b/cvat-core/src/enums.js @@ -104,6 +104,20 @@ CUBOID: 'cuboid', }); + /** + * Annotation type + * @enum {string} + * @name source + * @memberof module:API.cvat.enums + * @property {string} MANUAL 'manual' + * @property {string} AUTO 'auto' + * @readonly + */ + const source = Object.freeze({ + MANUAL:'manual', + AUTO:'auto', +}); + /** * Logger event types * @enum {string} @@ -190,6 +204,7 @@ * @property {string} CHANGED_LOCK Changed lock * @property {string} CHANGED_COLOR Changed color * @property {string} CHANGED_HIDDEN Changed hidden + * @property {string} CHANGED_SOURCE Changed source * @property {string} MERGED_OBJECTS Merged objects * @property {string} SPLITTED_TRACK Splitted track * @property {string} GROUPED_OBJECTS Grouped objects @@ -209,6 +224,7 @@ CHANGED_PINNED: 'Changed pinned', CHANGED_COLOR: 'Changed color', CHANGED_HIDDEN: 'Changed hidden', + CHANGED_SOURCE: 'Changed source', MERGED_OBJECTS: 'Merged objects', SPLITTED_TRACK: 'Splitted track', GROUPED_OBJECTS: 'Grouped objects', @@ -241,5 +257,6 @@ LogType, HistoryActions, colors, + source, }; })(); diff --git a/cvat-core/src/object-state.js b/cvat-core/src/object-state.js index 93d17d4827a3..1b3e4c483a03 100644 --- a/cvat-core/src/object-state.js +++ b/cvat-core/src/object-state.js @@ -22,7 +22,7 @@ *
Necessary fields: objectType, shapeType, frame, updated, group *
Optional fields: keyframes, clientID, serverID *
Optional fields which can be set later: points, zOrder, outside, - * occluded, hidden, attributes, lock, label, color, keyframe + * occluded, hidden, attributes, lock, label, color, keyframe, source */ constructor(serialized) { const data = { @@ -39,6 +39,7 @@ color: null, hidden: null, pinned: null, + source: null, keyframes: serialized.keyframes, group: serialized.group, updated: serialized.updated, @@ -68,6 +69,7 @@ this.lock = false; this.color = false; this.hidden = false; + this.source = false; return reset; }, @@ -109,6 +111,20 @@ */ get: () => data.shapeType, }, + source: { + /** + * @name source + * @type {module:API.cvat.enums.source} + * @memberof module:API.cvat.classes.ObjectState + * @readonly + * @instance + */ + get: () => data.source, + set: (source) => { + data.updateFlags.source = true; + data.source = source; + }, + }, clientID: { /** * @name clientID @@ -343,6 +359,7 @@ this.label = serialized.label; this.lock = serialized.lock; + this.source = serialized.source; if (typeof (serialized.zOrder) === 'number') { this.zOrder = serialized.zOrder; diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index c78c871b9a81..5aa6c4575023 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -485,6 +485,7 @@ export function propagateObjectAsync( label: objectState.label, zOrder: objectState.zOrder, frame: from, + source: objectState.source, }; await sessionInstance.logger.log( diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx index b10cd3d6bfe8..4824a4428119 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -324,6 +324,7 @@ export default class CanvasWrapperComponent extends React.PureComponent { .filter((label: any) => label.id === activeLabelID)[0]; state.occluded = state.occluded || false; state.frame = frame; + state.source = 'manual'; const objectState = new cvat.classes.ObjectState(state); onCreateAnnotations(jobInstance, frame, [objectState]); }; @@ -500,6 +501,7 @@ export default class CanvasWrapperComponent extends React.PureComponent { points, } = event.detail; state.points = points; + state.source = 'manual'; onUpdateAnnotations([state]); }; diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index 392518119c22..7e20fc33f7e7 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -21,13 +21,13 @@ class TaskData: Attribute = namedtuple('Attribute', 'name, value') LabeledShape = namedtuple( - 'LabeledShape', 'type, frame, label, points, occluded, attributes, group, z_order') + 'LabeledShape', 'type, frame, label, points, occluded, attributes, source, group, z_order') LabeledShape.__new__.__defaults__ = (0, 0) TrackedShape = namedtuple( - 'TrackedShape', 'type, frame, points, occluded, outside, keyframe, attributes, group, z_order, label, track_id') - TrackedShape.__new__.__defaults__ = (0, 0, None, 0) - Track = namedtuple('Track', 'label, group, shapes') - Tag = namedtuple('Tag', 'frame, label, attributes, group') + 'TrackedShape', 'type, frame, points, occluded, outside, keyframe, attributes, source, group, z_order, label, track_id') + TrackedShape.__new__.__defaults__ = ('manual', 0, 0, None, 0) + Track = namedtuple('Track', 'label, group, source, shapes') + Tag = namedtuple('Tag', 'frame, label, attributes, source, group') Tag.__new__.__defaults__ = (0, ) Frame = namedtuple( 'Frame', 'idx, frame, name, width, height, labeled_shapes, tags') @@ -217,6 +217,7 @@ def _export_tracked_shape(self, shape): outside=shape.get("outside", False), keyframe=shape.get("keyframe", True), track_id=shape["track_id"], + source=shape.get("source", "manual"), attributes=self._export_attributes(shape["attributes"]), ) @@ -229,6 +230,7 @@ def _export_labeled_shape(self, shape): occluded=shape["occluded"], z_order=shape.get("z_order", 0), group=shape.get("group", 0), + source=shape["source"], attributes=self._export_attributes(shape["attributes"]), ) @@ -237,6 +239,7 @@ def _export_tag(self, tag): frame=self.abs_frame_id(tag["frame"]), label=self._get_label_name(tag["label_id"]), group=tag.get("group", 0), + source=tag["source"], attributes=self._export_attributes(tag["attributes"]), ) @@ -290,11 +293,13 @@ def tracks(self): tracked_shape["attributes"] += track["attributes"] tracked_shape["track_id"] = idx tracked_shape["group"] = track["group"] + tracked_shape["source"] = track["source"] tracked_shape["label_id"] = track["label_id"] yield TaskData.Track( label=self._get_label_name(track["label_id"]), group=track["group"], + source=track["source"], shapes=[self._export_tracked_shape(shape) for shape in tracked_shapes], ) @@ -650,6 +655,7 @@ def import_dm_annotations(dm_dataset, task_data): occluded=ann.attributes.get('occluded') == True, z_order=ann.z_order, group=group_map.get(ann.group, 0), + source='manual', attributes=[task_data.Attribute(name=n, value=str(v)) for n, v in ann.attributes.items()], )) @@ -658,6 +664,7 @@ def import_dm_annotations(dm_dataset, task_data): frame=frame_number, label=label_cat.items[ann.label].name, group=group_map.get(ann.group, 0), + source='manual', attributes=[task_data.Attribute(name=n, value=str(v)) for n, v in ann.attributes.items()], )) diff --git a/cvat/apps/dataset_manager/formats/cvat.py b/cvat/apps/dataset_manager/formats/cvat.py index a510582c19c6..ae1257c27081 100644 --- a/cvat/apps/dataset_manager/formats/cvat.py +++ b/cvat/apps/dataset_manager/formats/cvat.py @@ -190,6 +190,7 @@ def dump_as_cvat_annotation(file_object, annotations): dump_data = OrderedDict([ ("label", shape.label), ("occluded", str(int(shape.occluded))), + ("source", shape.source), ]) if shape.type == "rectangle": @@ -269,6 +270,7 @@ def dump_as_cvat_annotation(file_object, annotations): for tag in frame_annotation.tags: tag_data = OrderedDict([ ("label", tag.label), + ("source", tag.source), ]) if tag.group: tag_data["group_id"] = str(tag.group) @@ -294,6 +296,7 @@ def dump_track(idx, track): dump_data = OrderedDict([ ("id", str(track_id)), ("label", track.label), + ("source", track.source), ]) if track.group: @@ -385,6 +388,7 @@ def dump_track(idx, track): dump_track(counter, annotations.Track( label=shape.label, group=shape.group, + source=shape.source, shapes=[annotations.TrackedShape( type=shape.type, points=shape.points, @@ -430,6 +434,7 @@ def load(file_object, annotations): track = annotations.Track( label=el.attrib['label'], group=int(el.attrib.get('group_id', 0)), + source=el.attrib.get('source', 'manual'), shapes=[], ) elif el.tag == 'image': @@ -448,6 +453,7 @@ def load(file_object, annotations): 'label': el.attrib['label'], 'group': int(el.attrib.get('group_id', 0)), 'attributes': attributes, + 'source': str(el.attrib.get('source', 'manual')) } elif ev == 'end': if el.tag == 'attribute' and attributes is not None: @@ -464,6 +470,7 @@ def load(file_object, annotations): shape['frame'] = frame_id shape['label'] = el.attrib['label'] shape['group'] = int(el.attrib.get('group_id', 0)) + shape['source'] = str(el.attrib.get('source', 'manual')) shape['type'] = 'rectangle' if el.tag == 'box' else el.tag shape['occluded'] = el.attrib['occluded'] == '1' diff --git a/cvat/apps/dataset_manager/formats/mot.py b/cvat/apps/dataset_manager/formats/mot.py index 9e373ee5c8bd..b854ddb2b8bb 100644 --- a/cvat/apps/dataset_manager/formats/mot.py +++ b/cvat/apps/dataset_manager/formats/mot.py @@ -54,6 +54,7 @@ def _import(src_file, task_data): group=0, frame=frame_number, attributes=[], + source='manual', )) continue @@ -66,12 +67,13 @@ def _import(src_file, task_data): z_order=ann.z_order, frame=frame_number, attributes=[], + source='manual', ) # build trajectories as lists of shapes in track dict if track_id not in tracks: tracks[track_id] = task_data.Track( - label_cat.items[ann.label].name, 0, []) + label_cat.items[ann.label].name, 0, 'manual', []) tracks[track_id].shapes.append(shape) for track in tracks.values(): diff --git a/cvat/apps/dataset_manager/task.py b/cvat/apps/dataset_manager/task.py index 0d9985b724df..f2c40dfd0a17 100644 --- a/cvat/apps/dataset_manager/task.py +++ b/cvat/apps/dataset_manager/task.py @@ -381,6 +381,7 @@ def _init_tags_from_db(self): 'frame', 'label_id', 'group', + 'source', 'labeledimageattributeval__spec_id', 'labeledimageattributeval__value', 'labeledimageattributeval__id', @@ -415,6 +416,7 @@ def _init_shapes_from_db(self): 'type', 'frame', 'group', + 'source', 'occluded', 'z_order', 'points', @@ -451,6 +453,7 @@ def _init_tracks_from_db(self): "frame", "label_id", "group", + "source", "labeledtrackattributeval__spec_id", "labeledtrackattributeval__value", "labeledtrackattributeval__id", diff --git a/cvat/apps/dataset_manager/tests/_test_formats.py b/cvat/apps/dataset_manager/tests/_test_formats.py index 5dbee71c44c6..3b4ea5487ae0 100644 --- a/cvat/apps/dataset_manager/tests/_test_formats.py +++ b/cvat/apps/dataset_manager/tests/_test_formats.py @@ -163,6 +163,7 @@ def _generate_annotations(self, task): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -181,6 +182,7 @@ def _generate_annotations(self, task): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 300.222, 400, 500, 1, 3], "type": "polygon", @@ -190,6 +192,7 @@ def _generate_annotations(self, task): "frame": 1, "label_id": task["labels"][0]["id"], "group": 1, + "source": "manual", "attributes": [], "points": [100, 300.222, 400, 500, 1, 3], "type": "points", @@ -199,6 +202,7 @@ def _generate_annotations(self, task): "frame": 1, "label_id": task["labels"][0]["id"], "group": 1, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 400, 500, 1, 3], "type": "polyline", @@ -210,6 +214,7 @@ def _generate_annotations(self, task): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -244,6 +249,7 @@ def _generate_annotations(self, task): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "shapes": [ { diff --git a/cvat/apps/dataset_manager/tests/test_annotation.py b/cvat/apps/dataset_manager/tests/test_annotation.py index d27d07293d3b..580243a9cde3 100644 --- a/cvat/apps/dataset_manager/tests/test_annotation.py +++ b/cvat/apps/dataset_manager/tests/test_annotation.py @@ -13,6 +13,7 @@ def test_point_interpolation(self): "frame": 0, "label_id": 0, "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -44,6 +45,7 @@ def test_polygon_interpolation(self): "label_id": 0, "group": None, "attributes": [], + "source": "manual", "shapes": [ { "frame": 0, @@ -74,6 +76,7 @@ def test_bbox_interpolation(self): "label_id": 0, "group": None, "attributes": [], + "source": "manual", "shapes": [ { "frame": 0, @@ -104,6 +107,7 @@ def test_line_interpolation(self): "label_id": 0, "group": None, "attributes": [], + "source": "manual", "shapes": [ { "frame": 0, diff --git a/cvat/apps/engine/migrations/0027_auto_20200719_1552.py b/cvat/apps/engine/migrations/0027_auto_20200719_1552.py new file mode 100644 index 000000000000..4ffffd6ac905 --- /dev/null +++ b/cvat/apps/engine/migrations/0027_auto_20200719_1552.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.10 on 2020-07-19 15:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('engine', '0026_auto_20200719_1511'), + ] + + operations = [ + migrations.AddField( + model_name='labeledimage', + name='source', + field=models.CharField(choices=[('auto', 'AUTO'), ('manual', 'MANUAL')], default='manual', max_length=16, null=True), + ), + migrations.AddField( + model_name='labeledshape', + name='source', + field=models.CharField(choices=[('auto', 'AUTO'), ('manual', 'MANUAL')], default='manual', max_length=16, null=True), + ), + migrations.AddField( + model_name='labeledtrack', + name='source', + field=models.CharField(choices=[('auto', 'AUTO'), ('manual', 'MANUAL')], default='manual', max_length=16, null=True), + ), + ] diff --git a/cvat/apps/engine/models.py b/cvat/apps/engine/models.py index c43c12c5440e..d4c46eb3e264 100644 --- a/cvat/apps/engine/models.py +++ b/cvat/apps/engine/models.py @@ -302,12 +302,24 @@ def choices(cls): def __str__(self): return self.value +class source(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) + source = models.CharField(max_length=16, choices=source.choices(), default="manual", null=True) class Meta: abstract = True diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index 8d047e0d8f7d..90e24714c7d5 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -409,6 +409,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) + source = serializers.CharField(default = 'manual') class LabeledImageSerializer(AnnotationSerializer): attributes = AttributeValSerializer(many=True, diff --git a/cvat/apps/engine/tests/_test_rest_api.py b/cvat/apps/engine/tests/_test_rest_api.py index 44d8f32a9246..73c8114185ee 100644 --- a/cvat/apps/engine/tests/_test_rest_api.py +++ b/cvat/apps/engine/tests/_test_rest_api.py @@ -2100,6 +2100,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [] } ], @@ -2108,6 +2109,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2126,6 +2128,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 300.222, 400, 500, 1, 3], "type": "polygon", @@ -2137,6 +2140,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2171,6 +2175,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2220,6 +2225,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [] } ], @@ -2228,6 +2234,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2240,16 +2247,17 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): ], "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", - "occluded": False + "occluded": False, }, { "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 300.222, 400, 500, 1, 3], "type": "polygon", - "occluded": False + "occluded": False, }, ], "tracks": [ @@ -2257,6 +2265,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2283,7 +2292,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "points": [2.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": True, - "outside": True + "outside": True, }, ] }, @@ -2291,6 +2300,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2299,7 +2309,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": False, - "outside": False + "outside": False, } ] }, @@ -2361,7 +2371,8 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": 11010101, "group": None, - "attributes": [] + "source": "manual", + "attributes": [], } ], "shapes": [ @@ -2369,6 +2380,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": 32234234, @@ -2381,16 +2393,17 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): ], "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", - "occluded": False + "occluded": False, }, { "frame": 1, "label_id": 1212121, "group": None, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 300.222, 400, 500, 1, 3], "type": "polygon", - "occluded": False + "occluded": False, }, ], "tracks": [ @@ -2398,6 +2411,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": 0, "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2423,7 +2437,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "points": [2.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": True, - "outside": True + "outside": True, }, ] }, @@ -2431,6 +2445,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2439,7 +2454,7 @@ def _run_api_v1_jobs_id_annotations(self, owner, assignee, annotator): "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": False, - "outside": False + "outside": False, } ] }, @@ -2574,7 +2589,8 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, - "attributes": [] + "source": "manual", + "attributes": [], } ], "shapes": [ @@ -2582,6 +2598,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2594,16 +2611,17 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): ], "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", - "occluded": False + "occluded": False, }, { "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 300.222, 400, 500, 1, 3], "type": "polygon", - "occluded": False + "occluded": False, }, ], "tracks": [ @@ -2611,6 +2629,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2637,7 +2656,8 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "points": [2.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": True, - "outside": True + "outside": True, + }, ] }, @@ -2645,6 +2665,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2653,7 +2674,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": False, - "outside": False + "outside": False, } ] }, @@ -2694,7 +2715,8 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, - "attributes": [] + "source": "manual", + "attributes": [], } ], "shapes": [ @@ -2702,6 +2724,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2714,16 +2737,17 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): ], "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", - "occluded": False + "occluded": False, }, { "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 300.222, 400, 500, 1, 3], "type": "polygon", - "occluded": False + "occluded": False, }, ], "tracks": [ @@ -2731,6 +2755,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2757,7 +2782,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "points": [2.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": True, - "outside": True + "outside": True, }, ] }, @@ -2765,6 +2790,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2773,7 +2799,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": False, - "outside": False + "outside": False, } ] }, @@ -2835,7 +2861,8 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": 11010101, "group": None, - "attributes": [] + "source": "manual", + "attributes": [], } ], "shapes": [ @@ -2843,6 +2870,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": task["labels"][0]["id"], "group": None, + "source": "manual", "attributes": [ { "spec_id": 32234234, @@ -2855,16 +2883,17 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): ], "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", - "occluded": False + "occluded": False, }, { "frame": 1, "label_id": 1212121, "group": None, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 300.222, 400, 500, 1, 3], "type": "polygon", - "occluded": False + "occluded": False, }, ], "tracks": [ @@ -2872,6 +2901,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 0, "label_id": 0, "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2897,7 +2927,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "points": [2.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": True, - "outside": True + "outside": True, }, ] }, @@ -2905,6 +2935,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "frame": 1, "label_id": task["labels"][1]["id"], "group": None, + "source": "manual", "attributes": [], "shapes": [ { @@ -2913,7 +2944,7 @@ def _run_api_v1_tasks_id_annotations(self, owner, assignee, annotator): "points": [1.0, 2.1, 100, 300.222], "type": "rectangle", "occluded": False, - "outside": False + "outside": False, } ] }, @@ -2940,6 +2971,7 @@ def _get_initial_annotation(annotation_format): "frame": 0, "label_id": task["labels"][0]["id"], "group": 0, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -2992,6 +3024,7 @@ def _get_initial_annotation(annotation_format): "frame": 0, "label_id": task["labels"][1]["id"], "group": 0, + "source": "manual", "attributes": [], "shapes": [ { @@ -3000,7 +3033,7 @@ def _get_initial_annotation(annotation_format): "points": [1.0, 2.1, 50.2, 36.6], "type": "rectangle", "occluded": False, - "outside": False + "outside": False, }, { "frame": 1, @@ -3016,7 +3049,7 @@ def _get_initial_annotation(annotation_format): "points": [1.0, 2.1, 51, 36.6], "type": "rectangle", "occluded": False, - "outside": True + "outside": True, } ] }] @@ -3025,6 +3058,7 @@ def _get_initial_annotation(annotation_format): "frame": 0, "label_id": task["labels"][0]["id"], "group": 0, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -3037,33 +3071,36 @@ def _get_initial_annotation(annotation_format): ], "points": [1.0, 2.1, 10.6, 53.22], "type": "rectangle", - "occluded": False + "occluded": False, }] rectangle_shapes_wo_attrs = [{ "frame": 1, "label_id": task["labels"][1]["id"], "group": 0, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 40, 50.7], "type": "rectangle", - "occluded": False + "occluded": False, }] polygon_shapes_wo_attrs = [{ "frame": 1, "label_id": task["labels"][1]["id"], "group": 0, + "source": "manual", "attributes": [], "points": [2.0, 2.1, 100, 30.22, 40, 77, 1, 3], "type": "polygon", - "occluded": False + "occluded": False, }] polygon_shapes_with_attrs = [{ "frame": 2, "label_id": task["labels"][0]["id"], "group": 1, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], @@ -3076,28 +3113,31 @@ def _get_initial_annotation(annotation_format): ], "points": [20.0, 0.1, 10, 3.22, 4, 7, 10, 30, 1, 2, 4.44, 5.55], "type": "polygon", - "occluded": True + "occluded": True, }, { "frame": 2, "label_id": task["labels"][1]["id"], "group": 1, + "source": "manual", "attributes": [], "points": [4, 7, 10, 30, 4, 5.55], "type": "polygon", - "occluded": False + "occluded": False, }] tags_wo_attrs = [{ "frame": 2, "label_id": task["labels"][1]["id"], "group": 0, - "attributes": [] + "source": "manual", + "attributes": [], }] tags_with_attrs = [{ "frame": 1, "label_id": task["labels"][0]["id"], "group": 3, + "source": "manual", "attributes": [ { "spec_id": task["labels"][0]["attributes"][0]["id"], diff --git a/cvat/apps/tf_annotation/views.py b/cvat/apps/tf_annotation/views.py index 1c321f14440a..e112860e5219 100644 --- a/cvat/apps/tf_annotation/views.py +++ b/cvat/apps/tf_annotation/views.py @@ -174,6 +174,7 @@ def convert_to_cvat_format(data): "group": None, "occluded": False, "attributes": [], + "source": "auto", }) return result