Skip to content

Commit

Permalink
CVAT.js implemented API methods and bug fixes (#564)
Browse files Browse the repository at this point in the history
* Increase/decrease ZOrder

* ZOrder up/down

* Some crutial bugs fixed

* hasUnsavedChanges and merge

* Added API description

* Fixed bugs

* Merge was tested

* New file

* Fixed unit tests

* Fixed small bug which reproduced only after build
  • Loading branch information
bsekachev authored and nmanovic committed Jul 11, 2019
1 parent 3ae8a72 commit 0a2cb94
Show file tree
Hide file tree
Showing 10 changed files with 917 additions and 391 deletions.
351 changes: 274 additions & 77 deletions cvatjs/src/annotations-collection.js

Large diffs are not rendered by default.

161 changes: 90 additions & 71 deletions cvatjs/src/annotations-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,22 @@

(() => {
const ObjectState = require('./object-state');
const { checkObjectType } = require('./common');

// Called with the Annotation context
function objectStateFactory(frame, data) {
const objectState = new ObjectState(data);

// Rewrite default implementations of save/delete
objectState.updateInCollection = this.save.bind(this, frame, objectState);
objectState.deleteFromCollection = this.delete.bind(this);
objectState.hidden = {
save: this.save.bind(this, frame, objectState),
delete: this.delete.bind(this),
up: this.up.bind(this, frame, objectState),
down: this.down.bind(this, frame, objectState),
};

return objectState;
}

function checkObjectType(name, value, type, instance) {
if (type) {
if (typeof (value) !== type) {
// specific case for integers which aren't native type in JS
if (type === 'integer' && Number.isInteger(value)) {
return;
}

if (value !== undefined) {
throw new window.cvat.exceptions.ArgumentError(
`Got ${typeof (value)} value for ${name}. `
+ `Expected ${type}`,
);
}

throw new window.cvat.exceptions.ArgumentError(
`Got undefined value for ${name}. `
+ `Expected ${type}`,
);
}
} else if (instance) {
if (!(value instanceof instance)) {
if (value !== undefined) {
throw new window.cvat.exceptions.ArgumentError(
`Got ${value.constructor.name} value for ${name}. `
+ `Expected instance of ${instance.name}`,
);
}

throw new window.cvat.exceptions.ArgumentError(
`Got undefined value for ${name}. `
+ `Expected instance of ${instance.name}`,
);
}
}
}

class Annotation {
constructor(data, clientID, injection) {
this.taskLabels = injection.labels;
Expand Down Expand Up @@ -92,19 +60,73 @@
}
}

class Shape extends Annotation {
class Drawn extends Annotation {
constructor(data, clientID, color, injection) {
super(data, clientID, injection);

this.collectionZ = injection.collectionZ;
const z = this._getZ(this.frame);
z.max = Math.max(z.max, this.zOrder || 0);
z.min = Math.min(z.min, this.zOrder || 0);

this.color = color;
this.shapeType = null;
}

_getZ(frame) {
this.collectionZ[frame] = this.collectionZ[frame] || {
max: 0,
min: 0,
};

return this.collectionZ[frame];
}

save() {
throw window.cvat.exceptions.ScriptingError(
'Is not implemented',
);
}

get() {
throw window.cvat.exceptions.ScriptingError(
'Is not implemented',
);
}

toJSON() {
throw window.cvat.exceptions.ScriptingError(
'Is not implemented',
);
}

// Increase ZOrder within frame
up(frame, objectState) {
const z = this._getZ(frame);
z.max++;
objectState.zOrder = z.max;
}

// Decrease ZOrder within frame
down(frame, objectState) {
const z = this._getZ(frame);
z.min--;
objectState.zOrder = z.min;
}
}

class Shape extends Drawn {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.points = data.points;
this.occluded = data.occluded;
this.zOrder = data.z_order;
this.color = color;
this.shape = null;
}

// Method is used to export data to the server
toJSON() {
return {
type: this.shapeType,
clientID: this.clientID,
occluded: this.occluded,
z_order: this.zOrder,
Expand Down Expand Up @@ -133,9 +155,10 @@
}

return {
type: window.cvat.enums.ObjectType.SHAPE,
shape: this.shape,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: this.shapeType,
clientID: this.clientID,
serverID: this.serverID,
occluded: this.occluded,
lock: this.lock,
zOrder: this.zOrder,
Expand Down Expand Up @@ -232,34 +255,30 @@
}
}

class Track extends Annotation {
class Track extends Drawn {
constructor(data, clientID, color, injection) {
super(data, clientID, injection);
super(data, clientID, color, injection);
this.shapes = data.shapes.reduce((shapeAccumulator, value) => {
shapeAccumulator[value.frame] = {
serverID: value.id,
occluded: value.occluded,
zOrder: value.z_order,
points: value.points,
frame: value.frame,
outside: value.outside,
attributes: value.attributes.reduce((attributeAccumulator, attr) => {
attributeAccumulator[attr.spec_id] = attr.value;
return attributeAccumulator;
}, {}),
};

return shapeAccumulator;
}, {});
const z = this._getZ(value.frame);
z.max = Math.max(z.max, value.z_order);
z.min = Math.min(z.min, value.z_order);

this.attributes = data.attributes.reduce((attributeAccumulator, attr) => {
attributeAccumulator[attr.spec_id] = attr.value;
return attributeAccumulator;
return shapeAccumulator;
}, {});

this.cache = {};
this.color = color;
this.shape = null;
}

// Method is used to export data to the server
Expand All @@ -280,7 +299,7 @@
}, []),
shapes: Object.keys(this.shapes).reduce((shapesAccumulator, frame) => {
shapesAccumulator.push({
type: this.shape,
type: this.shapeType,
occluded: this.shapes[frame].occluded,
z_order: this.shapes[frame].zOrder,
points: [...this.shapes[frame].points],
Expand Down Expand Up @@ -312,9 +331,10 @@
attributes: this.getAttributes(frame),
label: this.label,
group: this.group,
type: window.cvat.enums.ObjectType.TRACK,
shape: this.shape,
objectType: window.cvat.enums.ObjectType.TRACK,
shapeType: this.shapeType,
clientID: this.clientID,
serverID: this.serverID,
lock: this.lock,
color: this.color,
},
Expand Down Expand Up @@ -630,8 +650,9 @@
}

return {
type: window.cvat.enums.ObjectType.TAG,
objectType: window.cvat.enums.ObjectType.TAG,
clientID: this.clientID,
serverID: this.serverID,
lock: this.lock,
attributes: Object.assign({}, this.attributes),
label: this.label,
Expand Down Expand Up @@ -697,7 +718,7 @@
class RectangleShape extends Shape {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.RECTANGLE;
this.shapeType = window.cvat.enums.ObjectShape.RECTANGLE;
}
}

Expand All @@ -710,28 +731,28 @@
class PolygonShape extends PolyShape {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.POLYGON;
this.shapeType = window.cvat.enums.ObjectShape.POLYGON;
}
}

class PolylineShape extends PolyShape {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.POLYLINE;
this.shapeType = window.cvat.enums.ObjectShape.POLYLINE;
}
}

class PointsShape extends PolyShape {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.POINTS;
this.shapeType = window.cvat.enums.ObjectShape.POINTS;
}
}

class RectangleTrack extends Track {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.RECTANGLE;
this.shapeType = window.cvat.enums.ObjectShape.RECTANGLE;
}

interpolatePosition(leftPosition, rightPosition, targetFrame) {
Expand Down Expand Up @@ -1142,25 +1163,21 @@
class PolygonTrack extends PolyTrack {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.POLYGON;
this.shapeType = window.cvat.enums.ObjectShape.POLYGON;
}
}

class PolylineTrack extends PolyTrack {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.POLYLINE;
}

appendMapping() {
// TODO after checking how it works with polygons
this.shapeType = window.cvat.enums.ObjectShape.POLYLINE;
}
}

class PointsTrack extends PolyTrack {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shape = window.cvat.enums.ObjectShape.POINTS;
this.shapeType = window.cvat.enums.ObjectShape.POINTS;
}
}

Expand All @@ -1173,6 +1190,8 @@
PolygonTrack,
PolylineTrack,
PointsTrack,
Track,
Shape,
Tag,
objectStateFactory,
};
Expand Down
9 changes: 6 additions & 3 deletions cvatjs/src/annotations-saver.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

class AnnotationsSaver {
constructor(version, collection, session) {
this.session = session.constructor.name.toLowerCase();
this.sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
this.id = session.id;
this.version = version;
this.collection = collection;
Expand Down Expand Up @@ -42,7 +42,7 @@

async _request(data, action) {
const result = await serverProxy.annotations.updateAnnotations(
this.session,
this.sessionType,
this.id,
data,
action,
Expand Down Expand Up @@ -249,14 +249,17 @@
delete this.initialObjects[object.id];
}
}

this.hash = this._getHash();
onUpdate('Saving is done');
} catch (error) {
onUpdate(`Can not save annotations: ${error.message}`);
throw error;
}
}

hasUnsavedChanges() {
return this._getHash() !== this._hash;
return this._getHash() !== this.hash;
}
}

Expand Down
Loading

0 comments on commit 0a2cb94

Please sign in to comment.