supervisely 6.73.376__py3-none-any.whl → 6.73.378__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.
@@ -0,0 +1,550 @@
1
+ from typing import List, Tuple, Union
2
+
3
+ from supervisely.api.api import Api
4
+ from supervisely.api.dataset_api import DatasetInfo
5
+ from supervisely.app.widgets import Progress
6
+ from supervisely.app.widgets.button.button import Button
7
+ from supervisely.app.widgets.checkbox.checkbox import Checkbox
8
+ from supervisely.app.widgets.container.container import Container
9
+ from supervisely.app.widgets.empty.empty import Empty
10
+ from supervisely.app.widgets.flexbox.flexbox import Flexbox
11
+ from supervisely.app.widgets.input_number.input_number import InputNumber
12
+ from supervisely.app.widgets.notification_box.notification_box import NotificationBox
13
+ from supervisely.app.widgets.one_of.one_of import OneOf
14
+ from supervisely.app.widgets.project_thumbnail.project_thumbnail import ProjectThumbnail
15
+ from supervisely.app.widgets.radio_group.radio_group import RadioGroup
16
+ from supervisely.app.widgets.select_dataset.select_dataset import SelectDataset
17
+ from supervisely.app.widgets.select_project.select_project import SelectProject
18
+ from supervisely.app.widgets.text.text import Text
19
+ from supervisely.app.widgets.widget import Widget
20
+ from supervisely.project.project import ProjectType
21
+ from supervisely.video.sampling import SamplingSettings, sample_video_project
22
+
23
+
24
+ class Sampling(Widget):
25
+ def __init__(
26
+ self,
27
+ project_id: int = None,
28
+ input_selectable: bool = True,
29
+ datasets_ids: List[int] = None,
30
+ output_project_id: int = None,
31
+ output_project_selectable: bool = True,
32
+ widgth: int = 370,
33
+ widget_id: str = None,
34
+ file_path: str = __file__,
35
+ ):
36
+ super().__init__(widget_id, file_path)
37
+ if not input_selectable and project_id is None:
38
+ raise ValueError(
39
+ "Either 'project_id' must be provided or 'project_selectable' must be True."
40
+ )
41
+ if project_id is None and not input_selectable:
42
+ input_selectable = True
43
+ if not output_project_selectable and output_project_id is None:
44
+ raise ValueError(
45
+ "Either 'output_project_id' must be provided or 'output_project_selectable' must be True."
46
+ )
47
+ if output_project_id is None and not output_project_selectable:
48
+ output_project_selectable = True
49
+ self._api = Api()
50
+ self.project_id = project_id
51
+ self.project_selectable = input_selectable
52
+ self.datasets_ids = datasets_ids
53
+ self.output_project_id = output_project_id
54
+ self.output_project_selectable = output_project_selectable
55
+ self.widgth = widgth
56
+ self.project_info = (
57
+ self._api.project.get_info_by_id(self.project_id) if self.project_id else None
58
+ )
59
+ self.all_datasets = (
60
+ self._api.dataset.get_list(self.project_id, recursive=True) if self.project_id else []
61
+ )
62
+ self.items_count = self._count_items(self.all_datasets, datasets_ids, with_children=True)
63
+ self._init_gui()
64
+
65
+ def _init_input_gui(self):
66
+ self.input_datasets_select = SelectDataset(
67
+ default_id=self.datasets_ids,
68
+ project_id=self.project_id,
69
+ allowed_project_types=[ProjectType.VIDEOS],
70
+ size="mini",
71
+ multiselect=True,
72
+ select_all_datasets=self.datasets_ids is None,
73
+ )
74
+ self.project_preview = ProjectThumbnail()
75
+ self.project_preview.hide()
76
+ if not self.project_selectable:
77
+ self.input_datasets_select.hide()
78
+ project_info = self._api.project.get_info_by_id(self.project_id)
79
+ self.project_preview.set(project_info)
80
+ self.project_preview.show()
81
+ self.nested_datasets_checkbox = Checkbox(
82
+ "Include nested datasets",
83
+ checked=True,
84
+ )
85
+ self.input_project_container = Container(
86
+ widgets=[
87
+ self.input_datasets_select,
88
+ self.nested_datasets_checkbox,
89
+ self.project_preview,
90
+ ],
91
+ style="padding-left: 21px; padding-top: 10px;",
92
+ )
93
+ self.input_field = Container(
94
+ widgets=[
95
+ Text(
96
+ '<i class="zmdi zmdi-collection-video" style="padding-right: 10px; color: rgb(0, 154, 255);"></i><b>Input project</b>'
97
+ ),
98
+ self.input_project_container,
99
+ ],
100
+ gap=0,
101
+ )
102
+
103
+ def _init_settings_gui(self):
104
+ self.only_annotated_checkbox = Checkbox(Text("Only annotated frames", font_size=13))
105
+ self.only_annotated_row = Flexbox(widgets=[self.only_annotated_checkbox])
106
+ self.step_label = Text("Step:", font_size=13)
107
+ self.step_input = InputNumber(value=1, min=1, step=1, size="mini", width=160)
108
+ self.step_row = Container(
109
+ widgets=[self.step_label, self.step_input],
110
+ direction="horizontal",
111
+ style="width: 202px; align-items: center;",
112
+ widgets_style="flex: 1; display: flex;",
113
+ )
114
+ self.resize_checkbox = Checkbox(Text("Resize frames", font_size=13))
115
+ self.resize_input_h_label = Text("Height:", font_size=13)
116
+ self.resize_input_h = InputNumber(value=224, min=1, step=1, size="mini", controls=False)
117
+ self.resize_input_w_label = Text("Width:", font_size=13)
118
+ self.resize_input_w = InputNumber(value=224, min=1, step=1, size="mini", controls=False)
119
+ self.resize_h_row = Flexbox(widgets=[self.resize_input_h_label, self.resize_input_h])
120
+ self.resize_w_row = Flexbox(
121
+ widgets=[self.resize_input_w_label, self.resize_input_w], gap=15
122
+ )
123
+ self.resize_row = Flexbox(widgets=[self.resize_checkbox])
124
+ self.resize_hw_container = Container(
125
+ widgets=[Empty(), self.resize_h_row, self.resize_w_row]
126
+ )
127
+ self.resize_hw_container.hide()
128
+ self.resize_container = Container(
129
+ widgets=[self.resize_row, self.resize_hw_container], gap=0
130
+ )
131
+ self.copy_annotations_checkbox = Checkbox(
132
+ Text("Copy annotations from source project", font_size=13)
133
+ )
134
+ self.copy_annotations_row = Flexbox(widgets=[self.copy_annotations_checkbox])
135
+
136
+ @self.resize_checkbox.value_changed
137
+ def on_resize_checkbox_change(checked: bool):
138
+ if checked:
139
+ self.resize_hw_container.show()
140
+ else:
141
+ self.resize_hw_container.hide()
142
+
143
+ self.settings_container = Container(
144
+ widgets=[
145
+ Empty(),
146
+ self.step_row,
147
+ self.only_annotated_row,
148
+ self.resize_container,
149
+ self.copy_annotations_row,
150
+ Empty(),
151
+ ],
152
+ style="padding-left: 21px; padding-top: 10px;",
153
+ )
154
+ self.settings_field = Container(
155
+ widgets=[
156
+ Text(
157
+ '<i class="zmdi zmdi-settings" style="padding-right: 10px; color: rgb(0, 154, 255);"></i><b>Sampling settings</b>'
158
+ ),
159
+ self.settings_container,
160
+ ],
161
+ gap=0,
162
+ )
163
+
164
+ def _datasets_to_process(
165
+ self, all_datasets: List[DatasetInfo], datasets_ids: List[int], with_children: bool
166
+ ) -> List[DatasetInfo]:
167
+ if datasets_ids is None:
168
+ return all_datasets.copy()
169
+ datasets = []
170
+ for ds in [ds for ds in all_datasets if ds.id in datasets_ids]:
171
+ datasets.append(ds)
172
+ if with_children:
173
+ children = [child for child in all_datasets if child.parent_id == ds.id]
174
+ if children:
175
+ datasets.extend(
176
+ self._datasets_to_process(
177
+ all_datasets, [child.id for child in children], True
178
+ )
179
+ )
180
+ return datasets
181
+
182
+ def _count_items(
183
+ self, all_datasets: List[DatasetInfo], datasets_ids: List[int], with_children: bool
184
+ ) -> int:
185
+ return sum(
186
+ ds.items_count
187
+ for ds in self._datasets_to_process(
188
+ all_datasets, datasets_ids, with_children=with_children
189
+ )
190
+ )
191
+
192
+ def _selected_text(self, datasets_ids: List[int] = None, with_children: bool = True) -> str:
193
+ red = "#FF6458;"
194
+ blue = "rgb(0, 154, 255);"
195
+ datasets = self._datasets_to_process(
196
+ self.all_datasets, datasets_ids, with_children=with_children
197
+ )
198
+ color = blue if self.items_count > 0 else red
199
+ ds_num = len(datasets)
200
+ return f'Selected <b style="color: {color};">{ds_num}</b> dataset{"s" if ds_num % 10 != 1 else ""} with <b style="color: {color};">{self.items_count}</b> videos'
201
+
202
+ def _update_preview(self):
203
+ with_children = self.nested_datasets_checkbox.is_checked()
204
+ self.selected_items_text.text = self._selected_text(
205
+ self.datasets_ids, with_children=with_children
206
+ )
207
+ if self.items_count > 0:
208
+ self.run_button.enable()
209
+ else:
210
+ self.run_button.disable()
211
+
212
+ def _datasets_changed(self, datasets_ids: List[int]):
213
+ self.preview_container.loading = True
214
+ self.datasets_ids = datasets_ids
215
+ project_id = self.input_datasets_select.get_selected_project_id()
216
+ with_children = self.nested_datasets_checkbox.is_checked()
217
+ if self.project_id != project_id:
218
+ if project_id is None:
219
+ self.project_id = None
220
+ self.project_info = None
221
+ self.all_datasets = []
222
+ else:
223
+ self.project_id = project_id
224
+ self._api.project.get_info_by_id(project_id)
225
+ self.all_datasets = self._api.dataset.get_list(project_id, recursive=True)
226
+ self.items_count = self._count_items(
227
+ self.all_datasets, datasets_ids, with_children=with_children
228
+ )
229
+ self._update_preview()
230
+ self.preview_container.loading = False
231
+
232
+ def _init_peview_gui(self):
233
+ self.selected_items_text = Text("", font_size=13)
234
+ self.run_button = Button("Run", icon="zmdi zmdi-play", button_size="mini")
235
+ self.run_button.disable()
236
+
237
+ self.preview_text = Text(
238
+ '<i class="zmdi zmdi-eye" style="padding-right: 10px; color: rgb(0, 154, 255);"></i><b style="font-size: 14px">Preview</b>',
239
+ font_size=13,
240
+ )
241
+ self.preview_field = Container(
242
+ widgets=[
243
+ self.preview_text,
244
+ Container(widgets=[self.selected_items_text], style="padding-left: 21px;"),
245
+ ],
246
+ style="padding-top: 10px;",
247
+ )
248
+ self.run_button_container = Container(
249
+ widgets=[self.run_button],
250
+ direction="horizontal",
251
+ overflow="wrap",
252
+ style="display: flex; justify-content: flex-end;",
253
+ widgets_style="display: flex; flex: none;",
254
+ )
255
+ self.preview_container = Container(
256
+ widgets=[self.preview_field, self.run_button_container],
257
+ )
258
+ self._update_preview()
259
+
260
+ @self.input_datasets_select.value_changed
261
+ def on_input_datasets_select_change(datasets_ids: List[int]):
262
+ self._datasets_changed(datasets_ids)
263
+
264
+ @self.nested_datasets_checkbox.value_changed
265
+ def on_nested_datasets_checkbox_change(is_checked: bool):
266
+ self._datasets_changed(self.input_datasets_select.get_selected_ids())
267
+
268
+ @self.run_button.click
269
+ def on_run_button_click():
270
+ self.run()
271
+
272
+ def _init_output_gui(self):
273
+ self.output_project_select = SelectProject(
274
+ default_id=self.output_project_id, allowed_types=[ProjectType.IMAGES], size="mini"
275
+ )
276
+ self.output_project_preview = ProjectThumbnail()
277
+ self.output_project_preview.hide()
278
+ self.output_mode_radio = RadioGroup(
279
+ items=[
280
+ RadioGroup.Item("create", "Create new project", content=Empty()),
281
+ RadioGroup.Item(
282
+ "merge",
283
+ "Merge with existing project",
284
+ content=self.output_project_select,
285
+ ),
286
+ ]
287
+ )
288
+ self.output_merge_project_oneof = OneOf(self.output_mode_radio)
289
+ self.output_project_container = Container(
290
+ widgets=[self.output_mode_radio, self.output_merge_project_oneof],
291
+ )
292
+
293
+ self.output_container = Container(
294
+ widgets=[self.output_project_preview, self.output_project_container],
295
+ gap=0,
296
+ style="padding-left: 21px; padding-top: 10px;",
297
+ )
298
+ if not self.output_project_selectable:
299
+ self.output_project_container.hide()
300
+ project_info = self._api.project.get_info_by_id(self.output_project_id)
301
+ self.output_project_preview.set(project_info)
302
+ self.output_project_preview.show()
303
+ if self.output_project_id is not None:
304
+ self.output_mode_radio.set_value("merge")
305
+
306
+ self.output_field = Container(
307
+ widgets=[
308
+ Text(
309
+ '<i class="zmdi zmdi-collection-folder-image" style="padding-right: 10px; color: rgb(0, 154, 255);"></i><b>Output project</b>'
310
+ ),
311
+ self.output_container,
312
+ ],
313
+ gap=0,
314
+ )
315
+
316
+ def _init_progress_gui(self):
317
+ self.items_progress = Progress(hide_on_finish=False)
318
+ self.frames_progress = Progress(hide_on_finish=False)
319
+ self.error_notification = NotificationBox(title="Error", description="", box_type="error")
320
+ self.error_notification.hide()
321
+ self.progress_container = Container(widgets=[self.items_progress, self.frames_progress])
322
+ self.progress_container.hide()
323
+ self.result_project_preview = ProjectThumbnail()
324
+ self.result_project_preview_field = Container(
325
+ widgets=[
326
+ Text(
327
+ '<i class="zmdi zmdi-check-square" style="padding-right: 10px; color: rgb(0, 154, 255);"></i><b>Result project</b>'
328
+ ),
329
+ Container(
330
+ widgets=[self.result_project_preview],
331
+ style="padding-left: 21px;",
332
+ ),
333
+ ]
334
+ )
335
+ self.result_project_preview_field.hide()
336
+ self.result_container = Container(
337
+ widgets=[
338
+ self.progress_container,
339
+ self.error_notification,
340
+ self.result_project_preview_field,
341
+ ],
342
+ gap=0,
343
+ )
344
+
345
+ def _init_gui(self):
346
+ self._init_input_gui()
347
+ self._init_settings_gui()
348
+ self._init_output_gui()
349
+ self._init_peview_gui()
350
+ self._init_progress_gui()
351
+
352
+ self.content = Container(
353
+ widgets=[
354
+ self.input_field,
355
+ self.settings_field,
356
+ self.output_field,
357
+ self.preview_container,
358
+ self.result_container,
359
+ ],
360
+ style=f"width: {self.widgth}px;",
361
+ )
362
+
363
+ def _get_settings(self) -> dict:
364
+ settings = {
365
+ SamplingSettings.ONLY_ANNOTATED: self.only_annotated_checkbox.is_checked(),
366
+ SamplingSettings.STEP: self.step_input.get_value(),
367
+ SamplingSettings.RESIZE: None,
368
+ SamplingSettings.COPY_ANNOTATIONS: self.copy_annotations_checkbox.is_checked(),
369
+ }
370
+ if self.resize_checkbox.is_checked():
371
+ settings[SamplingSettings.RESIZE] = [
372
+ self.resize_input_h.get_value(),
373
+ self.resize_input_w.get_value(),
374
+ ]
375
+
376
+ return settings
377
+
378
+ def _get_dst_project_id(self) -> int:
379
+ if self.output_mode_radio.get_value() == "create":
380
+ return None
381
+ else:
382
+ return self.output_project_select.get_selected_id()
383
+
384
+ def run(self):
385
+ self.progress_container.show()
386
+ self.error_notification.hide()
387
+ self.result_project_preview_field.hide()
388
+ try:
389
+ project_id = self.input_datasets_select.get_selected_project_id()
390
+ datasets_ids = self.input_datasets_select.get_selected_ids()
391
+ with_children = self.nested_datasets_checkbox.is_checked()
392
+ selected_datasets_with_children = self._datasets_to_process(
393
+ all_datasets=self.all_datasets,
394
+ datasets_ids=datasets_ids,
395
+ with_children=with_children,
396
+ )
397
+ total_items = sum(ds.items_count for ds in selected_datasets_with_children)
398
+ datasets_ids = [ds.id for ds in selected_datasets_with_children]
399
+ project_info = self.project_info
400
+
401
+ if project_info.type != str(ProjectType.VIDEOS):
402
+ raise ValueError(
403
+ f"Project with ID {self.input_datasets_select.get_selected_id()} is not a video project."
404
+ )
405
+ frames_pbar = self.frames_progress()
406
+ with self.items_progress(
407
+ message=f"Videos progress...",
408
+ total=total_items,
409
+ ) as pbar:
410
+ self.progress_container.show()
411
+ dst_project_info = sample_video_project(
412
+ api=self._api,
413
+ project_id=project_id,
414
+ settings=self._get_settings(),
415
+ dst_project_id=self._get_dst_project_id(),
416
+ datasets_ids=datasets_ids,
417
+ items_progress_cb=pbar.update,
418
+ video_progress=frames_pbar,
419
+ )
420
+ except Exception as e:
421
+ self.error_notification.set(title="Error", description=str(e))
422
+ self.error_notification.show()
423
+ raise e
424
+ else:
425
+ if self.output_project_selectable:
426
+ dst_project_info = self._api.project.get_info_by_id(dst_project_info.id)
427
+ self.result_project_preview.set(dst_project_info)
428
+ self.result_project_preview_field.show()
429
+ else:
430
+ dst_project_info = self._api.project.get_info_by_id(self.output_project_id)
431
+ self.output_project_preview.set(dst_project_info)
432
+ finally:
433
+ self.progress_container.hide()
434
+
435
+ @property
436
+ def selected_project_id(self) -> int:
437
+ if not self.project_selectable:
438
+ return self.project_id
439
+ return self.input_datasets_select.get_selected_project_id()
440
+
441
+ @selected_project_id.setter
442
+ def selected_project_id(self, value: int):
443
+ if not self.project_selectable:
444
+ raise ValueError("Project is not selectable.")
445
+ self.input_datasets_select.set_project_id(value)
446
+ self._datasets_changed(self.input_datasets_select.get_selected_ids())
447
+
448
+ @property
449
+ def selected_all_datasets(self) -> bool:
450
+ return self.input_datasets_select._all_datasets_checkbox.is_checked()
451
+
452
+ @selected_all_datasets.setter
453
+ def selected_all_datasets(self, value: bool):
454
+ if value:
455
+ self.input_datasets_select._all_datasets_checkbox.check()
456
+ else:
457
+ self.input_datasets_select._all_datasets_checkbox.uncheck()
458
+ self._datasets_changed(self.input_datasets_select.get_selected_ids())
459
+
460
+ @property
461
+ def selected_datasets_ids(self) -> List[int]:
462
+ return self.input_datasets_select.get_selected_ids()
463
+
464
+ @selected_datasets_ids.setter
465
+ def selected_datasets_ids(self, value: List[int]):
466
+ self.input_datasets_select.set_dataset_ids(value)
467
+
468
+ @property
469
+ def include_nested_datasets(self) -> bool:
470
+ return self.nested_datasets_checkbox.is_checked()
471
+
472
+ @include_nested_datasets.setter
473
+ def include_nested_datasets(self, value: bool):
474
+ if value:
475
+ self.nested_datasets_checkbox.check()
476
+ else:
477
+ self.nested_datasets_checkbox.uncheck()
478
+ self._datasets_changed(self.input_datasets_select.get_selected_ids())
479
+
480
+ @property
481
+ def step(self) -> int:
482
+ return self.step_input.get_value()
483
+
484
+ @step.setter
485
+ def step(self, value: int):
486
+ self.step_input.value = value
487
+
488
+ @property
489
+ def only_annotated(self) -> bool:
490
+ return self.only_annotated_checkbox.is_checked()
491
+
492
+ @only_annotated.setter
493
+ def only_annotated(self, value: bool):
494
+ if value:
495
+ self.only_annotated_checkbox.check()
496
+ else:
497
+ self.only_annotated_checkbox.uncheck()
498
+
499
+ @property
500
+ def resize(self) -> Union[Tuple[int, int], None]:
501
+ if self.resize_checkbox.is_checked():
502
+ return (self.resize_input_h.get_value(), self.resize_input_w.get_value())
503
+ return None
504
+
505
+ @resize.setter
506
+ def resize(self, value: Union[Tuple[int, int], None]):
507
+ if value is None:
508
+ self.resize_checkbox.uncheck()
509
+ else:
510
+ self.resize_checkbox.check()
511
+ self.resize_input_h.value = value[0]
512
+ self.resize_input_w.value = value[1]
513
+
514
+ @property
515
+ def copy_annotations(self) -> bool:
516
+ return self.copy_annotations_checkbox.is_checked()
517
+
518
+ @copy_annotations.setter
519
+ def copy_annotations(self, value: bool):
520
+ if value:
521
+ self.copy_annotations_checkbox.check()
522
+ else:
523
+ self.copy_annotations_checkbox.uncheck()
524
+
525
+ @property
526
+ def selected_output_project_id(self) -> int:
527
+ if not self.output_project_selectable:
528
+ return self.output_project_id
529
+ if self.output_mode_radio.get_value() == "create":
530
+ return None
531
+ return self.output_project_select.get_selected_id()
532
+
533
+ @selected_output_project_id.setter
534
+ def selected_output_project_id(self, value: int):
535
+ if not self.output_project_selectable:
536
+ raise ValueError("Output project is not selectable.")
537
+ self.output_project_select.set_project_id(value)
538
+ if value is not None:
539
+ self.output_mode_radio.set_value("merge")
540
+ else:
541
+ self.output_mode_radio.set_value("create")
542
+
543
+ def get_json_data(self) -> dict:
544
+ return {}
545
+
546
+ def get_json_state(self) -> dict:
547
+ return {}
548
+
549
+ def to_html(self):
550
+ return self.content.to_html()
@@ -138,11 +138,18 @@ class SelectDataset(Widget):
138
138
 
139
139
  def set_project_id(self, id: int):
140
140
  self._project_id = id
141
- if self._compact is True:
142
- DataJson()[self.widget_id]["projectId"] = self._project_id
143
- DataJson().send_changes()
141
+ self._project_selector.set_project_id(self._project_id)
142
+
143
+ def set_select_all_datasets(self, is_checked: bool):
144
+ if self._multiselect is False:
145
+ raise ValueError(
146
+ "Multiselect is disabled. Use another method 'set_dataset_id' instead of 'set_select_all_datasets'"
147
+ )
148
+ if is_checked:
149
+ self._all_datasets_checkbox.check()
144
150
  else:
145
- StateJson()[self.widget_id]["projectId"] = self._project_id
151
+ self._all_datasets_checkbox.uncheck()
152
+ StateJson()[self.widget_id]["datasets"] = []
146
153
  StateJson().send_changes()
147
154
 
148
155
  def set_dataset_id(self, id: int):
@@ -202,6 +209,7 @@ class SelectDataset(Widget):
202
209
  _process()
203
210
 
204
211
  if self._compact is False:
212
+
205
213
  @self._project_selector.value_changed
206
214
  def _update_datasets(project_id):
207
215
  if self._multiselect is True:
@@ -217,7 +225,7 @@ class SelectDataset(Widget):
217
225
  self._cb_called = True
218
226
  _process()
219
227
 
220
- @server.post(route_path)
228
+ @server.post(route_path)
221
229
  def _click():
222
230
  if self._cb_called is False or self._multiselect is False:
223
231
  _process()
@@ -256,4 +264,6 @@ class SelectDataset(Widget):
256
264
  info = self._api.dataset.get_info_by_id(self._default_id[0], raise_error=True)
257
265
  elif isinstance(self._default_id, int):
258
266
  info = self._api.dataset.get_info_by_id(self._default_id, raise_error=True)
267
+ else:
268
+ return
259
269
  self._project_id = info.project_id
@@ -171,6 +171,15 @@ class CustomTqdm(tqdm):
171
171
  **kwargs,
172
172
  )
173
173
 
174
+ def __setattr__(self, name, value):
175
+ if name == "total":
176
+ if hasattr(self, "fp"):
177
+ self.fp.total = value
178
+ if name == "message":
179
+ if hasattr(self, "fp"):
180
+ self.fp.progress["message"] = value
181
+ return super().__setattr__(name, value)
182
+
174
183
  def refresh(self, *args, **kwargs):
175
184
  if self.fp is not None:
176
185
  self.fp._n = self.n
@@ -17,7 +17,7 @@ from supervisely.api.api import Api
17
17
  from supervisely.convert.base_converter import AvailableImageConverters
18
18
  from supervisely.convert.image.image_converter import ImageConverter
19
19
  from supervisely.convert.image.image_helper import validate_image_bounds
20
- from supervisely.io.fs import dirs_filter, file_exists, get_file_ext
20
+ from supervisely.io.fs import dirs_filter, file_exists, get_file_ext, get_file_name
21
21
  from supervisely.io.json import load_json_file
22
22
  from supervisely.project.project import find_project_dirs
23
23
  from supervisely.project.project import upload_project as upload_project_fs
@@ -122,17 +122,20 @@ class SLYImageConverter(ImageConverter):
122
122
  self._items = []
123
123
  for image_path in images_list:
124
124
  item = self.Item(image_path)
125
- ann_name = f"{item.name}.json"
126
- if ann_name in ann_dict:
127
- ann_path = ann_dict[ann_name]
125
+ json_name, json_name_noext = f"{item.name}.json", f"{get_file_name(item.name)}.json"
126
+ ann_path = ann_dict.get(json_name, ann_dict.get(json_name_noext))
127
+ if ann_path:
128
128
  if self._meta is None:
129
129
  meta = self.generate_meta_from_annotation(ann_path, meta)
130
130
  is_valid = self.validate_ann_file(ann_path, meta)
131
131
  if is_valid:
132
132
  item.ann_data = ann_path
133
- detected_ann_cnt += 1
134
- if ann_name in img_meta_dict:
135
- item.set_meta_data(img_meta_dict[ann_name])
133
+
134
+ meta_path = img_meta_dict.get(json_name, img_meta_dict.get(json_name_noext))
135
+ if meta_path:
136
+ item.set_meta_data(meta_path)
137
+ if item.ann_data is not None or item.meta is not None:
138
+ detected_ann_cnt += 1
136
139
  self._items.append(item)
137
140
  self._meta = meta
138
141
  return detected_ann_cnt > 0