supervisely 6.73.452__py3-none-any.whl → 6.73.513__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. supervisely/__init__.py +25 -1
  2. supervisely/annotation/annotation.py +8 -2
  3. supervisely/annotation/json_geometries_map.py +13 -12
  4. supervisely/api/annotation_api.py +6 -3
  5. supervisely/api/api.py +2 -0
  6. supervisely/api/app_api.py +10 -1
  7. supervisely/api/dataset_api.py +74 -12
  8. supervisely/api/entities_collection_api.py +10 -0
  9. supervisely/api/entity_annotation/figure_api.py +28 -0
  10. supervisely/api/entity_annotation/object_api.py +3 -3
  11. supervisely/api/entity_annotation/tag_api.py +63 -12
  12. supervisely/api/guides_api.py +210 -0
  13. supervisely/api/image_api.py +4 -0
  14. supervisely/api/labeling_job_api.py +83 -1
  15. supervisely/api/labeling_queue_api.py +33 -7
  16. supervisely/api/module_api.py +5 -0
  17. supervisely/api/project_api.py +71 -26
  18. supervisely/api/storage_api.py +3 -1
  19. supervisely/api/task_api.py +13 -2
  20. supervisely/api/team_api.py +4 -3
  21. supervisely/api/video/video_annotation_api.py +119 -3
  22. supervisely/api/video/video_api.py +65 -14
  23. supervisely/app/__init__.py +1 -1
  24. supervisely/app/content.py +23 -7
  25. supervisely/app/development/development.py +18 -2
  26. supervisely/app/fastapi/__init__.py +1 -0
  27. supervisely/app/fastapi/custom_static_files.py +1 -1
  28. supervisely/app/fastapi/multi_user.py +105 -0
  29. supervisely/app/fastapi/subapp.py +88 -42
  30. supervisely/app/fastapi/websocket.py +77 -9
  31. supervisely/app/singleton.py +21 -0
  32. supervisely/app/v1/app_service.py +18 -2
  33. supervisely/app/v1/constants.py +7 -1
  34. supervisely/app/widgets/__init__.py +6 -0
  35. supervisely/app/widgets/activity_feed/__init__.py +0 -0
  36. supervisely/app/widgets/activity_feed/activity_feed.py +239 -0
  37. supervisely/app/widgets/activity_feed/style.css +78 -0
  38. supervisely/app/widgets/activity_feed/template.html +22 -0
  39. supervisely/app/widgets/card/card.py +20 -0
  40. supervisely/app/widgets/classes_list_selector/classes_list_selector.py +121 -9
  41. supervisely/app/widgets/classes_list_selector/template.html +60 -93
  42. supervisely/app/widgets/classes_mapping/classes_mapping.py +13 -12
  43. supervisely/app/widgets/classes_table/classes_table.py +1 -0
  44. supervisely/app/widgets/deploy_model/deploy_model.py +56 -35
  45. supervisely/app/widgets/ecosystem_model_selector/ecosystem_model_selector.py +1 -1
  46. supervisely/app/widgets/experiment_selector/experiment_selector.py +8 -0
  47. supervisely/app/widgets/fast_table/fast_table.py +184 -60
  48. supervisely/app/widgets/fast_table/template.html +1 -1
  49. supervisely/app/widgets/heatmap/__init__.py +0 -0
  50. supervisely/app/widgets/heatmap/heatmap.py +564 -0
  51. supervisely/app/widgets/heatmap/script.js +533 -0
  52. supervisely/app/widgets/heatmap/style.css +233 -0
  53. supervisely/app/widgets/heatmap/template.html +21 -0
  54. supervisely/app/widgets/modal/__init__.py +0 -0
  55. supervisely/app/widgets/modal/modal.py +198 -0
  56. supervisely/app/widgets/modal/template.html +10 -0
  57. supervisely/app/widgets/object_class_view/object_class_view.py +3 -0
  58. supervisely/app/widgets/radio_tabs/radio_tabs.py +18 -2
  59. supervisely/app/widgets/radio_tabs/template.html +1 -0
  60. supervisely/app/widgets/select/select.py +6 -3
  61. supervisely/app/widgets/select_class/__init__.py +0 -0
  62. supervisely/app/widgets/select_class/select_class.py +363 -0
  63. supervisely/app/widgets/select_class/template.html +50 -0
  64. supervisely/app/widgets/select_cuda/select_cuda.py +22 -0
  65. supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +65 -7
  66. supervisely/app/widgets/select_tag/__init__.py +0 -0
  67. supervisely/app/widgets/select_tag/select_tag.py +352 -0
  68. supervisely/app/widgets/select_tag/template.html +64 -0
  69. supervisely/app/widgets/select_team/select_team.py +37 -4
  70. supervisely/app/widgets/select_team/template.html +4 -5
  71. supervisely/app/widgets/select_user/__init__.py +0 -0
  72. supervisely/app/widgets/select_user/select_user.py +270 -0
  73. supervisely/app/widgets/select_user/template.html +13 -0
  74. supervisely/app/widgets/select_workspace/select_workspace.py +59 -10
  75. supervisely/app/widgets/select_workspace/template.html +9 -12
  76. supervisely/app/widgets/table/table.py +68 -13
  77. supervisely/app/widgets/tree_select/tree_select.py +2 -0
  78. supervisely/aug/aug.py +6 -2
  79. supervisely/convert/base_converter.py +1 -0
  80. supervisely/convert/converter.py +2 -2
  81. supervisely/convert/image/image_converter.py +3 -1
  82. supervisely/convert/image/image_helper.py +48 -4
  83. supervisely/convert/image/label_studio/label_studio_converter.py +2 -0
  84. supervisely/convert/image/medical2d/medical2d_helper.py +2 -24
  85. supervisely/convert/image/multispectral/multispectral_converter.py +6 -0
  86. supervisely/convert/image/pascal_voc/pascal_voc_converter.py +8 -5
  87. supervisely/convert/image/pascal_voc/pascal_voc_helper.py +7 -0
  88. supervisely/convert/pointcloud/kitti_3d/kitti_3d_converter.py +33 -3
  89. supervisely/convert/pointcloud/kitti_3d/kitti_3d_helper.py +12 -5
  90. supervisely/convert/pointcloud/las/las_converter.py +13 -1
  91. supervisely/convert/pointcloud/las/las_helper.py +110 -11
  92. supervisely/convert/pointcloud/nuscenes_conv/nuscenes_converter.py +27 -16
  93. supervisely/convert/pointcloud/pointcloud_converter.py +91 -3
  94. supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_converter.py +58 -22
  95. supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_helper.py +21 -47
  96. supervisely/convert/video/__init__.py +1 -0
  97. supervisely/convert/video/multi_view/__init__.py +0 -0
  98. supervisely/convert/video/multi_view/multi_view.py +543 -0
  99. supervisely/convert/video/sly/sly_video_converter.py +359 -3
  100. supervisely/convert/video/video_converter.py +22 -2
  101. supervisely/convert/volume/dicom/dicom_converter.py +13 -5
  102. supervisely/convert/volume/dicom/dicom_helper.py +30 -18
  103. supervisely/geometry/constants.py +1 -0
  104. supervisely/geometry/geometry.py +4 -0
  105. supervisely/geometry/helpers.py +5 -1
  106. supervisely/geometry/oriented_bbox.py +676 -0
  107. supervisely/geometry/rectangle.py +2 -1
  108. supervisely/io/env.py +76 -1
  109. supervisely/io/fs.py +21 -0
  110. supervisely/nn/benchmark/base_evaluator.py +104 -11
  111. supervisely/nn/benchmark/instance_segmentation/evaluator.py +1 -8
  112. supervisely/nn/benchmark/object_detection/evaluator.py +20 -4
  113. supervisely/nn/benchmark/object_detection/vis_metrics/pr_curve.py +10 -5
  114. supervisely/nn/benchmark/semantic_segmentation/evaluator.py +34 -16
  115. supervisely/nn/benchmark/semantic_segmentation/vis_metrics/confusion_matrix.py +1 -1
  116. supervisely/nn/benchmark/semantic_segmentation/vis_metrics/frequently_confused.py +1 -1
  117. supervisely/nn/benchmark/semantic_segmentation/vis_metrics/overview.py +1 -1
  118. supervisely/nn/benchmark/visualization/evaluation_result.py +66 -4
  119. supervisely/nn/inference/cache.py +43 -18
  120. supervisely/nn/inference/gui/serving_gui_template.py +5 -2
  121. supervisely/nn/inference/inference.py +795 -199
  122. supervisely/nn/inference/inference_request.py +42 -9
  123. supervisely/nn/inference/predict_app/gui/classes_selector.py +83 -12
  124. supervisely/nn/inference/predict_app/gui/gui.py +676 -488
  125. supervisely/nn/inference/predict_app/gui/input_selector.py +205 -26
  126. supervisely/nn/inference/predict_app/gui/model_selector.py +2 -4
  127. supervisely/nn/inference/predict_app/gui/output_selector.py +46 -6
  128. supervisely/nn/inference/predict_app/gui/settings_selector.py +756 -59
  129. supervisely/nn/inference/predict_app/gui/tags_selector.py +1 -1
  130. supervisely/nn/inference/predict_app/gui/utils.py +236 -119
  131. supervisely/nn/inference/predict_app/predict_app.py +2 -2
  132. supervisely/nn/inference/session.py +43 -35
  133. supervisely/nn/inference/tracking/bbox_tracking.py +113 -34
  134. supervisely/nn/inference/tracking/tracker_interface.py +7 -2
  135. supervisely/nn/inference/uploader.py +139 -12
  136. supervisely/nn/live_training/__init__.py +7 -0
  137. supervisely/nn/live_training/api_server.py +111 -0
  138. supervisely/nn/live_training/artifacts_utils.py +243 -0
  139. supervisely/nn/live_training/checkpoint_utils.py +229 -0
  140. supervisely/nn/live_training/dynamic_sampler.py +44 -0
  141. supervisely/nn/live_training/helpers.py +14 -0
  142. supervisely/nn/live_training/incremental_dataset.py +146 -0
  143. supervisely/nn/live_training/live_training.py +497 -0
  144. supervisely/nn/live_training/loss_plateau_detector.py +111 -0
  145. supervisely/nn/live_training/request_queue.py +52 -0
  146. supervisely/nn/model/model_api.py +9 -0
  147. supervisely/nn/prediction_dto.py +12 -1
  148. supervisely/nn/tracker/base_tracker.py +11 -1
  149. supervisely/nn/tracker/botsort/botsort_config.yaml +0 -1
  150. supervisely/nn/tracker/botsort/tracker/mc_bot_sort.py +7 -4
  151. supervisely/nn/tracker/botsort_tracker.py +94 -65
  152. supervisely/nn/tracker/visualize.py +87 -90
  153. supervisely/nn/training/gui/classes_selector.py +16 -1
  154. supervisely/nn/training/train_app.py +28 -29
  155. supervisely/project/data_version.py +115 -51
  156. supervisely/project/download.py +1 -1
  157. supervisely/project/pointcloud_episode_project.py +37 -8
  158. supervisely/project/pointcloud_project.py +30 -2
  159. supervisely/project/project.py +14 -2
  160. supervisely/project/project_meta.py +27 -1
  161. supervisely/project/project_settings.py +32 -18
  162. supervisely/project/versioning/__init__.py +1 -0
  163. supervisely/project/versioning/common.py +20 -0
  164. supervisely/project/versioning/schema_fields.py +35 -0
  165. supervisely/project/versioning/video_schema.py +221 -0
  166. supervisely/project/versioning/volume_schema.py +87 -0
  167. supervisely/project/video_project.py +717 -15
  168. supervisely/project/volume_project.py +623 -5
  169. supervisely/template/experiment/experiment.html.jinja +4 -4
  170. supervisely/template/experiment/experiment_generator.py +14 -21
  171. supervisely/template/live_training/__init__.py +0 -0
  172. supervisely/template/live_training/header.html.jinja +96 -0
  173. supervisely/template/live_training/live_training.html.jinja +51 -0
  174. supervisely/template/live_training/live_training_generator.py +464 -0
  175. supervisely/template/live_training/sly-style.css +402 -0
  176. supervisely/template/live_training/template.html.jinja +18 -0
  177. supervisely/versions.json +28 -26
  178. supervisely/video/sampling.py +39 -20
  179. supervisely/video/video.py +40 -11
  180. supervisely/video_annotation/video_object.py +29 -4
  181. supervisely/volume/stl_converter.py +2 -0
  182. supervisely/worker_api/agent_rpc.py +24 -1
  183. supervisely/worker_api/rpc_servicer.py +31 -7
  184. {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/METADATA +56 -39
  185. {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/RECORD +189 -142
  186. {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/WHEEL +1 -1
  187. {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/entry_points.txt +0 -0
  188. {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info/licenses}/LICENSE +0 -0
  189. {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,402 @@
1
+ .experiment-body .sly-markdown-widget .markdown-body {
2
+ padding: 0;
3
+ font-family: inherit;
4
+ }
5
+
6
+ .experiment-body .sly-markdown-widget .markdown-body h2 {
7
+ font-size: 18px;
8
+ font-weight: 600;
9
+ margin-bottom: 0px;
10
+ border: 0;
11
+ }
12
+
13
+ .experiment-body .sly-markdown-widget .markdown-body h3 {
14
+ color: #949bab;
15
+ font-size: 18px;
16
+ margin-bottom: 7px;
17
+ }
18
+
19
+ .experiment-body .sly-markdown-widget .markdown-body p {
20
+ margin-bottom: 12px;
21
+ }
22
+
23
+ .experiment-body .section {
24
+ margin-bottom: 30px;
25
+ scroll-margin-top: 20px;
26
+ padding-top: 10px;
27
+ }
28
+
29
+ .experiment-body .overview-info-block {
30
+ background: #f4f7fb;
31
+ border-radius: 12px;
32
+ padding: 20px;
33
+ margin-bottom: 20px;
34
+ }
35
+
36
+ .experiment-body .width-fit-content {
37
+ width: fit-content;
38
+ }
39
+
40
+ .experiment-body .main-content {
41
+ flex-grow: 1;
42
+ margin-right: 20px;
43
+ }
44
+
45
+ .experiment-body .buttons-container {
46
+ display: flex;
47
+ flex-wrap: wrap;
48
+ gap: 10px;
49
+ margin-bottom: 20px;
50
+ }
51
+
52
+ .experiment-body hr {
53
+ display: none
54
+ }
55
+
56
+ .experiment-body blockquote {
57
+ margin: 15px 0 0;
58
+ }
59
+
60
+ .experiment-body table {
61
+ width: 100%;
62
+ border-collapse: collapse;
63
+ margin-bottom: 20px;
64
+ }
65
+
66
+ .experiment-body table th,
67
+ .experiment-body table td {
68
+ border: 1px solid #e0e0e0;
69
+ padding: 8px 12px;
70
+ text-align: left;
71
+ }
72
+
73
+ .experiment-body table th {
74
+ background-color: #f4f7fb;
75
+ }
76
+
77
+ .experiment-body .table {
78
+ width: 100%;
79
+ border-collapse: collapse;
80
+ margin-bottom: 20px;
81
+ /* box-shadow: 0 2px 6px rgba(0,0,0,0.05); */
82
+ border-radius: 6px;
83
+ overflow: hidden;
84
+ }
85
+
86
+ .experiment-body .table th {
87
+ background-color: #f4f7fb;
88
+ font-weight: 600;
89
+ color: #333;
90
+ padding: 12px 15px;
91
+ text-align: left;
92
+ border-bottom: 2px solid #e0e0e0;
93
+ }
94
+
95
+ .experiment-body .table td {
96
+ padding: 10px 15px;
97
+ border-bottom: 1px solid #e9ecef;
98
+ }
99
+
100
+ .experiment-body .table tr:hover {
101
+ background-color: #f8f9fa;
102
+ }
103
+
104
+ .experiment-body .links-list,
105
+ .experiment-body .overview-list,
106
+ .experiment-body .buttons-list {
107
+ list-style-type: none;
108
+ padding: 0;
109
+ margin: 0 0 20px 0;
110
+ }
111
+
112
+ .experiment-body .links-list li,
113
+ .experiment-body .overview-list li,
114
+ .experiment-body .buttons-list li {
115
+ margin-bottom: 8px;
116
+ position: relative;
117
+ padding-left: 8px;
118
+ display: flex;
119
+ align-items: flex-start;
120
+ }
121
+
122
+ .experiment-body .links-list li:before,
123
+ .experiment-body .buttons-list li:before {
124
+ content: "•";
125
+ color: #1890ff;
126
+ display: inline-block;
127
+ width: 15px;
128
+ margin-right: 10px;
129
+ }
130
+
131
+ .experiment-body .overview-list li:before {
132
+ content: "";
133
+ display: none;
134
+ }
135
+
136
+ .experiment-body .link-icon,
137
+ .experiment-body .button-icon {
138
+ margin-right: 8px;
139
+ }
140
+
141
+ .experiment-body .overview-list .label {
142
+ font-weight: 600;
143
+ margin-right: 8px;
144
+ min-width: 120px;
145
+ display: inline-block;
146
+ }
147
+
148
+ /* Code */
149
+ .experiment-body .code-block {
150
+ background-color: #f5f5f5;
151
+ border-radius: 6px;
152
+ padding: 15px;
153
+ margin-bottom: 20px;
154
+ overflow-x: auto;
155
+ }
156
+
157
+ .experiment-body details {
158
+ border-radius: 6px;
159
+ overflow: hidden;
160
+ margin-bottom: 20px;
161
+ }
162
+
163
+ .experiment-body details summary {
164
+ padding: 12px 15px;
165
+ background-color: #f4f7fb;
166
+ border-radius: 6px;
167
+ cursor: pointer;
168
+ font-weight: 600;
169
+ transition: background-color 0.2s;
170
+ width: fit-content;
171
+ }
172
+
173
+ .experiment-body details summary:hover {
174
+ background-color: #e6edf7;
175
+ }
176
+
177
+ .experiment-body details[open] summary {
178
+ border-bottom-left-radius: 0;
179
+ border-bottom-right-radius: 0;
180
+ margin-bottom: 10px;
181
+ }
182
+
183
+ /* Classes overview styles */
184
+ .classes-overview {
185
+ margin-bottom: 30px;
186
+ }
187
+
188
+ .class-tags {
189
+ display: flex;
190
+ flex-wrap: wrap;
191
+ gap: 8px;
192
+ margin-top: 12px;
193
+ }
194
+
195
+ .class-tag {
196
+ background: #e3e8ef;
197
+ color: #434a53;
198
+ padding: 3px 7px;
199
+ border-radius: 4px;
200
+ font-size: 12px;
201
+ font-weight: 400;
202
+ }
203
+
204
+
205
+ .experiment-main-wrapper {
206
+ display: flex;
207
+ }
208
+
209
+ .experiment-main-content .main-content.markdown-body {
210
+ font-size: 14px;
211
+ font-family: inherit;
212
+ }
213
+
214
+ .experiment-main-content .main-content.markdown-body h2 {
215
+ font-size: 18px;
216
+ font-weight: 700;
217
+ /* border: 0;
218
+ padding: 0; */
219
+ }
220
+
221
+ .experiment-main-content .main-content.markdown-body h3 {
222
+ font-size: 16px;
223
+ font-weight: 700;
224
+ border: 0;
225
+ }
226
+
227
+ .experiment-main-content .main-content.markdown-body .img-grid-gallery-v2-header {
228
+ font-size: 13px;
229
+ }
230
+
231
+ /*********************** Header ***********************/
232
+
233
+ .experiment-body .experiment-info-header {
234
+ background: #f8fafc;
235
+ border-radius: 6px;
236
+ font-size: 14px;
237
+ }
238
+
239
+ .experiment-body .experiment-info-header h1 {
240
+ margin: 0;
241
+ font-size: 18px;
242
+ font-weight: 700;
243
+ padding: 0;
244
+ border: 0;
245
+ }
246
+
247
+ .experiment-body .experiment-info-header ul {
248
+ list-style: none;
249
+ padding: 0;
250
+ margin: 0;
251
+ }
252
+
253
+ .experiment-body .experiment-info-header .experiment-info-subheader {
254
+ display: flex;
255
+ background: #f1f5f9;
256
+ padding: 15px 20px;
257
+ justify-content: space-between;
258
+ align-items: center;
259
+ border-radius: 6px 6px 0 0;
260
+ }
261
+
262
+ .experiment-body .experiment-info-header .experiment-info-subheader-body {
263
+ padding: 15px 20px;
264
+ display: flex;
265
+ gap: 30px;
266
+ }
267
+
268
+ .experiment-body .experiment-info-header .experiment-info-subheader-body h2 {
269
+ border: 0;
270
+ margin: 0;
271
+ font-size: 16px;
272
+ font-weight: 700;
273
+ margin-right: 5px;
274
+ }
275
+
276
+ .experiment-body .experiment-info-header .experiment-info-subheader-body ul strong {
277
+ width: 100px;
278
+ }
279
+
280
+ .experiment-body .experiment-info-header .experiment-info-subheader-block {
281
+ padding-right: 30px;
282
+ border-right: 1px solid #dde4ef;
283
+ }
284
+
285
+ /*.experiment-body .experiment-info-header .experiment-info-subheader-block:nth-last-child(2) { border: none; flex: 1; }*/
286
+
287
+ .experiment-body .experiment-info-header .experiment-info-subheader-block:last-child {
288
+ border: none;
289
+ }
290
+
291
+ .experiment-body .experiment-info-header .experiment-info-subheader-block .experiment-info-subheader-mini-title {
292
+ display: flex;
293
+ align-items: center;
294
+ gap: 3px;
295
+ margin: 0 0 6px;
296
+ }
297
+
298
+ .experiment-body .experiment-info-header .experiment-info-subheader-block .experiment-info-subheader-mini-title a {
299
+ padding: 2px 6px;
300
+ border: 1px solid #ccd3d9;
301
+ border-radius: 6px;
302
+ font-size: 12px;
303
+ cursor: pointer;
304
+ background: white;
305
+ /*color: #1a6cdb;*/
306
+ color: black;
307
+ margin-left: 3px;
308
+ margin-top: -2px;
309
+ }
310
+
311
+ .experiment-body .experiment-info-header .experiment-info-buttons {
312
+ display: flex;
313
+ gap: 5px;
314
+ align-items: center;
315
+ }
316
+
317
+ .experiment-body .experiment-info-header .experiment-info-buttons a, .training-plots-button {
318
+ display: flex;
319
+ gap: 5px;
320
+ align-items: center;
321
+ background: white;
322
+ padding: 7px 13px;
323
+ border: 1px solid #ccd3d9;
324
+ border-radius: 6px;
325
+ font-size: 13px;
326
+ font-weight: 600;
327
+ cursor: pointer;
328
+ }
329
+
330
+
331
+ .experiment-body .experiment-info-header .experiment-info-buttons a.primary, .training-plots-button {
332
+ background: black;
333
+ color: white;
334
+ }
335
+
336
+ .experiment-body .experiment-info-header .experiment-info-buttons img {
337
+ height: 16px;
338
+ width: auto;
339
+ background: transparent;
340
+ }
341
+
342
+ .experiment-body .training-plots-button {
343
+ display: inline-block;
344
+ }
345
+
346
+ /*********************** Metrics ***********************/
347
+
348
+ .experiment-body .experiment-metric {
349
+ font-size: 13px;
350
+ display: flex;
351
+ align-items: center;
352
+ justify-content: space-between;
353
+ }
354
+
355
+ .experiment-body .experiment-metric .experiment-label {
356
+ width: 100px;
357
+ font-weight: 600;
358
+ }
359
+
360
+ .experiment-body .experiment-metric .experiment-value {
361
+ margin-right: 5px;
362
+ text-align: right;
363
+ }
364
+
365
+ .experiment-body .experiment-progress-bar {
366
+ background: #eee;
367
+ height: 6px;
368
+ border-radius: 6px;
369
+ overflow: hidden;
370
+ width: 90px;
371
+ }
372
+
373
+ .experiment-body .experiment-progress {
374
+ height: 100%;
375
+ background: #28a745;
376
+ }
377
+
378
+ .experiment-body .experiment-info-header .experiment-info-subheader-footer-menu {
379
+ display: flex;
380
+ gap: 5px;
381
+ margin: 0px 20px;
382
+ padding-top: 5px;
383
+ border-top: 1px solid #dde4ef;
384
+ font-size: 14px;
385
+ }
386
+
387
+ .experiment-body .experiment-info-header .experiment-info-subheader-footer-menu a {
388
+ line-height: 36px;
389
+ padding: 0 7px;
390
+ color: black;
391
+ border-bottom: 2px solid transparent;
392
+ }
393
+
394
+ .experiment-body .experiment-info-header .experiment-info-subheader-footer-menu a:hover {
395
+ text-decoration: none;
396
+ }
397
+
398
+ .experiment-body .experiment-info-header .experiment-info-subheader-footer-menu a.active {
399
+ border-color: #20a0ff;
400
+ font-weight: 500;
401
+ color: #20a0ff;
402
+ }
@@ -0,0 +1,18 @@
1
+ <div class="experiment-body">
2
+ <sly-style>
3
+ {% include "sly-style.css" %}
4
+ </sly-style>
5
+
6
+ <div class="experiment-main-wrapper">
7
+ <!-- Main content -->
8
+ <div class="experiment-main-content">
9
+ <div class="main-content markdown-body">
10
+ {% include "header.html.jinja" %}
11
+
12
+ {% markdown %}
13
+ {% include "live_training.html.jinja" %}
14
+ {% endmarkdown %}
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </div>
supervisely/versions.json CHANGED
@@ -1,28 +1,30 @@
1
1
  {
2
- "6.9.11": "6.72.70",
3
- "6.9.13": "6.73.76",
4
- "6.9.18": "6.73.81",
5
- "6.9.22": "6.73.90",
6
- "6.9.31": "6.73.123",
7
- "6.10.0": "6.73.126",
8
- "6.11.8": "6.73.159",
9
- "6.11.10": "6.73.166",
10
- "6.11.16": "6.73.184",
11
- "6.11.19": "6.73.199",
12
- "6.12.2": "6.73.222",
13
- "6.12.5": "6.73.226",
14
- "6.12.12": "6.73.241",
15
- "6.12.17": "6.73.263",
16
- "6.12.23": "6.73.281",
17
- "6.12.28": "6.73.292",
18
- "6.12.30": "6.73.312",
19
- "6.12.34": "6.73.324",
20
- "6.12.44": "6.73.344",
21
- "6.12.46": "6.73.375",
22
- "6.13.1": "6.73.379",
23
- "6.13.8": "6.73.394",
24
- "6.14.0": "6.73.400",
25
- "6.14.4": "6.73.410",
26
- "6.15.0": "6.73.431",
27
- "6.15.2": "6.73.433"
2
+ "6.9.11": "6.72.70",
3
+ "6.9.13": "6.73.76",
4
+ "6.9.18": "6.73.81",
5
+ "6.9.22": "6.73.90",
6
+ "6.9.31": "6.73.123",
7
+ "6.10.0": "6.73.126",
8
+ "6.11.8": "6.73.159",
9
+ "6.11.10": "6.73.166",
10
+ "6.11.16": "6.73.184",
11
+ "6.11.19": "6.73.199",
12
+ "6.12.2": "6.73.222",
13
+ "6.12.5": "6.73.226",
14
+ "6.12.12": "6.73.241",
15
+ "6.12.17": "6.73.263",
16
+ "6.12.23": "6.73.281",
17
+ "6.12.28": "6.73.292",
18
+ "6.12.30": "6.73.312",
19
+ "6.12.34": "6.73.324",
20
+ "6.12.44": "6.73.344",
21
+ "6.12.46": "6.73.375",
22
+ "6.13.1": "6.73.379",
23
+ "6.13.8": "6.73.394",
24
+ "6.14.0": "6.73.400",
25
+ "6.14.4": "6.73.410",
26
+ "6.15.0": "6.73.431",
27
+ "6.15.2": "6.73.433",
28
+ "6.15.35": "6.73.483",
29
+ "6.15.40": "6.73.493"
28
30
  }
@@ -103,7 +103,6 @@ def _upload_annotations(api: Api, image_ids, frame_indices, video_annotation: Vi
103
103
  api.annotation.upload_anns(image_ids, anns=anns)
104
104
 
105
105
 
106
-
107
106
  def _upload_frames(
108
107
  api: Api,
109
108
  frames: List[np.ndarray],
@@ -226,28 +225,48 @@ def sample_video(
226
225
  progress.miniters = 1
227
226
  progress.refresh()
228
227
 
229
- with VideoFrameReader(video_path, frame_indices) as reader:
230
- for batch in batched_iter(zip(reader, frame_indices), 10):
231
- frames, indices = zip(*batch)
232
- for frame in frames:
228
+ batch_size = 50
229
+ try:
230
+ with VideoFrameReader(video_path, frame_indices) as reader:
231
+ for batch_indices in batched_iter(frame_indices, batch_size):
232
+ batch_indices_list = list(batch_indices)
233
+ frames = reader.read_batch(batch_indices_list)
234
+
233
235
  if resize:
234
- cv2.resize(frame, [*resize, frame.shape[2]], interpolation=cv2.INTER_LINEAR)
236
+ resized_frames = []
237
+ for frame in frames:
238
+ resized_frame = cv2.resize(
239
+ frame,
240
+ (resize[1], resize[0]), # (width, height)
241
+ interpolation=cv2.INTER_LINEAR,
242
+ )
243
+ resized_frames.append(resized_frame)
244
+ frames = resized_frames
245
+
246
+ image_ids = _upload_frames(
247
+ api=api,
248
+ frames=frames,
249
+ video_name=video_info.name,
250
+ video_frames_count=video_info.frames_count,
251
+ indices=batch_indices_list,
252
+ dataset_id=dst_dataset_info.id,
253
+ sample_info=sample_info,
254
+ context=context,
255
+ copy_annotations=copy_annotations,
256
+ video_annotation=video_annotation,
257
+ )
235
258
 
236
- image_ids = _upload_frames(
237
- api=api,
238
- frames=frames,
239
- video_name=video_info.name,
240
- video_frames_count=video_info.frames_count,
241
- indices=indices,
242
- dataset_id=dst_dataset_info.id,
243
- sample_info=sample_info,
244
- context=context,
245
- copy_annotations=copy_annotations,
246
- video_annotation=video_annotation,
247
- )
259
+ if progress is not None:
260
+ progress.update(len(image_ids))
248
261
 
249
- if progress is not None:
250
- progress.update(len(image_ids))
262
+ # Free memory after each batch
263
+ del frames
264
+ if resize:
265
+ del resized_frames
266
+ finally:
267
+ import os
268
+ if os.path.exists(video_path):
269
+ os.remove(video_path)
251
270
 
252
271
 
253
272
  def _get_or_create_dst_dataset(
@@ -4,7 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import os
7
- from typing import Dict, Generator, List, Optional, Tuple
7
+ from typing import Dict, Generator, Iterable, List, Optional, Tuple
8
8
 
9
9
  import cv2
10
10
  import numpy as np
@@ -537,11 +537,9 @@ class VideoFrameReader:
537
537
  try:
538
538
  import decord
539
539
 
540
- self.vr = decord.VideoReader(str(self.video_path))
540
+ self.vr = decord.VideoReader(str(self.video_path), num_threads=1)
541
541
  except ImportError:
542
- default_logger.debug(
543
- "Decord is not installed. Falling back to OpenCV for video reading."
544
- )
542
+ default_logger.debug("Decord is not installed. Falling back to OpenCV for video reading.")
545
543
  self.cap = cv2.VideoCapture(str(self.video_path))
546
544
 
547
545
  def close(self):
@@ -562,24 +560,30 @@ class VideoFrameReader:
562
560
  def __del__(self):
563
561
  self.close()
564
562
 
565
- def iterate_frames(self, frame_indexes: List[int] = None) -> Generator[np.ndarray, None, None]:
563
+ def iterate_frames(self, frame_indexes: Optional[List[int]] = None) -> Generator[np.ndarray, None, None]:
566
564
  self._ensure_initialized()
567
565
  if frame_indexes is None:
568
566
  frame_indexes = self.frame_indexes
569
567
  if self.vr is not None:
568
+ # Decord
570
569
  if frame_indexes is None:
571
570
  frame_indexes = range(len(self.vr))
572
- for frame_index in frame_indexes:
573
- frame = self.vr[frame_index]
574
- yield frame.asnumpy()
571
+ for idx in frame_indexes:
572
+ arr = self.vr[idx].asnumpy()
573
+ yield arr
574
+ del arr
575
575
  else:
576
+ # OpenCV fallback
576
577
  if frame_indexes is None:
577
578
  frame_count = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
578
579
  frame_indexes = range(frame_count)
579
580
  for frame_index in frame_indexes:
580
- if 1 > frame_index - self.prev_idx < 20:
581
+ if 1 < frame_index - self.prev_idx < 20:
581
582
  while self.prev_idx < frame_index - 1:
582
- self.cap.read()
583
+ ok, _ = self.cap.read()
584
+ if not ok:
585
+ break
586
+ self.prev_idx += 1
583
587
  if frame_index != self.prev_idx + 1:
584
588
  self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_index)
585
589
  ret, frame = self.cap.read()
@@ -588,6 +592,17 @@ class VideoFrameReader:
588
592
  yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
589
593
  self.prev_idx = frame_index
590
594
 
595
+ def read_batch(self, frame_indexes: List[int]) -> List[np.ndarray]:
596
+ self._ensure_initialized()
597
+ if self.vr is not None:
598
+ batch_nd = self.vr.get_batch(frame_indexes)
599
+ batch_np = batch_nd.asnumpy()
600
+ frames = [batch_np[i].copy() for i in range(batch_np.shape[0])]
601
+ del batch_np
602
+ return frames
603
+ else:
604
+ return list(self.iterate_frames(frame_indexes))
605
+
591
606
  def read_frames(self, frame_indexes: List[int] = None) -> List[np.ndarray]:
592
607
  return list(self.iterate_frames(frame_indexes))
593
608
 
@@ -625,3 +640,17 @@ class VideoFrameReader:
625
640
  return self.vr.get_avg_fps()
626
641
  else:
627
642
  return int(self.cap.get(cv2.CAP_PROP_FPS))
643
+
644
+
645
+ def create_from_frames(frames: Iterable[np.ndarray], output_path: str, fps: int = 30) -> None:
646
+ video_writer = None
647
+ for frame in frames:
648
+ if video_writer is None:
649
+ height, width, _ = frame.shape
650
+ fourcc = cv2.VideoWriter.fourcc(*"mp4v")
651
+ video_writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
652
+ if frame.dtype != np.uint8:
653
+ frame = (frame * 255).astype(np.uint8) if frame.max() <= 1.0 else frame.astype(np.uint8)
654
+
655
+ video_writer.write(frame)
656
+ video_writer.release()
@@ -18,6 +18,7 @@ from supervisely.geometry.constants import (
18
18
  UPDATED_AT,
19
19
  )
20
20
  from supervisely.project.project_meta import ProjectMeta
21
+ from supervisely.project.project_settings import LabelingInterface
21
22
  from supervisely.video_annotation.constants import ID, KEY, OBJECTS_MAP
22
23
  from supervisely.video_annotation.key_id_map import KeyIdMap
23
24
  from supervisely.video_annotation.video_tag import VideoTag
@@ -362,10 +363,34 @@ class VideoObject(KeyObject):
362
363
  f"was not found in the given project meta."
363
364
  )
364
365
 
365
- key = uuid.UUID(data[KEY]) if KEY in data else uuid.uuid4()
366
-
367
- if key_id_map is not None:
368
- key_id_map.add_object(key, data.get(ID, None))
366
+ is_multiview = False
367
+ try:
368
+ if project_meta.labeling_interface == LabelingInterface.MULTIVIEW:
369
+ is_multiview = True
370
+ except AttributeError:
371
+ is_multiview = False
372
+
373
+ raw_id = data.get(ID, None)
374
+
375
+ if not is_multiview:
376
+ key = uuid.UUID(data[KEY]) if KEY in data else uuid.uuid4()
377
+ if key_id_map is not None:
378
+ key_id_map.add_object(key, raw_id)
379
+ else:
380
+ if KEY in data:
381
+ key = uuid.UUID(data[KEY])
382
+ elif key_id_map is not None and isinstance(raw_id, int):
383
+ existing_key = key_id_map.get_object_key(raw_id)
384
+ if isinstance(existing_key, uuid.UUID):
385
+ key = existing_key
386
+ else:
387
+ key = uuid.uuid4()
388
+ else:
389
+ key = uuid.uuid4()
390
+
391
+ if key_id_map is not None and isinstance(raw_id, int):
392
+ if key_id_map.get_object_id(key) is None:
393
+ key_id_map.add_object(key, raw_id)
369
394
 
370
395
  class_id = data.get(CLASS_ID, None)
371
396
  labeler_login = data.get(LABELER_LOGIN, None)
@@ -15,6 +15,8 @@ from supervisely.io.fs import (
15
15
  change_directory_at_index,
16
16
  )
17
17
 
18
+ if not hasattr(np, "bool"):
19
+ np.bool = np.bool_
18
20
 
19
21
  def matrix_from_nrrd_header(header: Dict) -> np.ndarray:
20
22
  """