supervisely 6.73.444__py3-none-any.whl → 6.73.468__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.

Potentially problematic release.


This version of supervisely might be problematic. Click here for more details.

Files changed (68) hide show
  1. supervisely/__init__.py +24 -1
  2. supervisely/_utils.py +81 -0
  3. supervisely/annotation/json_geometries_map.py +2 -0
  4. supervisely/api/dataset_api.py +74 -12
  5. supervisely/api/entity_annotation/figure_api.py +8 -5
  6. supervisely/api/image_api.py +4 -0
  7. supervisely/api/video/video_annotation_api.py +4 -2
  8. supervisely/api/video/video_api.py +41 -1
  9. supervisely/app/__init__.py +1 -1
  10. supervisely/app/content.py +14 -6
  11. supervisely/app/fastapi/__init__.py +1 -0
  12. supervisely/app/fastapi/custom_static_files.py +1 -1
  13. supervisely/app/fastapi/multi_user.py +88 -0
  14. supervisely/app/fastapi/subapp.py +88 -42
  15. supervisely/app/fastapi/websocket.py +77 -9
  16. supervisely/app/singleton.py +21 -0
  17. supervisely/app/v1/app_service.py +18 -2
  18. supervisely/app/v1/constants.py +7 -1
  19. supervisely/app/widgets/card/card.py +20 -0
  20. supervisely/app/widgets/deploy_model/deploy_model.py +56 -35
  21. supervisely/app/widgets/dialog/dialog.py +12 -0
  22. supervisely/app/widgets/dialog/template.html +2 -1
  23. supervisely/app/widgets/experiment_selector/experiment_selector.py +8 -0
  24. supervisely/app/widgets/fast_table/fast_table.py +121 -31
  25. supervisely/app/widgets/fast_table/template.html +1 -1
  26. supervisely/app/widgets/radio_tabs/radio_tabs.py +18 -2
  27. supervisely/app/widgets/radio_tabs/template.html +1 -0
  28. supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +65 -7
  29. supervisely/app/widgets/table/table.py +68 -13
  30. supervisely/app/widgets/tree_select/tree_select.py +2 -0
  31. supervisely/convert/image/csv/csv_converter.py +24 -15
  32. supervisely/convert/video/video_converter.py +2 -2
  33. supervisely/geometry/polyline_3d.py +110 -0
  34. supervisely/io/env.py +76 -1
  35. supervisely/nn/inference/cache.py +37 -17
  36. supervisely/nn/inference/inference.py +667 -114
  37. supervisely/nn/inference/inference_request.py +15 -8
  38. supervisely/nn/inference/predict_app/gui/classes_selector.py +81 -12
  39. supervisely/nn/inference/predict_app/gui/gui.py +676 -488
  40. supervisely/nn/inference/predict_app/gui/input_selector.py +205 -26
  41. supervisely/nn/inference/predict_app/gui/model_selector.py +2 -4
  42. supervisely/nn/inference/predict_app/gui/output_selector.py +46 -6
  43. supervisely/nn/inference/predict_app/gui/settings_selector.py +756 -59
  44. supervisely/nn/inference/predict_app/gui/tags_selector.py +1 -1
  45. supervisely/nn/inference/predict_app/gui/utils.py +236 -119
  46. supervisely/nn/inference/predict_app/predict_app.py +2 -2
  47. supervisely/nn/inference/session.py +43 -35
  48. supervisely/nn/model/model_api.py +9 -0
  49. supervisely/nn/model/prediction_session.py +8 -7
  50. supervisely/nn/prediction_dto.py +7 -0
  51. supervisely/nn/tracker/base_tracker.py +11 -1
  52. supervisely/nn/tracker/botsort/botsort_config.yaml +0 -1
  53. supervisely/nn/tracker/botsort_tracker.py +14 -7
  54. supervisely/nn/tracker/visualize.py +70 -72
  55. supervisely/nn/training/gui/train_val_splits_selector.py +52 -31
  56. supervisely/nn/training/train_app.py +10 -5
  57. supervisely/project/project.py +9 -1
  58. supervisely/video/sampling.py +39 -20
  59. supervisely/video/video.py +41 -12
  60. supervisely/volume/stl_converter.py +2 -0
  61. supervisely/worker_api/agent_rpc.py +24 -1
  62. supervisely/worker_api/rpc_servicer.py +31 -7
  63. {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/METADATA +14 -11
  64. {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/RECORD +68 -66
  65. {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/LICENSE +0 -0
  66. {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/WHEEL +0 -0
  67. {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/entry_points.txt +0 -0
  68. {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/top_level.txt +0 -0
@@ -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()
@@ -15,6 +15,8 @@ from supervisely.io.fs import (
15
15
  change_directory_at_index,
16
16
  )
17
17
 
18
+ if not hasattr(np, "bool"):
19
+ np.bool = np.bool_
18
20
 
19
21
  def matrix_from_nrrd_header(header: Dict) -> np.ndarray:
20
22
  """
@@ -1,10 +1,12 @@
1
1
  # coding: utf-8
2
+ # isort: skip_file
2
3
 
3
4
  import cv2
4
5
  import numpy as np
5
6
 
6
7
  from .chunking import load_to_memory_chunked_image, load_to_memory_chunked
7
- from ..worker_proto import worker_api_pb2 as api_proto
8
+
9
+ # from ..worker_proto import worker_api_pb2 as api_proto # Import moved to methods where needed
8
10
 
9
11
 
10
12
  class SimpleCache:
@@ -22,6 +24,13 @@ class SimpleCache:
22
24
 
23
25
 
24
26
  def download_image_from_remote(agent_api, image_hash, src_node_token, logger):
27
+ try:
28
+ from ..worker_proto import worker_api_pb2 as api_proto
29
+ except Exception as e:
30
+ from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
31
+
32
+ raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
33
+
25
34
  resp = agent_api.get_stream_with_data(
26
35
  'DownloadImages',
27
36
  api_proto.ChunkImage,
@@ -34,6 +43,13 @@ def download_image_from_remote(agent_api, image_hash, src_node_token, logger):
34
43
 
35
44
 
36
45
  def download_data_from_remote(agent_api, req_id, logger):
46
+ try:
47
+ from ..worker_proto import worker_api_pb2 as api_proto
48
+ except Exception as e:
49
+ from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
50
+
51
+ raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
52
+
37
53
  resp = agent_api.get_stream_with_data('GetGeneralEventData', api_proto.Chunk, api_proto.Empty(),
38
54
  addit_headers={'x-request-id': req_id})
39
55
  b_data = load_to_memory_chunked(resp)
@@ -47,6 +63,13 @@ def batched(seq, batch_size):
47
63
 
48
64
 
49
65
  def send_from_memory_generator(out_bytes, chunk_size):
66
+ try:
67
+ from ..worker_proto import worker_api_pb2 as api_proto
68
+ except Exception as e:
69
+ from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
70
+
71
+ raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
72
+
50
73
  for bytes_chunk in batched(out_bytes, chunk_size):
51
74
  yield api_proto.Chunk(buffer=bytes_chunk, total_size=len(out_bytes))
52
75
 
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # isort: skip_file
2
3
 
3
4
  import os
4
5
  import concurrent.futures
@@ -11,18 +12,27 @@ import threading
11
12
  from supervisely.annotation.annotation import Annotation
12
13
  from supervisely.function_wrapper import function_wrapper, function_wrapper_nofail
13
14
  from supervisely.imaging.image import drop_image_alpha_channel
14
- from supervisely.nn.legacy.hosted.inference_modes import InferenceModeFactory, InfModeFullImage, \
15
- MODE, NAME, get_effective_inference_mode_config
15
+ from supervisely.nn.legacy.hosted.inference_modes import (
16
+ InferenceModeFactory,
17
+ InfModeFullImage,
18
+ MODE,
19
+ NAME,
20
+ get_effective_inference_mode_config,
21
+ )
16
22
  from supervisely.project.project_meta import ProjectMeta
17
23
  from supervisely.worker_api.agent_api import AgentAPI
18
- from supervisely.worker_api.agent_rpc import decode_image, download_image_from_remote, download_data_from_remote, \
19
- send_from_memory_generator
24
+ from supervisely.worker_api.agent_rpc import (
25
+ decode_image,
26
+ download_image_from_remote,
27
+ download_data_from_remote,
28
+ send_from_memory_generator,
29
+ )
20
30
  from supervisely.worker_api.interfaces import SingleImageInferenceInterface
21
- from supervisely.worker_proto import worker_api_pb2 as api_proto
31
+
32
+ # from supervisely.worker_proto import worker_api_pb2 as api_proto # Import moved to methods where needed
22
33
  from supervisely.task.progress import report_agent_rpc_ready
23
34
  from supervisely.api.api import Api
24
35
 
25
-
26
36
  REQUEST_TYPE = 'request_type'
27
37
  GET_OUT_META = 'get_out_meta'
28
38
  INFERENCE = 'inference'
@@ -123,6 +133,13 @@ class AgentRPCServicerBase:
123
133
  self.thread_pool.submit(function_wrapper_nofail, self._send_data, res_msg, req_id) # skip errors
124
134
 
125
135
  def _send_data(self, out_msg, req_id):
136
+ try:
137
+ from supervisely.worker_proto import worker_api_pb2 as api_proto
138
+ except Exception as e:
139
+ from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
140
+
141
+ raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
142
+
126
143
  self.logger.trace('Will send output data.', extra={REQUEST_ID: req_id})
127
144
  out_bytes = json.dumps(out_msg).encode('utf-8')
128
145
 
@@ -173,6 +190,13 @@ class AgentRPCServicerBase:
173
190
  self._load_data_if_required(event_obj)
174
191
 
175
192
  def run_inf_loop(self):
193
+ try:
194
+ from supervisely.worker_proto import worker_api_pb2 as api_proto
195
+ except Exception as e:
196
+ from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
197
+
198
+ raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
199
+
176
200
  def seq_inf_wrapped():
177
201
  function_wrapper(self._sequential_final_processing) # exit if raised
178
202
 
@@ -252,4 +276,4 @@ class InactiveRPCServicer(AgentRPCServicer):
252
276
  self.logger.info('Created InactiveRPCServicer for internal usage', extra=conn_config)
253
277
 
254
278
  def run_inf_loop(self):
255
- raise RuntimeError("Method is not accessible")
279
+ raise RuntimeError("Method is not accessible")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.444
3
+ Version: 6.73.468
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -21,15 +21,14 @@ Requires-Python: >=3.8
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: cachetools<=5.5.0,>=4.2.3
24
- Requires-Dist: numpy<2.0.0,>=1.19
24
+ Requires-Dist: numpy<=2.3.3,>=1.19
25
25
  Requires-Dist: opencv-python<5.0.0.0,>=4.6.0.66
26
26
  Requires-Dist: PTable<1.0.0,>=0.9.2
27
- Requires-Dist: pillow<=10.2.0,>=5.4.1
28
- Requires-Dist: protobuf<=3.20.3,>=3.19.5
27
+ Requires-Dist: pillow<=10.4.0,>=5.4.1
29
28
  Requires-Dist: python-json-logger<3.0.0,>=0.1.11
30
29
  Requires-Dist: requests<3.0.0,>=2.27.1
31
30
  Requires-Dist: requests-toolbelt>=0.9.1
32
- Requires-Dist: Shapely<=2.0.2,>=1.7.1
31
+ Requires-Dist: Shapely<=2.1.2,>=1.7.1
33
32
  Requires-Dist: bidict<1.0.0,>=0.21.2
34
33
  Requires-Dist: varname<1.0.0,>=0.8.1
35
34
  Requires-Dist: python-dotenv<=1.0.1,>=0.19.2
@@ -40,9 +39,9 @@ Requires-Dist: stringcase<2.0.0,>=1.2.0
40
39
  Requires-Dist: python-magic<1.0.0,>=0.4.25
41
40
  Requires-Dist: trimesh<=4.5.0,>=3.11.2
42
41
  Requires-Dist: uvicorn[standard]<1.0.0,>=0.18.2
43
- Requires-Dist: pydantic<=2.11.3,>=1.7.4
44
- Requires-Dist: anyio<=4.2.0,>=3.7.1
45
- Requires-Dist: fastapi<=0.109.0,>=0.79.0
42
+ Requires-Dist: starlette<=0.47.3
43
+ Requires-Dist: pydantic<=2.12.3,>=1.7.4
44
+ Requires-Dist: fastapi<=0.119.1,>=0.103.1
46
45
  Requires-Dist: websockets<=13.1,>=10.3
47
46
  Requires-Dist: jinja2<4.0.0,>=3.0.3
48
47
  Requires-Dist: psutil<6.0.0,>=5.9.0
@@ -50,7 +49,7 @@ Requires-Dist: jsonpatch<2.0,>=1.32
50
49
  Requires-Dist: MarkupSafe<3.0.0,>=2.1.1
51
50
  Requires-Dist: arel<1.0.0,>=0.2.0
52
51
  Requires-Dist: tqdm<5.0.0,>=4.62.3
53
- Requires-Dist: pandas<=2.1.4,>=1.1.3
52
+ Requires-Dist: pandas<=2.3.3,>=1.1.3
54
53
  Requires-Dist: async-asgi-testclient
55
54
  Requires-Dist: PyYAML>=5.4.0
56
55
  Requires-Dist: distinctipy
@@ -71,6 +70,9 @@ Requires-Dist: zstd
71
70
  Requires-Dist: aiofiles
72
71
  Requires-Dist: httpx[http2]==0.27.2
73
72
  Requires-Dist: debugpy
73
+ Requires-Dist: setuptools<81.0.0
74
+ Provides-Extra: agent
75
+ Requires-Dist: protobuf<=3.20.3,>=3.19.5; extra == "agent"
74
76
  Provides-Extra: apps
75
77
  Requires-Dist: uvicorn[standard]<1.0.0,>=0.18.2; extra == "apps"
76
78
  Requires-Dist: fastapi<1.0.0,>=0.79.0; extra == "apps"
@@ -81,10 +83,11 @@ Requires-Dist: jsonpatch<2.0,>=1.32; extra == "apps"
81
83
  Requires-Dist: MarkupSafe<3.0.0,>=2.1.1; extra == "apps"
82
84
  Requires-Dist: arel<1.0.0,>=0.2.0; extra == "apps"
83
85
  Requires-Dist: tqdm<5.0.0,>=4.62.3; extra == "apps"
84
- Requires-Dist: pandas<1.4.0,>=1.1.3; extra == "apps"
86
+ Requires-Dist: pandas<=2.3.3,>=1.1.3; extra == "apps"
85
87
  Provides-Extra: aug
86
88
  Requires-Dist: imgaug<1.0.0,>=0.4.0; extra == "aug"
87
89
  Requires-Dist: imagecorruptions<2.0.0,>=1.1.2; extra == "aug"
90
+ Requires-Dist: numpy<2.0.0,>=1.19; extra == "aug"
88
91
  Provides-Extra: docs
89
92
  Requires-Dist: sphinx==4.4.0; extra == "docs"
90
93
  Requires-Dist: jinja2==3.0.3; extra == "docs"
@@ -100,7 +103,7 @@ Requires-Dist: scikit-image<1.0.0,>=0.17.1; extra == "extras"
100
103
  Requires-Dist: matplotlib<4.0.0,>=3.3.2; extra == "extras"
101
104
  Requires-Dist: pascal-voc-writer<1.0.0,>=0.1.4; extra == "extras"
102
105
  Requires-Dist: scipy<2.0.0,>=1.8.0; extra == "extras"
103
- Requires-Dist: pandas<1.4.0,>=1.1.3; extra == "extras"
106
+ Requires-Dist: pandas<=2.3.3,>=1.1.3; extra == "extras"
104
107
  Requires-Dist: ruamel.yaml==0.17.21; extra == "extras"
105
108
  Provides-Extra: model-benchmark
106
109
  Requires-Dist: pycocotools; extra == "model-benchmark"