Skip to content

Commit a7f7ff1

Browse files
authored
Merge pull request cvat-ai#5980 from opencv/hotfix-2.4.1
Hotfix for v2.4.0 -> Release v2.4.1
2 parents 61470b6 + 209b5b6 commit a7f7ff1

File tree

8 files changed

+81
-21
lines changed

8 files changed

+81
-21
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## \[2.4.1] - 2023-04-05
9+
### Fixed
10+
- Optimized annotation fetching up to 10 times (<https://github.com/opencv/cvat/pull/5974>)
11+
- Incorrect calculation of working time in analytics (<https://github.com/opencv/cvat/pull/5973>)
12+
813
## \[2.4.0] - 2023-03-16
914
### Added
1015
- \[SDK\] An arg to wait for data processing in the task data uploading function

cvat/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
from cvat.utils.version import get_version
66

7-
VERSION = (2, 4, 0, 'final', 0)
7+
VERSION = (2, 4, 1, 'final', 0)
88

99
__version__ = get_version(VERSION)

cvat/apps/dataset_manager/task.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ def _init_tags_from_db(self):
399399
self._extend_attributes(db_tag.labeledimageattributeval_set,
400400
self.db_attributes[db_tag.label_id]["all"].values())
401401

402-
serializer = serializers.LabeledImageSerializer(db_tags, many=True)
402+
serializer = serializers.LabeledImageSerializerFromDB(db_tags, many=True)
403403
self.ir_data.tags = serializer.data
404404

405405
def _init_shapes_from_db(self):
@@ -453,7 +453,7 @@ def _init_shapes_from_db(self):
453453
for shape_id, shape_elements in elements.items():
454454
shapes[shape_id].elements = shape_elements
455455

456-
serializer = serializers.LabeledShapeSerializer(list(shapes.values()), many=True)
456+
serializer = serializers.LabeledShapeSerializerFromDB(list(shapes.values()), many=True)
457457
self.ir_data.shapes = serializer.data
458458

459459
def _init_tracks_from_db(self):
@@ -546,7 +546,7 @@ def _init_tracks_from_db(self):
546546
for track_id, track_elements in elements.items():
547547
tracks[track_id].elements = track_elements
548548

549-
serializer = serializers.LabeledTrackSerializer(list(tracks.values()), many=True)
549+
serializer = serializers.LabeledTrackSerializerFromDB(list(tracks.values()), many=True)
550550
self.ir_data.tracks = serializer.data
551551

552552
def _init_version_from_db(self):

cvat/apps/engine/mixins.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from cvat.apps.engine.models import Location
1818
from cvat.apps.engine.location import StorageType, get_location_configuration
19-
from cvat.apps.engine.serializers import DataSerializer, LabeledDataSerializer
19+
from cvat.apps.engine.serializers import DataSerializer
2020
from cvat.apps.webhooks.signals import signal_update, signal_create, signal_delete
2121

2222
class TusFile:
@@ -278,9 +278,7 @@ def export_annotations(self, request, db_obj, export_func, callback, get_data=No
278278
return Response("Format is not specified",status=status.HTTP_400_BAD_REQUEST)
279279

280280
data = get_data(self._object.pk)
281-
serializer = LabeledDataSerializer(data=data)
282-
if serializer.is_valid(raise_exception=True):
283-
return Response(serializer.data)
281+
return Response(data)
284282

285283
def import_annotations(self, request, db_obj, import_func, rq_func, rq_id):
286284
is_tus_request = request.headers.get('Upload-Length', None) is not None or \

cvat/apps/engine/serializers.py

+57-1
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,6 @@ def run_child_validation(self, data):
11891189

11901190
raise exceptions.ValidationError(errors)
11911191

1192-
11931192
class ShapeSerializer(serializers.Serializer):
11941193
type = serializers.ChoiceField(choices=models.ShapeType.choices())
11951194
occluded = serializers.BooleanField(default=False)
@@ -1207,6 +1206,63 @@ class SubLabeledShapeSerializer(ShapeSerializer, AnnotationSerializer):
12071206
class LabeledShapeSerializer(SubLabeledShapeSerializer):
12081207
elements = SubLabeledShapeSerializer(many=True, required=False)
12091208

1209+
def _convert_annotation(obj, keys):
1210+
return OrderedDict([(key, obj[key]) for key in keys])
1211+
1212+
def _convert_attributes(attr_set):
1213+
attr_keys = ['spec_id', 'value']
1214+
return [
1215+
OrderedDict([(key, attr[key]) for key in attr_keys]) for attr in attr_set
1216+
]
1217+
1218+
class LabeledImageSerializerFromDB(serializers.BaseSerializer):
1219+
# Use this serializer to export data from the database
1220+
# Because default DRF serializer is too slow on huge collections
1221+
def to_representation(self, instance):
1222+
def convert_tag(tag):
1223+
result = _convert_annotation(tag, ['id', 'label_id', 'frame', 'group', 'source'])
1224+
result['attributes'] = _convert_attributes(tag['labeledimageattributeval_set'])
1225+
return result
1226+
1227+
return convert_tag(instance)
1228+
1229+
class LabeledShapeSerializerFromDB(serializers.BaseSerializer):
1230+
# Use this serializer to export data from the database
1231+
# Because default DRF serializer is too slow on huge collections
1232+
def to_representation(self, instance):
1233+
def convert_shape(shape):
1234+
result = _convert_annotation(shape, [
1235+
'id', 'label_id', 'type', 'frame', 'group', 'source',
1236+
'occluded', 'outside', 'z_order', 'rotation', 'points',
1237+
])
1238+
result['attributes'] = _convert_attributes(shape['labeledshapeattributeval_set'])
1239+
if shape.get('elements', None) is not None and shape['parent'] is None:
1240+
result['elements'] = [convert_shape(element) for element in shape['elements']]
1241+
return result
1242+
1243+
return convert_shape(instance)
1244+
1245+
class LabeledTrackSerializerFromDB(serializers.BaseSerializer):
1246+
# Use this serializer to export data from the database
1247+
# Because default DRF serializer is too slow on huge collections
1248+
def to_representation(self, instance):
1249+
def convert_track(track):
1250+
shape_keys = [
1251+
'id', 'type', 'frame', 'occluded', 'outside', 'z_order',
1252+
'rotation', 'points', 'trackedshapeattributeval_set',
1253+
]
1254+
result = _convert_annotation(track, ['id', 'label_id', 'frame', 'group', 'source'])
1255+
result['shapes'] = [_convert_annotation(shape, shape_keys) for shape in track['trackedshape_set']]
1256+
result['attributes'] = _convert_attributes(track['labeledtrackattributeval_set'])
1257+
for shape in result['shapes']:
1258+
shape['attributes'] = _convert_attributes(shape['trackedshapeattributeval_set'])
1259+
shape.pop('trackedshapeattributeval_set', None)
1260+
if track.get('elements', None) is not None and track['parent'] is None:
1261+
result['elements'] = [convert_track(element) for element in track['elements']]
1262+
return result
1263+
1264+
return convert_track(instance)
1265+
12101266
class TrackedShapeSerializer(ShapeSerializer):
12111267
id = serializers.IntegerField(default=None, allow_null=True)
12121268
frame = serializers.IntegerField(min_value=0)

cvat/apps/events/serializers.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class EventSerializer(serializers.Serializer):
3030
class ClientEventsSerializer(serializers.Serializer):
3131
events = EventSerializer(many=True, default=[])
3232
timestamp = serializers.DateTimeField()
33-
_TIME_THRESHOLD = 100 # seconds
33+
_TIME_THRESHOLD = datetime.timedelta(seconds=100)
34+
_WORKING_TIME_RESOLUTION = datetime.timedelta(milliseconds=1)
3435

3536
def to_internal_value(self, data):
3637
request = self.context.get("request")
@@ -47,12 +48,12 @@ def to_internal_value(self, data):
4748
timestamp = datetime_parser.isoparse(event['timestamp'])
4849
if last_timestamp:
4950
t_diff = timestamp - last_timestamp
50-
if t_diff.seconds < self._TIME_THRESHOLD:
51+
if t_diff < self._TIME_THRESHOLD:
5152
payload = event.get('payload', {})
5253
if payload:
5354
payload = json.loads(payload)
5455

55-
payload['working_time'] = t_diff.microseconds // 1000
56+
payload['working_time'] = t_diff // self._WORKING_TIME_RESOLUTION
5657
payload['username'] = request.user.username
5758
event['payload'] = json.dumps(payload)
5859

docker-compose.yml

+7-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ services:
2525

2626
cvat_server:
2727
container_name: cvat_server
28-
image: cvat/server:${CVAT_VERSION:-v2.4.0}
28+
image: cvat/server:${CVAT_VERSION:-v2.4.1}
2929
restart: always
3030
depends_on:
3131
- cvat_redis
@@ -63,7 +63,7 @@ services:
6363

6464
cvat_utils:
6565
container_name: cvat_utils
66-
image: cvat/server:${CVAT_VERSION:-v2.4.0}
66+
image: cvat/server:${CVAT_VERSION:-v2.4.1}
6767
restart: always
6868
depends_on:
6969
- cvat_redis
@@ -84,7 +84,7 @@ services:
8484

8585
cvat_worker_import:
8686
container_name: cvat_worker_import
87-
image: cvat/server:${CVAT_VERSION:-v2.4.0}
87+
image: cvat/server:${CVAT_VERSION:-v2.4.1}
8888
restart: always
8989
depends_on:
9090
- cvat_redis
@@ -106,7 +106,7 @@ services:
106106

107107
cvat_worker_export:
108108
container_name: cvat_worker_export
109-
image: cvat/server:${CVAT_VERSION:-v2.4.0}
109+
image: cvat/server:${CVAT_VERSION:-v2.4.1}
110110
restart: always
111111
depends_on:
112112
- cvat_redis
@@ -127,7 +127,7 @@ services:
127127

128128
cvat_worker_annotation:
129129
container_name: cvat_worker_annotation
130-
image: cvat/server:${CVAT_VERSION:-v2.4.0}
130+
image: cvat/server:${CVAT_VERSION:-v2.4.1}
131131
restart: always
132132
depends_on:
133133
- cvat_redis
@@ -148,7 +148,7 @@ services:
148148

149149
cvat_worker_webhooks:
150150
container_name: cvat_worker_webhooks
151-
image: cvat/server:${CVAT_VERSION:-v2.4.0}
151+
image: cvat/server:${CVAT_VERSION:-v2.4.1}
152152
restart: always
153153
depends_on:
154154
- cvat_redis
@@ -169,7 +169,7 @@ services:
169169

170170
cvat_ui:
171171
container_name: cvat_ui
172-
image: cvat/ui:${CVAT_VERSION:-v2.4.0}
172+
image: cvat/ui:${CVAT_VERSION:-v2.4.1}
173173
restart: always
174174
depends_on:
175175
- cvat_server

helm-chart/values.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ cvat:
7575
additionalVolumeMounts: []
7676
replicas: 1
7777
image: cvat/server
78-
tag: v2.4.0
78+
tag: v2.4.1
7979
imagePullPolicy: Always
8080
permissionFix:
8181
enabled: true
@@ -95,7 +95,7 @@ cvat:
9595
frontend:
9696
replicas: 1
9797
image: cvat/ui
98-
tag: v2.4.0
98+
tag: v2.4.1
9999
imagePullPolicy: Always
100100
labels: {}
101101
# test: test

0 commit comments

Comments
 (0)