supervisely 6.73.438__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 (203) hide show
  1. supervisely/__init__.py +137 -1
  2. supervisely/_utils.py +81 -0
  3. supervisely/annotation/annotation.py +8 -2
  4. supervisely/annotation/json_geometries_map.py +14 -11
  5. supervisely/annotation/label.py +80 -3
  6. supervisely/api/annotation_api.py +14 -11
  7. supervisely/api/api.py +59 -38
  8. supervisely/api/app_api.py +11 -2
  9. supervisely/api/dataset_api.py +74 -12
  10. supervisely/api/entities_collection_api.py +10 -0
  11. supervisely/api/entity_annotation/figure_api.py +52 -4
  12. supervisely/api/entity_annotation/object_api.py +3 -3
  13. supervisely/api/entity_annotation/tag_api.py +63 -12
  14. supervisely/api/guides_api.py +210 -0
  15. supervisely/api/image_api.py +72 -1
  16. supervisely/api/labeling_job_api.py +83 -1
  17. supervisely/api/labeling_queue_api.py +33 -7
  18. supervisely/api/module_api.py +9 -0
  19. supervisely/api/project_api.py +71 -26
  20. supervisely/api/storage_api.py +3 -1
  21. supervisely/api/task_api.py +13 -2
  22. supervisely/api/team_api.py +4 -3
  23. supervisely/api/video/video_annotation_api.py +119 -3
  24. supervisely/api/video/video_api.py +65 -14
  25. supervisely/api/video/video_figure_api.py +24 -11
  26. supervisely/app/__init__.py +1 -1
  27. supervisely/app/content.py +23 -7
  28. supervisely/app/development/development.py +18 -2
  29. supervisely/app/fastapi/__init__.py +1 -0
  30. supervisely/app/fastapi/custom_static_files.py +1 -1
  31. supervisely/app/fastapi/multi_user.py +105 -0
  32. supervisely/app/fastapi/subapp.py +88 -42
  33. supervisely/app/fastapi/websocket.py +77 -9
  34. supervisely/app/singleton.py +21 -0
  35. supervisely/app/v1/app_service.py +18 -2
  36. supervisely/app/v1/constants.py +7 -1
  37. supervisely/app/widgets/__init__.py +6 -0
  38. supervisely/app/widgets/activity_feed/__init__.py +0 -0
  39. supervisely/app/widgets/activity_feed/activity_feed.py +239 -0
  40. supervisely/app/widgets/activity_feed/style.css +78 -0
  41. supervisely/app/widgets/activity_feed/template.html +22 -0
  42. supervisely/app/widgets/card/card.py +20 -0
  43. supervisely/app/widgets/classes_list_selector/classes_list_selector.py +121 -9
  44. supervisely/app/widgets/classes_list_selector/template.html +60 -93
  45. supervisely/app/widgets/classes_mapping/classes_mapping.py +13 -12
  46. supervisely/app/widgets/classes_table/classes_table.py +1 -0
  47. supervisely/app/widgets/deploy_model/deploy_model.py +56 -35
  48. supervisely/app/widgets/dialog/dialog.py +12 -0
  49. supervisely/app/widgets/dialog/template.html +2 -1
  50. supervisely/app/widgets/ecosystem_model_selector/ecosystem_model_selector.py +1 -1
  51. supervisely/app/widgets/experiment_selector/experiment_selector.py +8 -0
  52. supervisely/app/widgets/fast_table/fast_table.py +184 -60
  53. supervisely/app/widgets/fast_table/template.html +1 -1
  54. supervisely/app/widgets/heatmap/__init__.py +0 -0
  55. supervisely/app/widgets/heatmap/heatmap.py +564 -0
  56. supervisely/app/widgets/heatmap/script.js +533 -0
  57. supervisely/app/widgets/heatmap/style.css +233 -0
  58. supervisely/app/widgets/heatmap/template.html +21 -0
  59. supervisely/app/widgets/modal/__init__.py +0 -0
  60. supervisely/app/widgets/modal/modal.py +198 -0
  61. supervisely/app/widgets/modal/template.html +10 -0
  62. supervisely/app/widgets/object_class_view/object_class_view.py +3 -0
  63. supervisely/app/widgets/radio_tabs/radio_tabs.py +18 -2
  64. supervisely/app/widgets/radio_tabs/template.html +1 -0
  65. supervisely/app/widgets/select/select.py +6 -3
  66. supervisely/app/widgets/select_class/__init__.py +0 -0
  67. supervisely/app/widgets/select_class/select_class.py +363 -0
  68. supervisely/app/widgets/select_class/template.html +50 -0
  69. supervisely/app/widgets/select_cuda/select_cuda.py +22 -0
  70. supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +65 -7
  71. supervisely/app/widgets/select_tag/__init__.py +0 -0
  72. supervisely/app/widgets/select_tag/select_tag.py +352 -0
  73. supervisely/app/widgets/select_tag/template.html +64 -0
  74. supervisely/app/widgets/select_team/select_team.py +37 -4
  75. supervisely/app/widgets/select_team/template.html +4 -5
  76. supervisely/app/widgets/select_user/__init__.py +0 -0
  77. supervisely/app/widgets/select_user/select_user.py +270 -0
  78. supervisely/app/widgets/select_user/template.html +13 -0
  79. supervisely/app/widgets/select_workspace/select_workspace.py +59 -10
  80. supervisely/app/widgets/select_workspace/template.html +9 -12
  81. supervisely/app/widgets/table/table.py +68 -13
  82. supervisely/app/widgets/tree_select/tree_select.py +2 -0
  83. supervisely/aug/aug.py +6 -2
  84. supervisely/convert/base_converter.py +1 -0
  85. supervisely/convert/converter.py +2 -2
  86. supervisely/convert/image/csv/csv_converter.py +24 -15
  87. supervisely/convert/image/image_converter.py +3 -1
  88. supervisely/convert/image/image_helper.py +48 -4
  89. supervisely/convert/image/label_studio/label_studio_converter.py +2 -0
  90. supervisely/convert/image/medical2d/medical2d_helper.py +2 -24
  91. supervisely/convert/image/multispectral/multispectral_converter.py +6 -0
  92. supervisely/convert/image/pascal_voc/pascal_voc_converter.py +8 -5
  93. supervisely/convert/image/pascal_voc/pascal_voc_helper.py +7 -0
  94. supervisely/convert/pointcloud/kitti_3d/kitti_3d_converter.py +33 -3
  95. supervisely/convert/pointcloud/kitti_3d/kitti_3d_helper.py +12 -5
  96. supervisely/convert/pointcloud/las/las_converter.py +13 -1
  97. supervisely/convert/pointcloud/las/las_helper.py +110 -11
  98. supervisely/convert/pointcloud/nuscenes_conv/nuscenes_converter.py +27 -16
  99. supervisely/convert/pointcloud/pointcloud_converter.py +91 -3
  100. supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_converter.py +58 -22
  101. supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_helper.py +21 -47
  102. supervisely/convert/video/__init__.py +1 -0
  103. supervisely/convert/video/multi_view/__init__.py +0 -0
  104. supervisely/convert/video/multi_view/multi_view.py +543 -0
  105. supervisely/convert/video/sly/sly_video_converter.py +359 -3
  106. supervisely/convert/video/video_converter.py +24 -4
  107. supervisely/convert/volume/dicom/dicom_converter.py +13 -5
  108. supervisely/convert/volume/dicom/dicom_helper.py +30 -18
  109. supervisely/geometry/constants.py +1 -0
  110. supervisely/geometry/geometry.py +4 -0
  111. supervisely/geometry/helpers.py +5 -1
  112. supervisely/geometry/oriented_bbox.py +676 -0
  113. supervisely/geometry/polyline_3d.py +110 -0
  114. supervisely/geometry/rectangle.py +2 -1
  115. supervisely/io/env.py +76 -1
  116. supervisely/io/fs.py +21 -0
  117. supervisely/nn/benchmark/base_evaluator.py +104 -11
  118. supervisely/nn/benchmark/instance_segmentation/evaluator.py +1 -8
  119. supervisely/nn/benchmark/object_detection/evaluator.py +20 -4
  120. supervisely/nn/benchmark/object_detection/vis_metrics/pr_curve.py +10 -5
  121. supervisely/nn/benchmark/semantic_segmentation/evaluator.py +34 -16
  122. supervisely/nn/benchmark/semantic_segmentation/vis_metrics/confusion_matrix.py +1 -1
  123. supervisely/nn/benchmark/semantic_segmentation/vis_metrics/frequently_confused.py +1 -1
  124. supervisely/nn/benchmark/semantic_segmentation/vis_metrics/overview.py +1 -1
  125. supervisely/nn/benchmark/visualization/evaluation_result.py +66 -4
  126. supervisely/nn/inference/cache.py +43 -18
  127. supervisely/nn/inference/gui/serving_gui_template.py +5 -2
  128. supervisely/nn/inference/inference.py +916 -222
  129. supervisely/nn/inference/inference_request.py +55 -10
  130. supervisely/nn/inference/predict_app/gui/classes_selector.py +83 -12
  131. supervisely/nn/inference/predict_app/gui/gui.py +676 -488
  132. supervisely/nn/inference/predict_app/gui/input_selector.py +205 -26
  133. supervisely/nn/inference/predict_app/gui/model_selector.py +2 -4
  134. supervisely/nn/inference/predict_app/gui/output_selector.py +46 -6
  135. supervisely/nn/inference/predict_app/gui/settings_selector.py +756 -59
  136. supervisely/nn/inference/predict_app/gui/tags_selector.py +1 -1
  137. supervisely/nn/inference/predict_app/gui/utils.py +236 -119
  138. supervisely/nn/inference/predict_app/predict_app.py +2 -2
  139. supervisely/nn/inference/session.py +43 -35
  140. supervisely/nn/inference/tracking/bbox_tracking.py +118 -35
  141. supervisely/nn/inference/tracking/point_tracking.py +5 -1
  142. supervisely/nn/inference/tracking/tracker_interface.py +10 -1
  143. supervisely/nn/inference/uploader.py +139 -12
  144. supervisely/nn/live_training/__init__.py +7 -0
  145. supervisely/nn/live_training/api_server.py +111 -0
  146. supervisely/nn/live_training/artifacts_utils.py +243 -0
  147. supervisely/nn/live_training/checkpoint_utils.py +229 -0
  148. supervisely/nn/live_training/dynamic_sampler.py +44 -0
  149. supervisely/nn/live_training/helpers.py +14 -0
  150. supervisely/nn/live_training/incremental_dataset.py +146 -0
  151. supervisely/nn/live_training/live_training.py +497 -0
  152. supervisely/nn/live_training/loss_plateau_detector.py +111 -0
  153. supervisely/nn/live_training/request_queue.py +52 -0
  154. supervisely/nn/model/model_api.py +9 -0
  155. supervisely/nn/model/prediction.py +2 -1
  156. supervisely/nn/model/prediction_session.py +26 -14
  157. supervisely/nn/prediction_dto.py +19 -1
  158. supervisely/nn/tracker/base_tracker.py +11 -1
  159. supervisely/nn/tracker/botsort/botsort_config.yaml +0 -1
  160. supervisely/nn/tracker/botsort/tracker/mc_bot_sort.py +7 -4
  161. supervisely/nn/tracker/botsort_tracker.py +94 -65
  162. supervisely/nn/tracker/utils.py +4 -5
  163. supervisely/nn/tracker/visualize.py +93 -93
  164. supervisely/nn/training/gui/classes_selector.py +16 -1
  165. supervisely/nn/training/gui/train_val_splits_selector.py +52 -31
  166. supervisely/nn/training/train_app.py +46 -31
  167. supervisely/project/data_version.py +115 -51
  168. supervisely/project/download.py +1 -1
  169. supervisely/project/pointcloud_episode_project.py +37 -8
  170. supervisely/project/pointcloud_project.py +30 -2
  171. supervisely/project/project.py +14 -2
  172. supervisely/project/project_meta.py +27 -1
  173. supervisely/project/project_settings.py +32 -18
  174. supervisely/project/versioning/__init__.py +1 -0
  175. supervisely/project/versioning/common.py +20 -0
  176. supervisely/project/versioning/schema_fields.py +35 -0
  177. supervisely/project/versioning/video_schema.py +221 -0
  178. supervisely/project/versioning/volume_schema.py +87 -0
  179. supervisely/project/video_project.py +717 -15
  180. supervisely/project/volume_project.py +623 -5
  181. supervisely/template/experiment/experiment.html.jinja +4 -4
  182. supervisely/template/experiment/experiment_generator.py +14 -21
  183. supervisely/template/live_training/__init__.py +0 -0
  184. supervisely/template/live_training/header.html.jinja +96 -0
  185. supervisely/template/live_training/live_training.html.jinja +51 -0
  186. supervisely/template/live_training/live_training_generator.py +464 -0
  187. supervisely/template/live_training/sly-style.css +402 -0
  188. supervisely/template/live_training/template.html.jinja +18 -0
  189. supervisely/versions.json +28 -26
  190. supervisely/video/sampling.py +39 -20
  191. supervisely/video/video.py +41 -12
  192. supervisely/video_annotation/video_figure.py +38 -4
  193. supervisely/video_annotation/video_object.py +29 -4
  194. supervisely/volume/stl_converter.py +2 -0
  195. supervisely/worker_api/agent_rpc.py +24 -1
  196. supervisely/worker_api/rpc_servicer.py +31 -7
  197. {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/METADATA +58 -40
  198. {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/RECORD +203 -155
  199. {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/WHEEL +1 -1
  200. supervisely_lib/__init__.py +6 -1
  201. {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/entry_points.txt +0 -0
  202. {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info/licenses}/LICENSE +0 -0
  203. {supervisely-6.73.438.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
@@ -18,7 +18,7 @@ ALLOWED_VIDEO_EXTENSIONS = [".avi", ".mp4", ".3gp", ".flv", ".webm", ".wmv", ".m
18
18
 
19
19
 
20
20
  _SUPPORTED_CONTAINERS = {"mp4", "webm", "ogg", "ogv"}
21
- _SUPPORTED_CODECS = {"h264", "vp8", "vp9"}
21
+ _SUPPORTED_CODECS = {"h264", "vp8", "vp9", "h265", "hevc", "av1"}
22
22
 
23
23
 
24
24
  class VideoExtensionError(Exception):
@@ -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()