supervisely 6.73.234__py3-none-any.whl → 6.73.236__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.
@@ -3126,6 +3126,7 @@ class ImageApi(RemoveableBulkModuleApi):
3126
3126
  progress_cb: Optional[Union[tqdm, Callable]] = None,
3127
3127
  links: Optional[List[str]] = None,
3128
3128
  conflict_resolution: Optional[Literal["rename", "skip", "replace"]] = "rename",
3129
+ force_metadata_for_links: Optional[bool] = False,
3129
3130
  ) -> List[ImageInfo]:
3130
3131
  """
3131
3132
  Uploads images to Supervisely and adds a tag to them.
@@ -3153,6 +3154,9 @@ class ImageApi(RemoveableBulkModuleApi):
3153
3154
  - 'skip': Ignores uploading the new images if there is a conflict; the original image's ImageInfo list will be returned instead.
3154
3155
  - 'rename': (default) Renames the new images to prevent name conflicts.
3155
3156
  :type conflict_resolution: Optional[Literal["rename", "skip", "replace"]]
3157
+ :param force_metadata_for_links: Specifies whether to force retrieving metadata for images from links.
3158
+ If False, metadata fields in the response can be empty (if metadata has not been retrieved yet).
3159
+ :type force_metadata_for_links: Optional[bool]
3156
3160
  :return: List of uploaded images infos
3157
3161
  :rtype: List[ImageInfo]
3158
3162
  :raises Exception: if tag does not exist in project or tag is not of type ANY_STRING
@@ -3215,6 +3219,7 @@ class ImageApi(RemoveableBulkModuleApi):
3215
3219
  links=links,
3216
3220
  progress_cb=progress_cb,
3217
3221
  conflict_resolution=conflict_resolution,
3222
+ force_metadata_for_links=force_metadata_for_links,
3218
3223
  )
3219
3224
  image_infos.extend(image_infos_by_links)
3220
3225
 
@@ -3223,10 +3228,151 @@ class ImageApi(RemoveableBulkModuleApi):
3223
3228
  self._api.annotation.upload_anns(image_ids, anns)
3224
3229
 
3225
3230
  uploaded_image_infos = self.get_list(
3226
- dataset_id, filters=[{"field": "id", "operator": "in", "value": image_ids}]
3231
+ dataset_id,
3232
+ filters=[
3233
+ {
3234
+ ApiField.FIELD: ApiField.ID,
3235
+ ApiField.OPERATOR: "in",
3236
+ ApiField.VALUE: image_ids,
3237
+ }
3238
+ ],
3239
+ force_metadata_for_links=force_metadata_for_links,
3227
3240
  )
3228
3241
  return uploaded_image_infos
3229
3242
 
3243
+ def group_images_for_multiview(
3244
+ self,
3245
+ image_ids: List[int],
3246
+ group_name: str,
3247
+ multiview_tag_name: Optional[str] = None,
3248
+ ) -> None:
3249
+ """
3250
+ Group images for multi-view by tag with given name. If tag does not exist in project, will create it first.
3251
+
3252
+ Note:
3253
+ * All images must belong to the same project.
3254
+ * Tag must be of type ANY_STRING and applicable to images.
3255
+ * Recommended number of images in group is 6-12.
3256
+
3257
+ :param image_ids: List of Images IDs in Supervisely.
3258
+ :type image_ids: List[int]
3259
+ :param group_name: Group name. Images will be assigned by group tag with this value.
3260
+ :type group_name: str
3261
+ :param multiview_tag_name: Multiview tag name in Supervisely.
3262
+ If None, will use default 'multiview' tag name.
3263
+ If tag does not exist in project, will create it first.
3264
+ :type multiview_tag_name: str, optional
3265
+ :return: :class:`None<None>`
3266
+
3267
+ :rtype: :class:`NoneType<NoneType>`
3268
+ :raises ValueError: if tag is not of type ANY_STRING or not applicable to images
3269
+
3270
+ :Usage example:
3271
+
3272
+ .. code-block:: python
3273
+
3274
+ # ? option 1
3275
+ import supervisely as sly
3276
+
3277
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
3278
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
3279
+ api = sly.Api.from_env()
3280
+
3281
+ BATCH_SIZE = 6
3282
+ image_ids = [2389126, 2389127, 2389128, 2389129, 2389130, 2389131, ...]
3283
+
3284
+ # group images for multiview
3285
+ for group_name, ids in enumerate(sly.batched(image_ids, batch_size=BATCH_SIZE)):
3286
+ api.image.group_images_for_multiview(ids, group_name)
3287
+
3288
+
3289
+ # ? option 2 (with sly.ApiContext)
3290
+ import supervisely as sly
3291
+
3292
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
3293
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
3294
+ api = sly.Api.from_env()
3295
+
3296
+ BATCH_SIZE = 6
3297
+ image_ids = [2389126, 2389127, 2389128, 2389129, 2389130, 2389131, ...]
3298
+ project_id = 111111 # change to your project id
3299
+
3300
+
3301
+ # * make sure that `with_settings=True` is set to get project settings from server
3302
+ project_meta_json = api.project.get_meta(project_id, with_settings=True)
3303
+ project_meta = sly.ProjectMeta.from_json(project_meta_json)
3304
+
3305
+ # create custom tag meta (optional)
3306
+ multiview_tag_name = 'cars'
3307
+ tag_meta = sly.TagMeta(multiview_tag_name, sly.TagValueType.ANY_STRING)
3308
+ project_meta = project_meta.add_tag_meta(tag_meta)
3309
+ project_meta = api.project.update_meta(project_id, project_meta) # update meta on server
3310
+
3311
+ # group images for multiview
3312
+ with sly.ApiContext(api, project_id=project_id, project_meta=project_meta):
3313
+ for group_name, ids in enumerate(sly.batched(image_ids, batch_size=BATCH_SIZE)):
3314
+ api.image.group_images_for_multiview(ids, group_name, multiview_tag_name)
3315
+
3316
+ """
3317
+
3318
+ # ============= Api Context ===================================
3319
+ # using context for optimization (avoiding extra API requests)
3320
+ context = self._api.optimization_context
3321
+ project_meta = context.get("project_meta")
3322
+ project_id = context.get("project_id")
3323
+ if project_id is None:
3324
+ project_id = self.get_project_id(image_ids[0])
3325
+ context["project_id"] = project_id
3326
+ if project_meta is None:
3327
+ project_meta = ProjectMeta.from_json(
3328
+ self._api.project.get_meta(project_id, with_settings=True)
3329
+ )
3330
+ context["project_meta"] = project_meta
3331
+ # =============================================================
3332
+
3333
+ need_update_project_meta = False
3334
+ multiview_tag_name = multiview_tag_name or _MULTIVIEW_TAG_NAME
3335
+ multiview_tag_meta = project_meta.get_tag_meta(multiview_tag_name)
3336
+
3337
+ if multiview_tag_meta is None:
3338
+ multiview_tag_meta = TagMeta(
3339
+ multiview_tag_name,
3340
+ TagValueType.ANY_STRING,
3341
+ applicable_to=TagApplicableTo.IMAGES_ONLY,
3342
+ )
3343
+ project_meta = project_meta.add_tag_meta(multiview_tag_meta)
3344
+ need_update_project_meta = True
3345
+ elif multiview_tag_meta.sly_id is None:
3346
+ logger.warning(f"`sly_id` is None for group tag, trying to get it from server")
3347
+ need_update_project_meta = True
3348
+
3349
+ if multiview_tag_meta.value_type != TagValueType.ANY_STRING:
3350
+ raise ValueError(f"Tag '{multiview_tag_name}' is not of type ANY_STRING.")
3351
+ elif multiview_tag_meta.applicable_to == TagApplicableTo.OBJECTS_ONLY:
3352
+ raise ValueError(f"Tag '{multiview_tag_name}' is not applicable to images.")
3353
+
3354
+ if need_update_project_meta:
3355
+ project_meta = self._api.project.update_meta(id=project_id, meta=project_meta)
3356
+ context["project_meta"] = project_meta
3357
+ multiview_tag_meta = project_meta.get_tag_meta(multiview_tag_name)
3358
+
3359
+ if not project_meta.project_settings.multiview_enabled:
3360
+ if multiview_tag_name == _MULTIVIEW_TAG_NAME:
3361
+ self._api.project.set_multiview_settings(project_id)
3362
+ else:
3363
+ self._api.project._set_custom_grouping_settings(
3364
+ id=project_id,
3365
+ group_images=True,
3366
+ tag_name=multiview_tag_name,
3367
+ sync=False,
3368
+ )
3369
+ project_meta = ProjectMeta.from_json(
3370
+ self._api.project.get_meta(project_id, with_settings=True)
3371
+ )
3372
+ context["project_meta"] = project_meta
3373
+
3374
+ self.add_tag_batch(image_ids, multiview_tag_meta.sly_id, group_name)
3375
+
3230
3376
  def upload_medical_images(
3231
3377
  self,
3232
3378
  dataset_id: int,
@@ -7,6 +7,7 @@ from typing import List
7
7
  import cv2
8
8
  import numpy as np
9
9
 
10
+
10
11
  class HiddenCocoPrints:
11
12
  def __enter__(self):
12
13
  self._original_stdout = sys.stdout
@@ -34,12 +35,13 @@ from supervisely import (
34
35
  logger,
35
36
  )
36
37
  from supervisely.convert.image.image_converter import ImageConverter
38
+ from supervisely.convert.image.image_helper import validate_image_bounds
37
39
  from supervisely.geometry.graph import KeypointsTemplate
38
40
  from supervisely.imaging.color import generate_rgb
39
- from supervisely.convert.image.image_helper import validate_image_bounds
40
41
 
41
42
  conflict_classes = []
42
43
 
44
+
43
45
  # COCO Convert funcs
44
46
  def create_supervisely_annotation(
45
47
  item: ImageConverter.Item,
@@ -53,21 +55,29 @@ def create_supervisely_annotation(
53
55
  name_cat_id_map = coco_category_to_class_name(coco_categories)
54
56
  renamed_classes = {} if renamed_classes is None else renamed_classes
55
57
  renamed_tags = {} if renamed_tags is None else renamed_tags
56
- for object in item.ann_data:
57
- caption = object.get("caption")
58
+ for coco_data in item.ann_data:
59
+ caption = coco_data.get("caption")
58
60
  if caption is not None:
59
61
  tag_name = renamed_tags.get("caption", "caption")
60
62
  imag_tags.append(Tag(meta.get_tag_meta(tag_name), caption))
61
- category_id = object.get("category_id")
63
+ category_id = coco_data.get("category_id")
62
64
  if category_id is None:
63
65
  continue
64
66
  obj_class_name = name_cat_id_map.get(category_id)
65
67
  if obj_class_name is None:
66
- logger.warn(f"Category with id {category_id} not found in categories list")
68
+ logger.warning(f"Category with id {category_id} not found in categories list")
67
69
  continue
68
70
  renamed_class_name = renamed_classes.get(obj_class_name, obj_class_name)
69
71
  key = None
70
- segm = object.get("segmentation")
72
+
73
+ segm = coco_data.get("segmentation")
74
+ keypoints = coco_data.get("keypoints")
75
+ bbox = coco_data.get("bbox")
76
+
77
+ if len([f for f in (segm, keypoints, bbox) if f]) > 1:
78
+ # create a binding key if more than one of the following fields are present
79
+ key = uuid.uuid4().hex
80
+
71
81
  curr_labels = []
72
82
  if segm is not None and len(segm) > 0:
73
83
  obj_class_polygon = meta.get_obj_class(renamed_class_name)
@@ -75,30 +85,24 @@ def create_supervisely_annotation(
75
85
  if obj_class_name not in conflict_classes:
76
86
  geometry_name = obj_class_polygon.geometry_type.geometry_name().capitalize()
77
87
  conflict_classes.append(obj_class_name)
78
- logger.warn(
88
+ logger.warning(
79
89
  "Conflict in class geometry type: "
80
90
  f"object class '{obj_class_name}' (category ID: {category_id}) "
81
91
  f"has type '{geometry_name}', but expected type is 'Polygon'."
82
92
  )
83
93
  continue
84
94
  if type(segm) is dict:
85
- polygons = convert_rle_mask_to_polygon(object)
95
+ polygons = convert_rle_mask_to_polygon(coco_data)
86
96
  for polygon in polygons:
87
- figure = polygon
88
- key = uuid.uuid4().hex
89
- label = Label(figure, obj_class_polygon, binding_key=key)
90
- curr_labels.append(label)
91
- elif type(segm) is list and object["segmentation"]:
92
- figures = convert_polygon_vertices(object, item.shape)
93
- for figure in figures:
94
- key = uuid.uuid4().hex
95
- label = Label(figure, obj_class_polygon, binding_key=key)
96
- curr_labels.append(label)
97
+ curr_labels.append(Label(polygon, obj_class_polygon, binding_key=key))
98
+ elif type(segm) is list and coco_data["segmentation"]:
99
+ polygons = convert_polygon_vertices(coco_data, item.shape)
100
+ for polygon in polygons:
101
+ curr_labels.append(Label(polygon, obj_class_polygon, binding_key=key))
97
102
 
98
- keypoints = object.get("keypoints")
99
103
  if keypoints is not None:
100
104
  obj_class_keypoints = meta.get_obj_class(renamed_class_name)
101
- keypoints = list(get_coords(object["keypoints"]))
105
+ keypoints = list(get_coords(keypoints))
102
106
  coco_categorie, keypoint_names = None, None
103
107
  for cat in coco_categories:
104
108
  if cat["id"] == category_id and cat["supercategory"] == obj_class_name:
@@ -116,11 +120,10 @@ def create_supervisely_annotation(
116
120
  node = Node(label=keypoint_name, row=row, col=col) # , disabled=v)
117
121
  nodes.append(node)
118
122
  if len(nodes) != 0:
119
- key = uuid.uuid4().hex
120
123
  label = Label(GraphNodes(nodes), obj_class_keypoints, binding_key=key)
121
124
  curr_labels.append(label)
122
125
  labels.extend(curr_labels)
123
- bbox = object.get("bbox")
126
+
124
127
  if bbox is not None and len(bbox) == 4:
125
128
  if not obj_class_name.endswith("bbox"):
126
129
  obj_class_name = add_tail(obj_class_name, "bbox")
@@ -130,24 +133,15 @@ def create_supervisely_annotation(
130
133
  if obj_class_name not in conflict_classes:
131
134
  geometry_name = obj_class_rectangle.geometry_type.geometry_name().capitalize()
132
135
  conflict_classes.append(obj_class_name)
133
- logger.warn(
136
+ logger.warning(
134
137
  "Conflict in class geometry type: "
135
138
  f"object class '{obj_class_name}' (category ID: {category_id}) "
136
139
  f"has type '{geometry_name}', but expected type is 'Rectangle'."
137
140
  )
138
141
  continue
139
- if len(curr_labels) > 1:
140
- for label in curr_labels:
141
- bbox = label.geometry.to_bbox()
142
- labels.append(Label(bbox, obj_class_rectangle, binding_key=label.binding_key))
143
- else:
144
- if len(curr_labels) == 1:
145
- key = curr_labels[0].binding_key
146
- x, y, w, h = bbox
147
- rectangle = Label(
148
- Rectangle(y, x, y + h, x + w), obj_class_rectangle, binding_key=key
149
- )
150
- labels.append(rectangle)
142
+ x, y, w, h = bbox
143
+ geometry = Rectangle(y, x, y + h, x + w)
144
+ labels.append(Label(geometry, obj_class_rectangle, binding_key=key))
151
145
  labels = validate_image_bounds(labels, Rectangle.from_size(item.shape))
152
146
  return Annotation(item.shape, labels=labels, img_tags=imag_tags)
153
147
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.234
3
+ Version: 6.73.236
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -28,7 +28,7 @@ supervisely/api/dataset_api.py,sha256=2-SQBlgEnIN-0uvDbtPlSXr6ztBeZ3WPryhkOtpBmk
28
28
  supervisely/api/file_api.py,sha256=WMg80fxqMKOo3ai-IGON2w-IDAySPk90USoVk29JOdE,82415
29
29
  supervisely/api/github_api.py,sha256=NIexNjEer9H5rf5sw2LEZd7C1WR-tK4t6IZzsgeAAwQ,623
30
30
  supervisely/api/image_annotation_tool_api.py,sha256=YcUo78jRDBJYvIjrd-Y6FJAasLta54nnxhyaGyanovA,5237
31
- supervisely/api/image_api.py,sha256=X26mRA40-DLU-AGD3iTe5x9VtNgQRbTvFDXrkfwDwe8,162626
31
+ supervisely/api/image_api.py,sha256=_wXn10tKKCcfvTiQax0O2X9lnE54nXucwQHTjA1WbRM,169172
32
32
  supervisely/api/import_storage_api.py,sha256=BDCgmR0Hv6OoiRHLCVPKt3iDxSVlQp1WrnKhAK_Zl84,460
33
33
  supervisely/api/issues_api.py,sha256=BqDJXmNoTzwc3xe6_-mA7FDFC5QQ-ahGbXk_HmpkSeQ,17925
34
34
  supervisely/api/labeling_job_api.py,sha256=odnzZjp29yM16Gq-FYkv-OA4WFMNJCLFo4qSikW2A7c,56280
@@ -565,7 +565,7 @@ supervisely/convert/image/cityscapes/cityscapes_helper.py,sha256=in5nR7__q_u5dCk
565
565
  supervisely/convert/image/coco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
566
566
  supervisely/convert/image/coco/coco_anntotation_converter.py,sha256=79rhAy_nkudxEgJDLW0BziUz808-fSqTOnlUeN-kvn8,6603
567
567
  supervisely/convert/image/coco/coco_converter.py,sha256=7czTd4I1we_HxEc9diQiXPC2pXAtnoqSnFSVCtNOmP4,5431
568
- supervisely/convert/image/coco/coco_helper.py,sha256=lRr9TcqRVphF_Hlw37-vgJClJBQ-THmCW5xHPYhkxPg,13340
568
+ supervisely/convert/image/coco/coco_helper.py,sha256=rVgorzdw9Um1CN7X0hJmJn2YIwLu9i-_KKI8yDV2h0E,12934
569
569
  supervisely/convert/image/csv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
570
570
  supervisely/convert/image/csv/csv_converter.py,sha256=iLyc2PAVtlsAq7blnGH4iS1_D7Ai6-4UsdI_RlDVB9Q,11677
571
571
  supervisely/convert/image/csv/csv_helper.py,sha256=-nR192IfMU0vTlNRoKXu5FS6tTs9fENqySyeKKyemRs,8409
@@ -997,9 +997,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
997
997
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
998
998
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
999
999
  supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
1000
- supervisely-6.73.234.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1001
- supervisely-6.73.234.dist-info/METADATA,sha256=r4mn1H6-TvF7ah1u4bgMSQ5xi4opQMEteUBMfPwPTlM,33150
1002
- supervisely-6.73.234.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1003
- supervisely-6.73.234.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1004
- supervisely-6.73.234.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1005
- supervisely-6.73.234.dist-info/RECORD,,
1000
+ supervisely-6.73.236.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1001
+ supervisely-6.73.236.dist-info/METADATA,sha256=27yVKc8ilCBbvT05LWWUVROQyN0b68bl_wfU5zsyQAQ,33150
1002
+ supervisely-6.73.236.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1003
+ supervisely-6.73.236.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1004
+ supervisely-6.73.236.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1005
+ supervisely-6.73.236.dist-info/RECORD,,