supervisely 6.73.439__py3-none-any.whl → 6.73.440__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.
@@ -4,6 +4,8 @@
4
4
  # docs
5
5
  from __future__ import annotations
6
6
 
7
+
8
+ from supervisely.collection.str_enum import StrEnum
7
9
  from copy import deepcopy
8
10
  from typing import Dict, List, Optional, Tuple, Union
9
11
 
@@ -45,6 +47,47 @@ class LabelJsonFields:
45
47
  """"""
46
48
  SMART_TOOL_INPUT = "smartToolInput"
47
49
  """"""
50
+ NN_CREATED = "nnCreated"
51
+ """Flag indicating if the label was created by NN model or manually."""
52
+ NN_UPDATED = "nnUpdated"
53
+ """Flag indicating if the label was corrected by NN model or manually."""
54
+
55
+ class LabelingStatus(StrEnum):
56
+ """
57
+ Shows status of the label. Can be one of the following:
58
+
59
+ - AUTO: Specifies if the label was created by NN model.
60
+ - nn_created: True | Created by NN model
61
+ - nn_updated: True | Corrected by NN model
62
+ - MANUAL: Specifies if the label was created manually.
63
+ - nn_created: False | Manually created
64
+ - nn_updated: False | Not corrected by NN model
65
+ - CORRECTED: Specifies if the label was initially created by NN model and then manually corrected.
66
+ - nn_created: True | Created by NN model
67
+ - nn_updated: False | Manually corrected
68
+ """
69
+
70
+ AUTO = "auto"
71
+ MANUAL = "manual"
72
+ CORRECTED = "corrected"
73
+
74
+ @classmethod
75
+ def to_flags(cls, status: LabelingStatus) -> Tuple[bool, bool]:
76
+ if status == cls.AUTO:
77
+ return True, True
78
+ elif status == cls.CORRECTED:
79
+ return True, False
80
+ else:
81
+ return False, False
82
+
83
+ @classmethod
84
+ def from_flags(cls, nn_created: bool, nn_updated: bool) -> LabelingStatus:
85
+ if nn_created and nn_updated:
86
+ return cls.AUTO
87
+ elif nn_created and not nn_updated:
88
+ return cls.CORRECTED
89
+ else:
90
+ return cls.MANUAL
48
91
 
49
92
 
50
93
  class LabelBase:
@@ -65,6 +108,8 @@ class LabelBase:
65
108
  :type smart_tool_input: dict, optional
66
109
  :param sly_id: Label unique identifier.
67
110
  :type sly_id: int, optional
111
+ :param status: Sets labeling status. Shows how label was created and corrected.
112
+ :type status: LabelingStatus, optional
68
113
 
69
114
  :Usage example:
70
115
 
@@ -99,6 +144,7 @@ class LabelBase:
99
144
  binding_key: Optional[str] = None,
100
145
  smart_tool_input: Optional[Dict] = None,
101
146
  sly_id: Optional[int] = None,
147
+ status: Optional[LabelingStatus] = None,
102
148
  ):
103
149
  self._geometry = geometry
104
150
  self._obj_class = obj_class
@@ -112,9 +158,14 @@ class LabelBase:
112
158
 
113
159
  self._binding_key = binding_key
114
160
  self._smart_tool_input = smart_tool_input
115
-
116
161
  self._sly_id = sly_id
117
162
 
163
+ if status is None:
164
+ status = LabelingStatus.MANUAL
165
+ self._status = status
166
+ self._nn_created, self._nn_updated = LabelingStatus.to_flags(self.status)
167
+
168
+
118
169
  def _validate_geometry(self):
119
170
  """
120
171
  The function checks the name of the Object for compliance.
@@ -268,7 +319,9 @@ class LabelBase:
268
319
  # "interior": []
269
320
  # },
270
321
  # "geometryType": "rectangle",
271
- # "shape": "rectangle"
322
+ # "shape": "rectangle",
323
+ # "nnCreated": false,
324
+ # "nnUpdated": false
272
325
  # }
273
326
  """
274
327
  res = {
@@ -278,6 +331,8 @@ class LabelBase:
278
331
  **self.geometry.to_json(),
279
332
  GEOMETRY_TYPE: self.geometry.geometry_name(),
280
333
  GEOMETRY_SHAPE: self.geometry.geometry_name(),
334
+ LabelJsonFields.NN_CREATED: self._nn_created,
335
+ LabelJsonFields.NN_UPDATED: self._nn_updated,
281
336
  }
282
337
 
283
338
  if self.obj_class.sly_id is not None:
@@ -328,7 +383,9 @@ class LabelBase:
328
383
  "points": {
329
384
  "exterior": [[100, 100], [900, 700]],
330
385
  "interior": []
331
- }
386
+ },
387
+ "nnCreated": false,
388
+ "nnUpdated": false
332
389
  }
333
390
 
334
391
  label_dog = sly.Label.from_json(data, meta)
@@ -352,6 +409,10 @@ class LabelBase:
352
409
  binding_key = data.get(LabelJsonFields.INSTANCE_KEY)
353
410
  smart_tool_input = data.get(LabelJsonFields.SMART_TOOL_INPUT)
354
411
 
412
+ nn_created = data.get(LabelJsonFields.NN_CREATED, False)
413
+ nn_updated = data.get(LabelJsonFields.NN_UPDATED, False)
414
+ status = LabelingStatus.from_flags(nn_created, nn_updated)
415
+
355
416
  return cls(
356
417
  geometry=geometry,
357
418
  obj_class=obj_class,
@@ -360,6 +421,7 @@ class LabelBase:
360
421
  binding_key=binding_key,
361
422
  smart_tool_input=smart_tool_input,
362
423
  sly_id=data.get(LabelJsonFields.ID),
424
+ status=status,
363
425
  )
364
426
 
365
427
  @property
@@ -441,6 +503,7 @@ class LabelBase:
441
503
  description: Optional[str] = None,
442
504
  binding_key: Optional[str] = None,
443
505
  smart_tool_input: Optional[Dict] = None,
506
+ status: Optional[LabelingStatus] = None,
444
507
  ) -> LabelBase:
445
508
  """
446
509
  Makes a copy of Label with new fields, if fields are given, otherwise it will use fields of the original Label.
@@ -457,6 +520,8 @@ class LabelBase:
457
520
  :type binding_key: str, optional
458
521
  :param smart_tool_input: Smart Tool parameters that were used for labeling.
459
522
  :type smart_tool_input: dict, optional
523
+ :param status: Sets labeling status. Specifies if the label was created by NN model, manually or created by NN and then manually corrected.
524
+ :type status: LabelingStatus, optional
460
525
  :return: New instance of Label
461
526
  :rtype: :class:`Label<LabelBase>`
462
527
  :Usage example:
@@ -501,6 +566,7 @@ class LabelBase:
501
566
  description=take_with_default(description, self.description),
502
567
  binding_key=take_with_default(binding_key, self.binding_key),
503
568
  smart_tool_input=take_with_default(smart_tool_input, self._smart_tool_input),
569
+ status=take_with_default(status, self.status),
504
570
  )
505
571
 
506
572
  def crop(self, rect: Rectangle) -> List[LabelBase]:
@@ -864,6 +930,17 @@ class LabelBase:
864
930
  def labeler_login(self):
865
931
  return self.geometry.labeler_login
866
932
 
933
+ @property
934
+ def status(self) -> LabelingStatus:
935
+ """Labeling status. Specifies if the Label was created by NN model, manually or created by NN and then manually corrected."""
936
+ return self._status
937
+
938
+ @status.setter
939
+ def status(self, status: LabelingStatus):
940
+ """Set labeling status."""
941
+ self._status = status
942
+ self._nn_created, self._nn_updated = LabelingStatus.to_flags(self.status)
943
+
867
944
  @classmethod
868
945
  def _to_pixel_coordinate_system_json(cls, data: Dict, image_size: List[int]) -> Dict:
869
946
  """
@@ -1312,14 +1312,14 @@ class AnnotationApi(ModuleApi):
1312
1312
 
1313
1313
  api.annotation.update_label(label_id, new_label)
1314
1314
  """
1315
- self._api.post(
1316
- "figures.editInfo",
1317
- {
1318
- ApiField.ID: label_id,
1319
- ApiField.TAGS: [tag.to_json() for tag in label.tags],
1320
- ApiField.GEOMETRY: label.geometry.to_json(),
1321
- },
1322
- )
1315
+ payload = {
1316
+ ApiField.ID: label_id,
1317
+ ApiField.TAGS: [tag.to_json() for tag in label.tags],
1318
+ ApiField.GEOMETRY: label.geometry.to_json(),
1319
+ ApiField.NN_CREATED: label._nn_created,
1320
+ ApiField.NN_UPDATED: label._nn_updated,
1321
+ }
1322
+ self._api.post("figures.editInfo", payload)
1323
1323
 
1324
1324
  def update_label_priority(self, label_id: int, priority: int) -> None:
1325
1325
  """Updates label's priority with given ID in Supervisely.
@@ -27,6 +27,7 @@ from supervisely._utils import batched, logger, run_coroutine
27
27
  from supervisely.api.module_api import ApiField, ModuleApi, RemoveableBulkModuleApi
28
28
  from supervisely.geometry.rectangle import Rectangle
29
29
  from supervisely.video_annotation.key_id_map import KeyIdMap
30
+ from supervisely.annotation.label import LabelingStatus
30
31
 
31
32
 
32
33
  class FigureInfo(NamedTuple):
@@ -221,6 +222,8 @@ class FigureApi(RemoveableBulkModuleApi):
221
222
  "meta",
222
223
  "area",
223
224
  "priority",
225
+ "nnCreated",
226
+ "nnUpdated",
224
227
  ]
225
228
  return self._get_info_by_id(id, "figures.info", {ApiField.FIELDS: fields})
226
229
 
@@ -233,6 +236,7 @@ class FigureApi(RemoveableBulkModuleApi):
233
236
  geometry_type: str,
234
237
  track_id: Optional[int] = None,
235
238
  custom_data: Optional[dict] = None,
239
+ status: Optional[LabelingStatus] = None,
236
240
  ) -> int:
237
241
  """"""
238
242
  input_figure = {
@@ -242,6 +246,13 @@ class FigureApi(RemoveableBulkModuleApi):
242
246
  ApiField.GEOMETRY: geometry_json,
243
247
  }
244
248
 
249
+ if status is None:
250
+ status = LabelingStatus.MANUAL
251
+
252
+ nn_created, nn_updated = LabelingStatus.to_flags(status)
253
+ input_figure[ApiField.NN_CREATED] = nn_created
254
+ input_figure[ApiField.NN_UPDATED] = nn_updated
255
+
245
256
  if track_id is not None:
246
257
  input_figure[ApiField.TRACK_ID] = track_id
247
258
 
@@ -376,6 +387,8 @@ class FigureApi(RemoveableBulkModuleApi):
376
387
  ApiField.AREA,
377
388
  ApiField.PRIORITY,
378
389
  ApiField.CUSTOM_DATA,
390
+ ApiField.NN_CREATED,
391
+ ApiField.NN_UPDATED,
379
392
  ]
380
393
  figures_infos = self.get_list_all_pages(
381
394
  "figures.list",
@@ -496,6 +509,8 @@ class FigureApi(RemoveableBulkModuleApi):
496
509
  ApiField.AREA,
497
510
  ApiField.PRIORITY,
498
511
  ApiField.CUSTOM_DATA,
512
+ ApiField.NN_CREATED,
513
+ ApiField.NN_UPDATED,
499
514
  ]
500
515
  if skip_geometry is True:
501
516
  fields = [x for x in fields if x != ApiField.GEOMETRY]
@@ -854,6 +869,8 @@ class FigureApi(RemoveableBulkModuleApi):
854
869
  ApiField.AREA,
855
870
  ApiField.PRIORITY,
856
871
  ApiField.CUSTOM_DATA,
872
+ ApiField.NN_CREATED,
873
+ ApiField.NN_UPDATED,
857
874
  ]
858
875
  if skip_geometry is True:
859
876
  fields = [x for x in fields if x != ApiField.GEOMETRY]
@@ -709,6 +709,10 @@ class ApiField:
709
709
  """"""
710
710
  UNIQUE_ITEMS = "uniqueItems"
711
711
  """"""
712
+ NN_CREATED = "nnCreated"
713
+ """"""
714
+ NN_UPDATED = "nnUpdated"
715
+ """"""
712
716
 
713
717
 
714
718
  def _get_single_item(items):
@@ -10,7 +10,7 @@ from supervisely.api.module_api import ApiField
10
10
  from supervisely.geometry.geometry import Geometry
11
11
  from supervisely.video_annotation.key_id_map import KeyIdMap
12
12
  from supervisely.video_annotation.video_figure import VideoFigure
13
-
13
+ from supervisely.annotation.label import LabelingStatus
14
14
 
15
15
  class VideoFigureApi(FigureApi):
16
16
  """
@@ -26,6 +26,7 @@ class VideoFigureApi(FigureApi):
26
26
  geometry_type: str,
27
27
  track_id: Optional[int] = None,
28
28
  meta: Optional[dict] = None,
29
+ status: Optional[LabelingStatus] = None,
29
30
  ) -> int:
30
31
  """
31
32
  Create new VideoFigure for given frame in given video ID.
@@ -42,6 +43,10 @@ class VideoFigureApi(FigureApi):
42
43
  :type geometry_type: str
43
44
  :param track_id: int, optional.
44
45
  :type track_id: int, optional
46
+ :param meta: Meta data for VideoFigure.
47
+ :type meta: dict, optional
48
+ :param status: Labeling status. Specifies if the VideoFigure was created by NN model, manually or created by NN and then manually corrected.
49
+ :type status: LabelingStatus, optional
45
50
  :return: New figure ID
46
51
  :rtype: :class:`int`
47
52
  :Usage example:
@@ -64,13 +69,16 @@ class VideoFigureApi(FigureApi):
64
69
  """
65
70
  if meta is None:
66
71
  meta = {}
72
+ meta = {**(meta or {}), ApiField.FRAME: frame_index}
73
+
67
74
  return super().create(
68
75
  video_id,
69
76
  object_id,
70
- {**meta, ApiField.FRAME: frame_index},
77
+ meta,
71
78
  geometry_json,
72
79
  geometry_type,
73
80
  track_id,
81
+ status=status,
74
82
  )
75
83
 
76
84
  def append_bulk(self, video_id: int, figures: List[VideoFigure], key_id_map: KeyIdMap) -> None:
@@ -115,13 +123,15 @@ class VideoFigureApi(FigureApi):
115
123
 
116
124
  self._append_bulk(video_id, figures_json, keys, key_id_map)
117
125
 
118
- def update(self, figure_id: int, geometry: Geometry) -> None:
126
+ def update(self, figure_id: int, geometry: Geometry, status: Optional[LabelingStatus] = None) -> None:
119
127
  """Updates figure feometry with given ID in Supervisely with new Geometry object.
120
128
 
121
129
  :param figure_id: ID of the figure to update
122
130
  :type figure_id: int
123
131
  :param geometry: Supervisely Gepmetry object
124
132
  :type geometry: Geometry
133
+ :param status: Labeling status. Specifies if the VideoFigure was created by NN model, manually or created by NN and then manually corrected.
134
+ :type status: LabelingStatus, optional
125
135
  :Usage example:
126
136
 
127
137
  .. code-block:: python
@@ -141,13 +151,17 @@ class VideoFigureApi(FigureApi):
141
151
 
142
152
  api.video.figure.update(figure_id, new_geometry)
143
153
  """
144
- self._api.post(
145
- "figures.editInfo",
146
- {
147
- ApiField.ID: figure_id,
148
- ApiField.GEOMETRY: geometry.to_json(),
149
- },
150
- )
154
+ payload = {
155
+ ApiField.ID: figure_id,
156
+ ApiField.GEOMETRY: geometry.to_json(),
157
+ }
158
+
159
+ if status is not None:
160
+ nn_created,nn_updated = LabelingStatus.to_flags(status)
161
+ payload[ApiField.NN_CREATED] = nn_created
162
+ payload[ApiField.NN_UPDATED] = nn_updated
163
+
164
+ self._api.post("figures.editInfo", payload)
151
165
 
152
166
  def download(
153
167
  self, dataset_id: int, video_ids: List[int] = None, skip_geometry: bool = False, **kwargs
@@ -161,7 +175,6 @@ class VideoFigureApi(FigureApi):
161
175
  :type video_ids: List[int], optional
162
176
  :param skip_geometry: Skip the download of figure geometry. May be useful for a significant api request speed increase in the large datasets.
163
177
  :type skip_geometry: bool
164
-
165
178
  :return: A dictionary where keys are video IDs and values are lists of figures.
166
179
  :rtype: :class: `Dict[int, List[FigureInfo]]`
167
180
  """
@@ -45,7 +45,7 @@ from supervisely._utils import (
45
45
  rand_str,
46
46
  )
47
47
  from supervisely.annotation.annotation import Annotation
48
- from supervisely.annotation.label import Label
48
+ from supervisely.annotation.label import Label, LabelingStatus
49
49
  from supervisely.annotation.obj_class import ObjClass
50
50
  from supervisely.annotation.tag_collection import TagCollection
51
51
  from supervisely.annotation.tag_meta import TagMeta, TagValueType
@@ -1269,16 +1269,16 @@ class Inference:
1269
1269
 
1270
1270
  def get_classes(self) -> List[str]:
1271
1271
  return self.classes
1272
-
1272
+
1273
1273
  def _tracker_init(self, tracker: str, tracker_settings: dict):
1274
1274
  # Check if tracking is supported for this model
1275
1275
  info = self.get_info()
1276
1276
  tracking_support = info.get("tracking_on_videos_support", False)
1277
-
1277
+
1278
1278
  if not tracking_support:
1279
1279
  logger.debug("Tracking is not supported for this model")
1280
1280
  return None
1281
-
1281
+
1282
1282
  if tracker == "botsort":
1283
1283
  from supervisely.nn.tracker import BotSortTracker
1284
1284
  device = tracker_settings.get("device", self.device)
@@ -1289,7 +1289,6 @@ class Inference:
1289
1289
  logger.warning(f"Unknown tracking type: {tracker}. Tracking is disabled.")
1290
1290
  return None
1291
1291
 
1292
-
1293
1292
  def get_info(self) -> Dict[str, Any]:
1294
1293
  num_classes = None
1295
1294
  classes = None
@@ -1439,8 +1438,12 @@ class Inference:
1439
1438
  # for example empty mask
1440
1439
  continue
1441
1440
  if isinstance(label, list):
1441
+ for lb in label:
1442
+ lb.status = LabelingStatus.AUTO
1442
1443
  labels.extend(label)
1443
1444
  continue
1445
+
1446
+ label.status = LabelingStatus.AUTO
1444
1447
  labels.append(label)
1445
1448
 
1446
1449
  # create annotation with correct image resolution
@@ -1872,7 +1875,7 @@ class Inference:
1872
1875
  n_frames = frames_reader.frames_count()
1873
1876
 
1874
1877
  self._tracker = self._tracker_init(state.get("tracker", None), state.get("tracker_settings", {}))
1875
-
1878
+
1876
1879
  progress_total = (n_frames + step - 1) // step
1877
1880
  inference_request.set_stage(InferenceRequest.Stage.INFERENCE, 0, progress_total)
1878
1881
 
@@ -1896,32 +1899,31 @@ class Inference:
1896
1899
  source=frames,
1897
1900
  settings=inference_settings,
1898
1901
  )
1899
-
1902
+
1900
1903
  if self._tracker is not None:
1901
1904
  anns = self._apply_tracker_to_anns(frames, anns)
1902
-
1905
+
1903
1906
  predictions = [
1904
1907
  Prediction(ann, model_meta=self.model_meta, frame_index=frame_index)
1905
1908
  for ann, frame_index in zip(anns, batch)
1906
1909
  ]
1907
-
1910
+
1908
1911
  for pred, this_slides_data in zip(predictions, slides_data):
1909
1912
  pred.extra_data["slides_data"] = this_slides_data
1910
1913
  batch_results = self._format_output(predictions)
1911
-
1914
+
1912
1915
  inference_request.add_results(batch_results)
1913
1916
  inference_request.done(len(batch_results))
1914
1917
  logger.debug(f"Frames {batch[0]}-{batch[-1]} done.")
1915
1918
  video_ann_json = None
1916
1919
  if self._tracker is not None:
1917
1920
  inference_request.set_stage("Postprocess...", 0, 1)
1918
-
1921
+
1919
1922
  video_ann_json = self._tracker.video_annotation.to_json()
1920
1923
  inference_request.done()
1921
1924
  result = {"ann": results, "video_ann": video_ann_json}
1922
1925
  inference_request.final_result = result.copy()
1923
1926
  return video_ann_json
1924
-
1925
1927
 
1926
1928
  def _inference_image_ids(
1927
1929
  self,
@@ -2102,7 +2104,7 @@ class Inference:
2102
2104
  n_frames = video_info.frames_count
2103
2105
 
2104
2106
  self._tracker = self._tracker_init(state.get("tracker", None), state.get("tracker_settings", {}))
2105
-
2107
+
2106
2108
  logger.debug(
2107
2109
  f"Video info:",
2108
2110
  extra=dict(
@@ -2137,10 +2139,10 @@ class Inference:
2137
2139
  source=frames,
2138
2140
  settings=inference_settings,
2139
2141
  )
2140
-
2142
+
2141
2143
  if self._tracker is not None:
2142
2144
  anns = self._apply_tracker_to_anns(frames, anns)
2143
-
2145
+
2144
2146
  predictions = [
2145
2147
  Prediction(
2146
2148
  ann,
@@ -2155,7 +2157,7 @@ class Inference:
2155
2157
  for pred, this_slides_data in zip(predictions, slides_data):
2156
2158
  pred.extra_data["slides_data"] = this_slides_data
2157
2159
  batch_results = self._format_output(predictions)
2158
-
2160
+
2159
2161
  inference_request.add_results(batch_results)
2160
2162
  inference_request.done(len(batch_results))
2161
2163
  logger.debug(f"Frames {batch[0]}-{batch[-1]} done.")
@@ -2637,6 +2639,10 @@ class Inference:
2637
2639
  for prediction in predictions:
2638
2640
  ds_predictions[prediction.dataset_id].append(prediction)
2639
2641
 
2642
+ def update_labeling_status(ann: Annotation) -> Annotation:
2643
+ for label in ann.labels:
2644
+ label.status = LabelingStatus.AUTO
2645
+
2640
2646
  def _new_name(image_info: ImageInfo):
2641
2647
  name = Path(image_info.name)
2642
2648
  stem = name.stem
@@ -2712,8 +2718,15 @@ class Inference:
2712
2718
  iou=iou_merge_threshold,
2713
2719
  meta=project_meta,
2714
2720
  )
2721
+
2722
+ # Update labeling status of new predictions before upload
2723
+ anns_with_nn_flags = []
2715
2724
  for pred, ann in zip(preds, anns):
2725
+ update_labeling_status(ann)
2716
2726
  pred.annotation = ann
2727
+ anns_with_nn_flags.append(ann)
2728
+
2729
+ anns = anns_with_nn_flags
2717
2730
 
2718
2731
  context.setdefault("image_info", {})
2719
2732
  missing = [
@@ -2778,7 +2791,10 @@ class Inference:
2778
2791
  iou=iou_merge_threshold,
2779
2792
  meta=project_meta,
2780
2793
  )
2794
+
2795
+ # Update labeling status of predicted labels before optional merge
2781
2796
  for pred, ann in zip(preds, anns):
2797
+ update_labeling_status(ann)
2782
2798
  pred.annotation = ann
2783
2799
 
2784
2800
  if upload_mode in ["iou_merge", "append"]:
@@ -4141,14 +4157,14 @@ class Inference:
4141
4157
  matches = self._tracker.update(frame, ann)
4142
4158
  track_ids = [match["track_id"] for match in matches]
4143
4159
  tracked_labels = [match["label"] for match in matches]
4144
-
4160
+
4145
4161
  filtered_annotation = ann.clone(
4146
4162
  labels=tracked_labels,
4147
4163
  custom_data=track_ids
4148
4164
  )
4149
4165
  updated_anns.append(filtered_annotation)
4150
4166
  return updated_anns
4151
-
4167
+
4152
4168
  def _add_workflow_input(self, model_source: str, model_files: dict, model_info: dict):
4153
4169
  if model_source == ModelSource.PRETRAINED:
4154
4170
  checkpoint_url = model_info["meta"]["model_files"]["checkpoint"]
@@ -7,7 +7,7 @@ import numpy as np
7
7
  from pydantic import ValidationError
8
8
 
9
9
  from supervisely.annotation.annotation import Annotation
10
- from supervisely.annotation.label import Geometry, Label
10
+ from supervisely.annotation.label import Geometry, Label, LabelingStatus
11
11
  from supervisely.annotation.obj_class import ObjClass
12
12
  from supervisely.api.api import Api
13
13
  from supervisely.api.module_api import ApiField
@@ -588,8 +588,12 @@ class BBoxTracking(BaseTracking):
588
588
  # for example empty mask
589
589
  continue
590
590
  if isinstance(label, list):
591
+ for lb in label:
592
+ lb.status = LabelingStatus.AUTO
591
593
  labels.extend(label)
592
594
  continue
595
+
596
+ label.status = LabelingStatus.AUTO
593
597
  labels.append(label)
594
598
 
595
599
  # create annotation with correct image resolution
@@ -10,7 +10,7 @@ from pydantic import ValidationError
10
10
 
11
11
  import supervisely.nn.inference.tracking.functional as F
12
12
  from supervisely.annotation.annotation import Annotation
13
- from supervisely.annotation.label import Geometry, Label
13
+ from supervisely.annotation.label import Geometry, Label, LabelingStatus
14
14
  from supervisely.annotation.obj_class import ObjClass
15
15
  from supervisely.api.api import Api
16
16
  from supervisely.api.module_api import ApiField
@@ -610,8 +610,12 @@ class PointTracking(BaseTracking):
610
610
  # for example empty mask
611
611
  continue
612
612
  if isinstance(label, list):
613
+ for lb in label:
614
+ lb.status = LabelingStatus.AUTO
613
615
  labels.extend(label)
614
616
  continue
617
+
618
+ label.status = LabelingStatus.AUTO
615
619
  labels.append(label)
616
620
 
617
621
  # create annotation with correct image resolution
@@ -22,6 +22,7 @@ from supervisely.geometry.rectangle import Rectangle
22
22
  from supervisely.nn.inference.cache import InferenceImageCache
23
23
  from supervisely.sly_logger import logger
24
24
  from supervisely.video_annotation.key_id_map import KeyIdMap
25
+ from supervisely.annotation.label import LabelingStatus
25
26
 
26
27
 
27
28
  class TrackerInterface:
@@ -166,6 +167,8 @@ class TrackerInterface:
166
167
  ApiField.GEOMETRY: geometry.to_json(),
167
168
  ApiField.META: {ApiField.FRAME: frame_index},
168
169
  ApiField.TRACK_ID: self.track_id,
170
+ ApiField.NN_CREATED: True,
171
+ ApiField.NN_UPDATED: True,
169
172
  }
170
173
  for geometry, frame_index in geometries_frame_indexes
171
174
  ]
@@ -195,6 +198,7 @@ class TrackerInterface:
195
198
  geometry.to_json(),
196
199
  geometry.geometry_name(),
197
200
  self.track_id,
201
+ status=LabelingStatus.AUTO,
198
202
  )
199
203
  self.logger.debug(f"Added {geometry.geometry_name()} to frame #{frame_ind}")
200
204
  if notify:
@@ -59,6 +59,7 @@ class Prediction:
59
59
  self.source = source
60
60
  if isinstance(annotation_json, Annotation):
61
61
  annotation_json = annotation_json.to_json()
62
+
62
63
  self.annotation_json = annotation_json
63
64
  self.model_meta = model_meta
64
65
  if isinstance(self.model_meta, dict):
@@ -157,7 +158,7 @@ class Prediction:
157
158
 
158
159
  @property
159
160
  def annotation(self) -> Annotation:
160
- if self._annotation is None:
161
+ if self._annotation is None and self.annotation_json is not None:
161
162
  if self.model_meta is None:
162
163
  raise ValueError("Model meta is not provided. Cannot create annotation.")
163
164
  model_meta = get_meta_from_annotation(self.annotation_json, self.model_meta)
@@ -71,7 +71,7 @@ class PredictionSession:
71
71
  tracking_config: dict = None,
72
72
  **kwargs: dict,
73
73
  ):
74
-
74
+
75
75
  extra_input_args = ["image_ids", "video_ids", "dataset_ids", "project_ids"]
76
76
  assert (
77
77
  sum(
@@ -90,7 +90,6 @@ class PredictionSession:
90
90
  == 1
91
91
  ), "Exactly one of input, image_ids, video_id, dataset_id, project_id or image_id must be provided."
92
92
 
93
-
94
93
  self._iterator = None
95
94
  self._base_url = url
96
95
  self.inference_request_uuid = None
@@ -115,12 +114,12 @@ class PredictionSession:
115
114
  self.inference_settings = {
116
115
  k: v for k, v in kwargs.items() if isinstance(v, (str, int, float))
117
116
  }
118
-
117
+
119
118
  if tracking is True:
120
119
  model_info = self._get_session_info()
121
120
  if not model_info.get("tracking_on_videos_support", False):
122
121
  raise ValueError("Tracking is not supported by this model")
123
-
122
+
124
123
  if tracking_config is None:
125
124
  self.tracker = "botsort"
126
125
  self.tracker_settings = {}
@@ -286,7 +285,7 @@ class PredictionSession:
286
285
  if self.api is not None:
287
286
  return self.api.token
288
287
  return env.api_token(raise_not_found=False)
289
-
288
+
290
289
  def _get_json_body(self):
291
290
  body = {"state": {}, "context": {}}
292
291
  if self.inference_request_uuid is not None:
@@ -298,7 +297,7 @@ class PredictionSession:
298
297
  if "model_prediction_suffix" in self.kwargs:
299
298
  body["state"]["model_prediction_suffix"] = self.kwargs["model_prediction_suffix"]
300
299
  return body
301
-
300
+
302
301
  def _post(self, method, *args, retries=5, **kwargs) -> requests.Response:
303
302
  if kwargs.get("headers") is None:
304
303
  kwargs["headers"] = {}
@@ -336,7 +335,7 @@ class PredictionSession:
336
335
  method = "get_session_info"
337
336
  r = self._post(method, json=self._get_json_body())
338
337
  return r.json()
339
-
338
+
340
339
  def _get_inference_progress(self):
341
340
  method = "get_inference_progress"
342
341
  r = self._post(method, json=self._get_json_body())
@@ -365,9 +364,21 @@ class PredictionSession:
365
364
  logger.info("Inference request will be cleared on the server")
366
365
  return r.json()
367
366
 
367
+ def _get_final_result(self):
368
+ method = "get_inference_result"
369
+ r = self._post(
370
+ method,
371
+ json=self._get_json_body(),
372
+ )
373
+ return r.json()
374
+
368
375
  def _on_infernce_end(self):
369
376
  if self.inference_request_uuid is None:
370
377
  return
378
+ try:
379
+ self.final_result = self._get_final_result()
380
+ except Exception as e:
381
+ logger.debug("Failed to get final result:", exc_info=True)
371
382
  self._clear_inference_request()
372
383
 
373
384
  @property
@@ -1,7 +1,7 @@
1
1
  import supervisely as sly
2
2
  from supervisely.nn.tracker.base_tracker import BaseTracker
3
3
  from supervisely import Annotation, VideoAnnotation
4
-
4
+ from supervisely.annotation.label import LabelingStatus
5
5
  from dataclasses import dataclass
6
6
  from types import SimpleNamespace
7
7
  from typing import List, Dict, Tuple, Any, Optional
@@ -239,7 +239,7 @@ class BotSortTracker(BaseTracker):
239
239
 
240
240
  video_object = video_objects[track_id]
241
241
  rect = sly.Rectangle(top=y1, left=x1, bottom=y2, right=x2)
242
- frame_figures.append(sly.VideoFigure(video_object, rect, frame_idx, track_id=str(track_id)))
242
+ frame_figures.append(sly.VideoFigure(video_object, rect, frame_idx, track_id=str(track_id), status=LabelingStatus.AUTO))
243
243
 
244
244
  frames.append(sly.Frame(frame_idx, frame_figures))
245
245
 
@@ -1,4 +1,3 @@
1
-
2
1
  from typing import List, Union, Dict, Tuple
3
2
  from pathlib import Path
4
3
  from collections import defaultdict
@@ -6,6 +5,7 @@ import numpy as np
6
5
 
7
6
  import supervisely as sly
8
7
  from supervisely.nn.model.prediction import Prediction
8
+ from supervisely.annotation.label import LabelingStatus
9
9
  from supervisely import VideoAnnotation
10
10
  from supervisely import logger
11
11
 
@@ -73,12 +73,11 @@ def predictions_to_video_annotation(
73
73
 
74
74
  video_object = video_objects[track_id]
75
75
  rect = sly.Rectangle(top=top, left=left, bottom=bottom, right=right)
76
- frame_figures.append(sly.VideoFigure(video_object, rect, frame_idx, track_id=str(track_id)))
76
+ frame_figures.append(sly.VideoFigure(video_object, rect, frame_idx, track_id=str(track_id), status=LabelingStatus.AUTO))
77
77
 
78
78
  frames.append(sly.Frame(frame_idx, frame_figures))
79
79
 
80
- objects = list(video_objects.values())
81
-
80
+ objects = list(video_objects.values())
82
81
  return VideoAnnotation(
83
82
  img_size=frame_shape,
84
83
  frames_count=len(predictions),
@@ -271,4 +270,4 @@ def mot_to_video_annotation(
271
270
 
272
271
  logger.info(f"Created VideoAnnotation with {len(objects)} tracks and {frames_count} frames")
273
272
 
274
- return annotation
273
+ return annotation
@@ -24,6 +24,8 @@ from supervisely.video_annotation.key_id_map import KeyIdMap
24
24
  from supervisely.video_annotation.video_object import VideoObject
25
25
  from supervisely.video_annotation.video_object_collection import VideoObjectCollection
26
26
 
27
+ from supervisely.annotation.label import LabelingStatus
28
+
27
29
 
28
30
  class OutOfImageBoundsException(Exception):
29
31
  pass
@@ -55,6 +57,8 @@ class VideoFigure:
55
57
  :type smart_tool_input: dict, optional
56
58
  :param priority: Priority of the figure (position of the figure relative to other overlapping or underlying figures).
57
59
  :type priority: int, optional
60
+ :param status: Sets labeling status. Shows how label was created and corrected.
61
+ :type status: LabelingStatus, optional
58
62
  :Usage example:
59
63
 
60
64
  .. code-block:: python
@@ -86,7 +90,9 @@ class VideoFigure:
86
90
  # ],
87
91
  # "interior": []
88
92
  # }
89
- # }
93
+ # },
94
+ # "nnCreated": false,
95
+ # "nnUpdated": false
90
96
  # }
91
97
  """
92
98
 
@@ -103,6 +109,7 @@ class VideoFigure:
103
109
  track_id: Optional[str] = None,
104
110
  smart_tool_input: Optional[Dict] = None,
105
111
  priority: Optional[int] = None,
112
+ status: Optional[LabelingStatus] = None,
106
113
  ):
107
114
  self._video_object = video_object
108
115
  self._set_geometry_inplace(geometry)
@@ -116,6 +123,11 @@ class VideoFigure:
116
123
  self._smart_tool_input = smart_tool_input
117
124
  self._priority = priority
118
125
 
126
+ if status is None:
127
+ status = LabelingStatus.MANUAL
128
+ self._status = status
129
+ self._nn_created, self._nn_updated = LabelingStatus.to_flags(self.status)
130
+
119
131
  def _add_creation_info(self, d):
120
132
  if self.labeler_login is not None:
121
133
  d[LABELER_LOGIN] = self.labeler_login
@@ -339,9 +351,9 @@ class VideoFigure:
339
351
  # "interior": []
340
352
  # }
341
353
  # },
342
- # "meta": {
343
- # "frame": 7
344
- # }
354
+ # "meta": {"frame": 7},
355
+ # "nnCreated": false,
356
+ # "nnUpdated": false
345
357
  # }
346
358
  """
347
359
  data_json = {
@@ -349,6 +361,8 @@ class VideoFigure:
349
361
  OBJECT_KEY: self.parent_object.key().hex,
350
362
  ApiField.GEOMETRY_TYPE: self.geometry.geometry_name(),
351
363
  ApiField.GEOMETRY: self.geometry.to_json(),
364
+ ApiField.NN_CREATED: self._nn_created,
365
+ ApiField.NN_UPDATED: self._nn_updated,
352
366
  }
353
367
 
354
368
  if key_id_map is not None:
@@ -473,6 +487,10 @@ class VideoFigure:
473
487
  smart_tool_input = data.get(ApiField.SMART_TOOL_INPUT, None)
474
488
  priority = data.get(ApiField.PRIORITY, None)
475
489
 
490
+ nn_created = data.get(ApiField.NN_CREATED, False)
491
+ nn_updated = data.get(ApiField.NN_UPDATED, False)
492
+ status = LabelingStatus.from_flags(nn_created, nn_updated)
493
+
476
494
  return cls(
477
495
  object,
478
496
  geometry,
@@ -485,6 +503,7 @@ class VideoFigure:
485
503
  track_id=track_id,
486
504
  smart_tool_input=smart_tool_input,
487
505
  priority=priority,
506
+ status=status,
488
507
  )
489
508
 
490
509
  def clone(
@@ -500,6 +519,7 @@ class VideoFigure:
500
519
  track_id: Optional[str] = None,
501
520
  smart_tool_input: Optional[Dict] = None,
502
521
  priority: Optional[int] = None,
522
+ status: Optional[LabelingStatus] = None,
503
523
  ) -> VideoFigure:
504
524
  """
505
525
  Makes a copy of VideoFigure with new fields, if fields are given, otherwise it will use fields of the original VideoFigure.
@@ -526,6 +546,8 @@ class VideoFigure:
526
546
  :type smart_tool_input: dict, optional
527
547
  :param priority: Priority of the figure (position of the figure relative to other overlapping or underlying figures).
528
548
  :type priority: int, optional
549
+ :param status: Sets labeling status. Specifies if the VideoFigure was created by NN model, manually or created by NN and then manually corrected.
550
+ :type status: LabelingStatus, optional
529
551
  :return: VideoFigure object
530
552
  :rtype: :class:`VideoFigure`
531
553
 
@@ -582,8 +604,20 @@ class VideoFigure:
582
604
  track_id=take_with_default(track_id, self.track_id),
583
605
  smart_tool_input=take_with_default(smart_tool_input, self._smart_tool_input),
584
606
  priority=take_with_default(priority, self._priority),
607
+ status=take_with_default(status, self.status),
585
608
  )
586
609
 
610
+ @property
611
+ def status(self) -> LabelingStatus:
612
+ """Labeling status. Specifies if the VideoFigure was created by NN model, manually or created by NN and then manually corrected."""
613
+ return self._status
614
+
615
+ @status.setter
616
+ def status(self, status: LabelingStatus):
617
+ """Set labeling status."""
618
+ self._status = status
619
+ self._nn_created, self._nn_updated = LabelingStatus.to_flags(self.status)
620
+
587
621
  def validate_bounds(
588
622
  self, img_size: Tuple[int, int], _auto_correct: Optional[bool] = False
589
623
  ) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.439
3
+ Version: 6.73.440
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -131,6 +131,7 @@ Requires-Dist: tensorboard; extra == "tracking"
131
131
  Requires-Dist: decord; extra == "tracking"
132
132
  Requires-Dist: gdown; extra == "tracking"
133
133
  Requires-Dist: torch; extra == "tracking"
134
+ Requires-Dist: motmetrics; extra == "tracking"
134
135
  Provides-Extra: training
135
136
  Requires-Dist: pycocotools; extra == "training"
136
137
  Requires-Dist: scikit-learn; extra == "training"
@@ -9,7 +9,7 @@ supervisely/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
9
9
  supervisely/annotation/annotation.py,sha256=th4gsIU-LNGcMRohHrtupmjxDwdzx1g4_0xIAa6NyJU,114717
10
10
  supervisely/annotation/annotation_transforms.py,sha256=TlVy_gUbM-XH6GbLpZPrAi6pMIGTr7Ow02iSKOSTa-I,9582
11
11
  supervisely/annotation/json_geometries_map.py,sha256=nL6AmMhFy02fw9ryBm75plKyOkDh61QdOToSuLAcz_Q,1659
12
- supervisely/annotation/label.py,sha256=FzILYIvkk4cSUzdHLlmYJyWw8L3rfOEEhNkHi0Qsr_E,37510
12
+ supervisely/annotation/label.py,sha256=sOK6lGDa-uSNCb7o4F9BJwnPia-Qp36OmFOU8oHyHPA,40601
13
13
  supervisely/annotation/obj_class.py,sha256=W7-958-E9TfsL7eKAI3bbOvfAVxd3Unq-7F3lc2Gxjg,16672
14
14
  supervisely/annotation/obj_class_collection.py,sha256=lsBJ8mElvwMHky2vsj4GfZ9_Uq186eS-o4ldoNeUJnw,12416
15
15
  supervisely/annotation/obj_class_mapper.py,sha256=aIJDoRULqcAOD2a1CQPk2OOF8k3VPPSJQZdBAj71VQc,943
@@ -22,7 +22,7 @@ supervisely/annotation/tag_meta_mapper.py,sha256=RWeTrxJ64syodyhXIRSH007bX6Hr3B4
22
22
  supervisely/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  supervisely/api/advanced_api.py,sha256=Nd5cCnHFWc3PSUrCtENxTGtDjS37_lCHXsgXvUI3Ti8,2054
24
24
  supervisely/api/agent_api.py,sha256=8EQBwD6v7KLS0-xKcZ12B7mtzKwG7RRgq1fk1vaN144,8893
25
- supervisely/api/annotation_api.py,sha256=JdcCKuy_7PvtNcHsRhi4ANhn3aynLY44rtbqau2Y9A4,82891
25
+ supervisely/api/annotation_api.py,sha256=TNOqVGE94FqDc7WDLBZiDY3aSIiyTQwn_bZv5_CIXBw,82970
26
26
  supervisely/api/api.py,sha256=gRItQzO6Xj7k_pJIpVUS2dV1vkTTHV25_1Uia6xxZSc,67930
27
27
  supervisely/api/app_api.py,sha256=Q6XxLxp3D_Vc3PIVyBmP7wJtTLbgYCPNOLND5UvJhMw,79010
28
28
  supervisely/api/constants.py,sha256=WfqIcEpRnU4Mcfb6q0njeRs2VVSoTAJaIyrqBkBjP8I,253
@@ -36,7 +36,7 @@ supervisely/api/import_storage_api.py,sha256=BDCgmR0Hv6OoiRHLCVPKt3iDxSVlQp1WrnK
36
36
  supervisely/api/issues_api.py,sha256=BqDJXmNoTzwc3xe6_-mA7FDFC5QQ-ahGbXk_HmpkSeQ,17925
37
37
  supervisely/api/labeling_job_api.py,sha256=G2_BV_WtA2lAhfw_nAQmWmv1P-pwimD0ba9GVKoGjiA,55537
38
38
  supervisely/api/labeling_queue_api.py,sha256=ilNjAL1d9NSa9yabQn6E-W26YdtooT3ZGXIFZtGnAvY,30158
39
- supervisely/api/module_api.py,sha256=8Asdr3llhC8XQ98xGdR03hpe2GYznJONzNfgN-mQYv8,46458
39
+ supervisely/api/module_api.py,sha256=cs7kTsOTjI38iZRheFAcPjpFupjrGj5UOf0OaH-Fc_0,46538
40
40
  supervisely/api/object_class_api.py,sha256=7-npNFMYjWNtSXYZg6syc6bX56_oCzDU2kFRPGQWCwA,10399
41
41
  supervisely/api/plugin_api.py,sha256=SFm0IlTTOjuHBLUMgG4d4k6U3cWJocE-SVb-f08fwMQ,5286
42
42
  supervisely/api/project_api.py,sha256=rZfPGwswx25-QXEgXwKIaCr5IEQJDA78s_2S92nAroY,104652
@@ -52,7 +52,7 @@ supervisely/api/video_annotation_tool_api.py,sha256=3A9-U8WJzrTShP_n9T8U01M9FzGY
52
52
  supervisely/api/workspace_api.py,sha256=24O9uR5eIA2JdD0eQLi9LGaaHISdb2gUqnxJtx7bTew,9222
53
53
  supervisely/api/entity_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  supervisely/api/entity_annotation/entity_annotation_api.py,sha256=R7irdsYmUecsibuUFbcPRiS6tV3GnCHi9NfWeuoN7_0,3085
55
- supervisely/api/entity_annotation/figure_api.py,sha256=0tG-eJ3HEzcOSQBKSmsAzB-tQ2uZZLyBGsYxA1Bk5us,38052
55
+ supervisely/api/entity_annotation/figure_api.py,sha256=DN0mL40ZIoDoVQtCoUfcff9AEKcAoKRYDi6zdHDR7rg,38652
56
56
  supervisely/api/entity_annotation/object_api.py,sha256=gbcNvN_KY6G80Me8fHKQgryc2Co7VU_kfFd1GYILZ4E,8875
57
57
  supervisely/api/entity_annotation/tag_api.py,sha256=IapvSZmakjdOn0yvqP2tQRY8gkZg0bcvIZBwWRcafrg,18996
58
58
  supervisely/api/nn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -72,7 +72,7 @@ supervisely/api/pointcloud/pointcloud_tag_api.py,sha256=iShtr052nOElxsyMyZEUT2vy
72
72
  supervisely/api/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
73
  supervisely/api/video/video_annotation_api.py,sha256=LAdZUC5qB6Q3ufDEUfWERYiglM3I_MYg9Yv1Nn6aKZ4,14137
74
74
  supervisely/api/video/video_api.py,sha256=jeW-UjQt5xt7qQHOyTgFc5qe7SergCadxfeNgpLDx-I,95727
75
- supervisely/api/video/video_figure_api.py,sha256=quksohjhgrK2l2-PtbbNE99fOW6uWXX59-_4xfc-I-k,6244
75
+ supervisely/api/video/video_figure_api.py,sha256=T7mka1EG16NBlWezwQB0AeoEQrDDjf_MDPfe_eO9BVE,7107
76
76
  supervisely/api/video/video_frame_api.py,sha256=4GwSI4xdCNYEUvTqzKc-Ewd44fw5zqkFoD24jrrN_aY,10214
77
77
  supervisely/api/video/video_object_api.py,sha256=IC0NP8EoIT_d3xxDRgz2cA3ixSiuJ5ymy64eS-RfmDM,2227
78
78
  supervisely/api/video/video_tag_api.py,sha256=wPe1HeJyg9kV1z2UJq6BEte5sKBoPJ2UGAHpGivis9c,14911
@@ -904,7 +904,7 @@ supervisely/nn/benchmark/visualization/widgets/table/__init__.py,sha256=47DEQpj8
904
904
  supervisely/nn/benchmark/visualization/widgets/table/table.py,sha256=atmDnF1Af6qLQBUjLhK18RMDKAYlxnsuVHMSEa5a-e8,4319
905
905
  supervisely/nn/inference/__init__.py,sha256=QFukX2ip-U7263aEPCF_UCFwj6EujbMnsgrXp5Bbt8I,1623
906
906
  supervisely/nn/inference/cache.py,sha256=rfmb1teJ9lNDfisUSh6bwDCVkPZocn8GMvDgLQktnbo,35023
907
- supervisely/nn/inference/inference.py,sha256=K4ZYGbfZ4aNvT-1a0PiNK-bMUYI53I03t8enVMxyo9A,202637
907
+ supervisely/nn/inference/inference.py,sha256=sr70lji4u7V5MsZBiUBBUuc8_dL_FsNLboAPexAq0HU,203145
908
908
  supervisely/nn/inference/inference_request.py,sha256=y6yw0vbaRRcEBS27nq3y0sL6Gmq2qLA_Bm0GrnJGegE,14267
909
909
  supervisely/nn/inference/session.py,sha256=XUqJ_CqHk3ZJYkWxdnErN_6afCpIBU76nq6Ek7DiOQI,35792
910
910
  supervisely/nn/inference/uploader.py,sha256=Dn5MfMRq7tclEWpP0B9fJjTiQPBpwumfXxC8-lOYgnM,5659
@@ -952,13 +952,13 @@ supervisely/nn/inference/semantic_segmentation/__init__.py,sha256=47DEQpj8HBSa-_
952
952
  supervisely/nn/inference/semantic_segmentation/semantic_segmentation.py,sha256=xpmViSYm1v_ZxlYyqiD_DiB7_LEynv9ZoU0t2QHEx8A,3370
953
953
  supervisely/nn/inference/tracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
954
954
  supervisely/nn/inference/tracking/base_tracking.py,sha256=pAxmuiPyuMuwSaOkLedqSVnqiZjk2Wlt03kyiLl5oxA,12434
955
- supervisely/nn/inference/tracking/bbox_tracking.py,sha256=nE8Vtd4sxu07eSa2bUcTwIo6WmB4bIelKvTh5gjA1ns,23765
955
+ supervisely/nn/inference/tracking/bbox_tracking.py,sha256=ScEj9Ce3n-vIQsaNm9cGDy6KRKhvjQ1FUQ2CAVgjSyE,23914
956
956
  supervisely/nn/inference/tracking/functional.py,sha256=LpVu2gvOOpr9D_uvwTPZey1wUCAhV-E20RPKmCSIrK4,1774
957
957
  supervisely/nn/inference/tracking/mask_tracking.py,sha256=Sl7HzznNIvUmCfPporOqDa2kbSmeTvU1hSkLgeWg3kc,25499
958
958
  supervisely/nn/inference/tracking/object_tracking_3d.py,sha256=Kqvx1qe1G8F1VtdBiy2HJ251rJU6s3LWhj0ZedhrmUw,4327
959
- supervisely/nn/inference/tracking/point_tracking.py,sha256=jQduMpFrntITDRCNb2q93TwSfkge4T_2nMJ71iJtzqM,24799
959
+ supervisely/nn/inference/tracking/point_tracking.py,sha256=8y20hzS8qDAZlAQhr-tLKUMyckklg-k1nyW6B8ZmG0k,24948
960
960
  supervisely/nn/inference/tracking/tracker3d_interface.py,sha256=7yIkNO9rgkzQuyXUUccLwqlv5k7RPbxTqz9uI4FylLE,2781
961
- supervisely/nn/inference/tracking/tracker_interface.py,sha256=nk2mhJXg4Xj5i5kWOoSzJ8w4N51RGA7GCGLcUbdVDR4,24038
961
+ supervisely/nn/inference/tracking/tracker_interface.py,sha256=1zsOO0AVfT0kJk6QqxkMJe_imkMHom7FquzpcVD2j9Y,24228
962
962
  supervisely/nn/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
963
963
  supervisely/nn/legacy/config.py,sha256=TKdyGtURJKzKoyydCZAfujoUnbC0SO8GeVLTSnoyS_w,2994
964
964
  supervisely/nn/legacy/dataset.py,sha256=-56EI6OYbkTWx4y8hOgD76y47zUoJNjGFyZ6JaP8iqg,6055
@@ -992,13 +992,13 @@ supervisely/nn/legacy/training/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
992
992
  supervisely/nn/legacy/training/eval_planner.py,sha256=zN9b0_CX7sWGdC8e6riTvD-NOUc3_Xduyhj00S7PEIo,1311
993
993
  supervisely/nn/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
994
994
  supervisely/nn/model/model_api.py,sha256=tSstGGdzm3cHc81P7IoM447sMVesUYJpspzMqUY70pg,10322
995
- supervisely/nn/model/prediction.py,sha256=5a-SLvxV3h6dp5KUs1ENZBY-rkWpddShjI8DBWQHhtU,11945
996
- supervisely/nn/model/prediction_session.py,sha256=W7DKIWvufCUQhIdk8q_fTsIOxW_DuZbkr1j_NVcT5gk,27386
995
+ supervisely/nn/model/prediction.py,sha256=gt4c80LkcBFd5-a2iHpShPDTRO81MKHSWiBp47Gb1z0,11983
996
+ supervisely/nn/model/prediction_session.py,sha256=9fPECqnRJLqi2HCJINhDabB7IbgKWAMbDHIxt4RDJeE,27691
997
997
  supervisely/nn/tracker/__init__.py,sha256=1Pv1zLedcZaTk1BS3ezscQbVizq7vQABlNbLhEhHkOI,326
998
998
  supervisely/nn/tracker/base_tracker.py,sha256=2d23JlHizOqVye324YT20EE8RP52uwoQUkPYvPXJTdw,1668
999
- supervisely/nn/tracker/botsort_tracker.py,sha256=scQIessMnF9xaBFkAkSDnUfY0jYEftpod1nUxMisZXU,10141
999
+ supervisely/nn/tracker/botsort_tracker.py,sha256=F2OaoeK1EAlBKAY95Fd9ZooZIlOZBh4YThhzmKNyP6w,10224
1000
1000
  supervisely/nn/tracker/calculate_metrics.py,sha256=JjXI4VYWYSZ5j2Ed81FNYozkS3v2UAM73ztjLrHGg58,10434
1001
- supervisely/nn/tracker/utils.py,sha256=UxGXcMfFgqh7y26oSk9MIeG_lOECn9kbytQWkiGVL2A,10046
1001
+ supervisely/nn/tracker/utils.py,sha256=4WdtFHSEx5Buq6aND7cD21FdH0sGg92QNIMTpC9EGD4,10126
1002
1002
  supervisely/nn/tracker/visualize.py,sha256=DY2cnRm4w6_e47xVuF9fwSnOP27ZWTRfv4MFPCyxsD4,20146
1003
1003
  supervisely/nn/tracker/botsort/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
1004
1004
  supervisely/nn/tracker/botsort/botsort_config.yaml,sha256=q_7Gp1-15lGYOLv7JvxVJ69mm6hbCLbUAl_ZBOYNGpw,535
@@ -1096,7 +1096,7 @@ supervisely/video_annotation/frame.py,sha256=np21FqavJ3xW9VbLbohifDwZQtF5dWIsNSG
1096
1096
  supervisely/video_annotation/frame_collection.py,sha256=YYA8NMywLwpzeqVZuifhwlW5gAeQr9NLOANMT4jWpyg,15037
1097
1097
  supervisely/video_annotation/key_id_map.py,sha256=KayYOhTtAe3ITq1-NQ82T6YIiBjmu4aJm8t4UxdvI8U,37712
1098
1098
  supervisely/video_annotation/video_annotation.py,sha256=WsZws8ls6Og3eXQJlEp9PT5DOceMnhajr82KL-8rd6c,28901
1099
- supervisely/video_annotation/video_figure.py,sha256=p8g0B9e8QzTOGuXpCqdMMWhmRmOPo1hmpcTibmVDgGk,23830
1099
+ supervisely/video_annotation/video_figure.py,sha256=r_tcVoiWWIfCa_8vmF1wPI7qlE1QQgpOqL1XQnAAqiM,25404
1100
1100
  supervisely/video_annotation/video_object.py,sha256=LnJg-tvvjfU_m-GfRp71PUziOXJVBEfoTro2P9EhjIs,16759
1101
1101
  supervisely/video_annotation/video_object_collection.py,sha256=vY-n7yJ5Fn6-1OiXpS65uY4_VD_VRMQL7isgSbtugFw,9108
1102
1102
  supervisely/video_annotation/video_tag.py,sha256=cF6EoZ7lxcVacnvtVpSW7A7nbkCp8AYkRjtMCD_wqo8,18312
@@ -1127,9 +1127,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
1127
1127
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
1128
1128
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
1129
1129
  supervisely_lib/__init__.py,sha256=yRwzEQmVwSd6lUQoAUdBngKEOlnoQ6hA9ZcoZGJRNC4,331
1130
- supervisely-6.73.439.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1131
- supervisely-6.73.439.dist-info/METADATA,sha256=ka6gwfc4dPZXyj_5xc2OSjv9UWP9jlwqMx_TS7qxaqU,35433
1132
- supervisely-6.73.439.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1133
- supervisely-6.73.439.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1134
- supervisely-6.73.439.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1135
- supervisely-6.73.439.dist-info/RECORD,,
1130
+ supervisely-6.73.440.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1131
+ supervisely-6.73.440.dist-info/METADATA,sha256=IkMNY-vAbGbAjZcZ63wwsWqEcsZQeJH2Zn3NgghAZ5g,35480
1132
+ supervisely-6.73.440.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1133
+ supervisely-6.73.440.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1134
+ supervisely-6.73.440.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1135
+ supervisely-6.73.440.dist-info/RECORD,,