Skip to content

Commit eac18ff

Browse files
bsekachevnmanovic
authored andcommitted
Release 0.2.0 (#64)
* Move function from closure to class method * Bug has been fixed: Failed to execute 'inverse' on 'SVGMatrix': The matrix is not invertible * Performance of frame changing has been increased due to UI containers had detached from DOM before their items were created * Bug has been fixed: Defiant doesn't support dash (-) in xpath nodes (#53) * Data validation on client and server (#51) * Migration files have been added (#59) * Big int migration file has been rewritten with Django syntax (#60) * Some memory leaks have been fixed (#61)
1 parent a50b4cc commit eac18ff

17 files changed

+498
-163
lines changed

cvat/apps/engine/annotation.py

+37-7
Original file line numberDiff line numberDiff line change
@@ -761,14 +761,29 @@ def init_from_client(self, data):
761761
label = _Label(self.db_labels[int(path['label_id'])])
762762
boxes = []
763763
frame = -1
764+
765+
has_boxes_on_prev_segm = False
766+
last_box_on_prev_segm = None
767+
has_box_on_start_frame = False
768+
for box in path['shapes']:
769+
if int(box['frame']) < self.start_frame:
770+
has_boxes_on_prev_segm = True
771+
if last_box_on_prev_segm is None or int(last_box_on_prev_segm["frame"]) < int(box["frame"]):
772+
last_box_on_prev_segm = box
773+
elif int(box['frame']) == self.start_frame:
774+
has_box_on_start_frame = True
775+
break
776+
if has_boxes_on_prev_segm and not has_box_on_start_frame:
777+
last_box_on_prev_segm["frame"] = self.start_frame
778+
764779
for box in path['shapes']:
765-
if int(box['frame']) <= self.stop_frame:
780+
if int(box['frame']) <= self.stop_frame and int(box['frame']) >= self.start_frame:
766781
frame_idx = int(box['frame']) if db_task.mode == 'annotation' else 0
767782
xtl, ytl, xbr, ybr = self._clamp_box(float(box['xtl']), float(box['ytl']),
768783
float(box['xbr']), float(box['ybr']), image_meta['original_size'][frame_idx])
769784
tracked_box = _TrackedBox(xtl, ytl, xbr, ybr, int(box['frame']), strtobool(str(box['occluded'])),
770785
int(box['z_order']), strtobool(str(box['outside'])))
771-
assert tracked_box.frame > frame
786+
assert tracked_box.frame > frame
772787
frame = tracked_box.frame
773788

774789
for attr in box['attributes']:
@@ -780,7 +795,7 @@ def init_from_client(self, data):
780795
boxes.append(tracked_box)
781796
else:
782797
self.logger.error("init_from_client: ignore frame #%d " +
783-
"because stop_frame is %d", int(box['frame']), self.stop_frame)
798+
"because it out of segment range [%d-%d]", int(box['frame']), self.start_frame, self.stop_frame)
784799

785800
attributes = []
786801
for attr in path['attributes']:
@@ -790,7 +805,7 @@ def init_from_client(self, data):
790805
attributes.append(attr)
791806

792807
assert frame <= self.stop_frame
793-
box_path = _BoxPath(label, int(path['frame']), self.stop_frame,
808+
box_path = _BoxPath(label, min(list(map(lambda box: box.frame, boxes))), self.stop_frame,
794809
int(path['group_id']), boxes, attributes)
795810
self.box_paths.append(box_path)
796811

@@ -799,8 +814,23 @@ def init_from_client(self, data):
799814
label = _Label(self.db_labels[int(path['label_id'])])
800815
poly_shapes = []
801816
frame = -1
817+
818+
has_shapes_on_prev_segm = False
819+
last_shape_on_prev_segm = None
820+
has_shape_on_start_frame = False
821+
for poly_shape in path['shapes']:
822+
if int(poly_shape['frame']) < self.start_frame:
823+
has_shapes_on_prev_segm = True
824+
if last_shape_on_prev_segm is None or int(last_shape_on_prev_segm["frame"]) < (poly_shape["frame"]):
825+
last_shape_on_prev_segm = box
826+
elif int(poly_shape['frame']) == self.start_frame:
827+
has_shape_on_start_frame = True
828+
break
829+
if has_shapes_on_prev_segm and not has_shape_on_start_frame:
830+
last_shape_on_prev_segm["frame"] = self.start_frame
831+
802832
for poly_shape in path['shapes']:
803-
if int(poly_shape['frame']) <= self.stop_frame:
833+
if int(poly_shape['frame']) <= self.stop_frame and int(poly_shape['frame']) >= self.start_frame:
804834
frame_idx = int(poly_shape['frame']) if db_task.mode == 'annotation' else 0
805835
points = self._clamp_poly(poly_shape['points'], image_meta['original_size'][frame_idx])
806836
tracked_poly_shape = _TrackedPolyShape(points, int(poly_shape['frame']), strtobool(str(poly_shape['occluded'])),
@@ -817,7 +847,7 @@ def init_from_client(self, data):
817847
poly_shapes.append(tracked_poly_shape)
818848
else:
819849
self.logger.error("init_from_client: ignore frame #%d " +
820-
"because stop_frame is %d", int(poly_shape['frame']), self.stop_frame)
850+
"because it out of segment range [%d-%d]", int(poly_shape['frame']), self.start_frame, self.stop_frame)
821851

822852
attributes = []
823853
for attr in path['attributes']:
@@ -826,7 +856,7 @@ def init_from_client(self, data):
826856
attr = _Attribute(spec, str(attr['value']))
827857
attributes.append(attr)
828858

829-
poly_path = _PolyPath(label, int(path['frame']), self.stop_frame + 1,
859+
poly_path = _PolyPath(label, min(list(map(lambda shape: shape.frame, poly_shapes))), self.stop_frame + 1,
830860
int(path['group_id']), poly_shapes, attributes)
831861

832862
getattr(self, poly_path_type).append(poly_path)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 2.0.3 on 2018-09-17 11:24
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('engine', '0007_task_flipped'),
12+
]
13+
14+
operations = [
15+
migrations.AlterField(
16+
model_name='task',
17+
name='owner',
18+
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
19+
),
20+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Generated by Django 2.0.3 on 2018-09-17 11:24
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('engine', '0008_auto_20180917_1424'),
10+
]
11+
12+
13+
14+
operations = [
15+
migrations.AlterField(
16+
model_name='labeledbox',
17+
name='id',
18+
field=models.BigAutoField(primary_key=True, serialize=False),
19+
),
20+
migrations.AlterField(
21+
model_name='labeledboxattributeval',
22+
name='id',
23+
field=models.BigAutoField(primary_key=True, serialize=False),
24+
),
25+
migrations.AlterField(
26+
model_name='labeledpoints',
27+
name='id',
28+
field=models.BigAutoField(primary_key=True, serialize=False),
29+
),
30+
migrations.AlterField(
31+
model_name='labeledpointsattributeval',
32+
name='id',
33+
field=models.BigAutoField(primary_key=True, serialize=False),
34+
),
35+
migrations.AlterField(
36+
model_name='labeledpolygon',
37+
name='id',
38+
field=models.BigAutoField(primary_key=True, serialize=False),
39+
),
40+
migrations.AlterField(
41+
model_name='labeledpolygonattributeval',
42+
name='id',
43+
field=models.BigAutoField(primary_key=True, serialize=False),
44+
),
45+
migrations.AlterField(
46+
model_name='labeledpolyline',
47+
name='id',
48+
field=models.BigAutoField(primary_key=True, serialize=False),
49+
),
50+
migrations.AlterField(
51+
model_name='labeledpolylineattributeval',
52+
name='id',
53+
field=models.BigAutoField(primary_key=True, serialize=False),
54+
),
55+
migrations.AlterField(
56+
model_name='objectpath',
57+
name='id',
58+
field=models.BigAutoField(primary_key=True, serialize=False),
59+
),
60+
migrations.AlterField(
61+
model_name='objectpathattributeval',
62+
name='id',
63+
field=models.BigAutoField(primary_key=True, serialize=False),
64+
),
65+
migrations.AlterField(
66+
model_name='trackedbox',
67+
name='id',
68+
field=models.BigAutoField(primary_key=True, serialize=False),
69+
),
70+
migrations.AlterField(
71+
model_name='trackedboxattributeval',
72+
name='id',
73+
field=models.BigAutoField(primary_key=True, serialize=False),
74+
),
75+
migrations.AlterField(
76+
model_name='trackedpoints',
77+
name='id',
78+
field=models.BigAutoField(primary_key=True, serialize=False),
79+
),
80+
migrations.AlterField(
81+
model_name='trackedpointsattributeval',
82+
name='id',
83+
field=models.BigAutoField(primary_key=True, serialize=False),
84+
),
85+
migrations.AlterField(
86+
model_name='trackedpolygon',
87+
name='id',
88+
field=models.BigAutoField(primary_key=True, serialize=False),
89+
),
90+
migrations.AlterField(
91+
model_name='trackedpolygonattributeval',
92+
name='id',
93+
field=models.BigAutoField(primary_key=True, serialize=False),
94+
),
95+
migrations.AlterField(
96+
model_name='trackedpolyline',
97+
name='id',
98+
field=models.BigAutoField(primary_key=True, serialize=False),
99+
),
100+
migrations.AlterField(
101+
model_name='trackedpolylineattributeval',
102+
name='id',
103+
field=models.BigAutoField(primary_key=True, serialize=False),
104+
),
105+
migrations.AlterField(
106+
model_name='objectpathattributeval',
107+
name='track_id',
108+
field=models.BigIntegerField(),
109+
),
110+
migrations.AlterField(
111+
model_name='objectpathattributeval',
112+
name='track_id',
113+
field=models.BigIntegerField(),
114+
),
115+
migrations.AlterField(
116+
model_name='trackedpoints',
117+
name='track_id',
118+
field=models.BigIntegerField(),
119+
),
120+
migrations.AlterField(
121+
model_name='trackedpolygon',
122+
name='track_id',
123+
field=models.BigIntegerField(),
124+
),
125+
migrations.AlterField(
126+
model_name='trackedpolyline',
127+
name='track_id',
128+
field=models.BigIntegerField(),
129+
),
130+
migrations.AlterField(
131+
model_name='trackedboxattributeval',
132+
name='box_id',
133+
field=models.BigIntegerField(),
134+
),
135+
migrations.AlterField(
136+
model_name='trackedpointsattributeval',
137+
name='points_id',
138+
field=models.BigIntegerField(),
139+
),
140+
migrations.AlterField(
141+
model_name='trackedpolygonattributeval',
142+
name='polygon_id',
143+
field=models.BigIntegerField(),
144+
),
145+
migrations.AlterField(
146+
model_name='trackedpolylineattributeval',
147+
name='polyline_id',
148+
field=models.BigIntegerField(),
149+
),
150+
migrations.AlterField(
151+
model_name='labeledboxattributeval',
152+
name='box_id',
153+
field=models.BigIntegerField(),
154+
),
155+
migrations.AlterField(
156+
model_name='labeledpointsattributeval',
157+
name='points_id',
158+
field=models.BigIntegerField(),
159+
),
160+
migrations.AlterField(
161+
model_name='labeledpolygonattributeval',
162+
name='polygon_id',
163+
field=models.BigIntegerField(),
164+
),
165+
migrations.AlterField(
166+
model_name='labeledpolylineattributeval',
167+
name='polyline_id',
168+
field=models.BigIntegerField(),
169+
),
170+
]

cvat/apps/engine/models.py

+4
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def __str__(self):
128128

129129
class AttributeVal(models.Model):
130130
# TODO: add a validator here to be sure that it corresponds to self.label
131+
id = models.BigAutoField(primary_key=True)
131132
spec = models.ForeignKey(AttributeSpec, on_delete=models.CASCADE)
132133
value = models.CharField(max_length=64)
133134
class Meta:
@@ -148,6 +149,7 @@ class Meta:
148149
abstract = True
149150

150151
class BoundingBox(Shape):
152+
id = models.BigAutoField(primary_key=True)
151153
xtl = models.FloatField()
152154
ytl = models.FloatField()
153155
xbr = models.FloatField()
@@ -156,6 +158,7 @@ class Meta:
156158
abstract = True
157159

158160
class PolyShape(Shape):
161+
id = models.BigAutoField(primary_key=True)
159162
points = models.TextField()
160163
class Meta:
161164
abstract = True
@@ -185,6 +188,7 @@ class LabeledPointsAttributeVal(AttributeVal):
185188
points = models.ForeignKey(LabeledPoints, on_delete=models.CASCADE)
186189

187190
class ObjectPath(Annotation):
191+
id = models.BigAutoField(primary_key=True)
188192
shapes = models.CharField(max_length=10, default='boxes')
189193

190194
class ObjectPathAttributeVal(AttributeVal):

cvat/apps/engine/static/engine/base.css

+2-1
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,9 @@ html {
9898
border: none;
9999
outline: none;
100100
cursor: pointer;
101-
padding: 14px 16px;
101+
padding: 3px 0px;
102102
transition: 0.3s;
103+
103104
}
104105

105106
.tab button:hover {

0 commit comments

Comments
 (0)