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

@@ -1372,6 +1372,19 @@ class VideoApi(RemoveableBulkModuleApi):
1372
1372
  },
1373
1373
  )
1374
1374
 
1375
+ def notify_tracking_warning(self, track_id: int, video_id: int, message: str):
1376
+ self._api.post(
1377
+ "videos.notify-annotation-tool",
1378
+ data={
1379
+ "type": "videos:tracking-warning",
1380
+ "data": {
1381
+ ApiField.VIDEO_ID: str(video_id),
1382
+ ApiField.TRACK_ID: str(track_id),
1383
+ ApiField.MESSAGE: message,
1384
+ },
1385
+ },
1386
+ )
1387
+
1375
1388
  # def upload(self):
1376
1389
  # #"/videos.bulk.upload"
1377
1390
  # pass
@@ -2055,7 +2068,7 @@ class VideoApi(RemoveableBulkModuleApi):
2055
2068
  hashes=[h],
2056
2069
  metas=[meta],
2057
2070
  skip_download=skip_download,
2058
- force_metadata_for_links=force_metadata_for_links
2071
+ force_metadata_for_links=force_metadata_for_links,
2059
2072
  )
2060
2073
  if len(links) != 1:
2061
2074
  raise RuntimeError(
@@ -1,7 +1,6 @@
1
1
  import json
2
- import os
3
2
  import shutil
4
- from concurrent.futures import ThreadPoolExecutor
3
+ from concurrent.futures import ThreadPoolExecutor, as_completed
5
4
  from enum import Enum
6
5
  from logging import Logger
7
6
  from pathlib import Path
@@ -16,6 +15,7 @@ from cachetools import Cache, LRUCache, TTLCache
16
15
  from fastapi import BackgroundTasks, FastAPI, Form, Request, UploadFile
17
16
 
18
17
  import supervisely as sly
18
+ from supervisely._utils import batched
19
19
  from supervisely.io.fs import silent_remove
20
20
 
21
21
 
@@ -151,6 +151,38 @@ class PersistentImageTTLCache(TTLCache):
151
151
  def get_project_meta(self, project_meta_name):
152
152
  return self[project_meta_name]
153
153
 
154
+ def copy_to(self, name, path):
155
+ shutil.copyfile(str(self[name]), path)
156
+
157
+
158
+ class VideoFrameReader:
159
+ def __init__(self, video_path: str, frame_indexes: List[int]):
160
+ self.video_path = video_path
161
+ self.frame_indexes = frame_indexes
162
+ self.cap = None
163
+ self.prev_idx = -1
164
+
165
+ def __enter__(self):
166
+ self.cap = cv2.VideoCapture(str(self.video_path))
167
+ return self
168
+
169
+ def __exit__(self, exc_type, exc_val, exc_tb):
170
+ if self.cap is not None:
171
+ self.cap.release()
172
+
173
+ def read_frames(self) -> Generator:
174
+ try:
175
+ for frame_index in self.frame_indexes:
176
+ if frame_index != self.prev_idx + 1:
177
+ self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_index)
178
+ ret, frame = self.cap.read()
179
+ if not ret:
180
+ raise KeyError(f"Frame {frame_index} not found in video {self.video_path}")
181
+ yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
182
+ self.prev_idx = frame_index
183
+ finally:
184
+ self.cap.release()
185
+
154
186
 
155
187
  class InferenceImageCache:
156
188
  class _LoadType(Enum):
@@ -238,25 +270,18 @@ class InferenceImageCache:
238
270
  return_images,
239
271
  )
240
272
 
273
+ def _read_frames_from_cached_video_iter(self, video_id, frame_indexes):
274
+ video_path = self._cache.get_video_path(video_id)
275
+ with VideoFrameReader(video_path, frame_indexes) as reader:
276
+ for frame in reader.read_frames():
277
+ yield frame
278
+
241
279
  def _read_frames_from_cached_video(
242
280
  self, video_id: int, frame_indexes: List[int]
243
281
  ) -> List[np.ndarray]:
244
- video_path = self._cache.get_video_path(video_id)
245
- if video_path is None or not video_path.exists():
246
- raise KeyError(f"Video {video_id} not found in cache")
247
- cap = cv2.VideoCapture(str(video_path))
248
- frames = []
249
- prev_idx = -1
250
- for frame_index in frame_indexes:
251
- if frame_index != prev_idx + 1:
252
- cap.set(cv2.CAP_PROP_POS_FRAMES, frame_index)
253
- ret, frame = cap.read()
254
- if not ret:
255
- raise KeyError(f"Frame {frame_index} not found in video {video_id}")
256
- frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
257
- prev_idx = frame_index
258
- cap.release()
259
- return frames
282
+ return [
283
+ frame for frame in self._read_frames_from_cached_video_iter(video_id, frame_indexes)
284
+ ]
260
285
 
261
286
  def get_frame_from_cache(self, video_id: int, frame_index: int) -> np.ndarray:
262
287
  name = self._frame_name(video_id, frame_index)
@@ -664,3 +689,39 @@ class InferenceImageCache:
664
689
  # TODO: sleep if slowdown
665
690
  sleep(0.1)
666
691
  continue
692
+
693
+ def download_frames_to_paths(self, api, video_id, frame_indexes, paths, progress_cb=None):
694
+ def _download_frame(frame_index):
695
+ self.download_frame(api, video_id, frame_index)
696
+ name = self._frame_name(video_id, frame_index)
697
+ return frame_index, name
698
+
699
+ def _download_and_save(this_frame_indexes, this_paths):
700
+ if video_id in self._cache:
701
+ for path, frame in zip(
702
+ this_paths,
703
+ self._read_frames_from_cached_video_iter(video_id, this_frame_indexes),
704
+ ):
705
+ sly.image.write(path, frame)
706
+ if progress_cb is not None:
707
+ progress_cb()
708
+ return
709
+
710
+ futures = []
711
+ frame_index_to_path = {}
712
+ for frame_index, path in zip(this_frame_indexes[:5], this_paths[:5]):
713
+ frame_index_to_path[frame_index] = path
714
+ futures.append(executor.submit(_download_frame, frame_index))
715
+ for future in as_completed(futures):
716
+ frame_index, name = future.result()
717
+ path = frame_index_to_path[frame_index]
718
+ self._cache.copy_to(name, path)
719
+ if progress_cb is not None:
720
+ progress_cb()
721
+ if len(this_frame_indexes) > 5:
722
+ _download_and_save(this_frame_indexes[5:], this_paths[5:])
723
+
724
+ # optimization for frame read from video file
725
+ frame_indexes, paths = zip(*sorted(zip(frame_indexes, paths), key=lambda x: x[0]))
726
+ executor = ThreadPoolExecutor(max_workers=5)
727
+ _download_and_save(frame_indexes, paths)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.232
3
+ Version: 6.73.233
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -64,7 +64,7 @@ supervisely/api/pointcloud/pointcloud_object_api.py,sha256=bO1USWb9HAywG_CW4CDu1
64
64
  supervisely/api/pointcloud/pointcloud_tag_api.py,sha256=iShtr052nOElxsyMyZEUT2vypEm6kP00gnP13ABX24A,4691
65
65
  supervisely/api/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  supervisely/api/video/video_annotation_api.py,sha256=Um_7UOJtP_E25X6v41mrZfDbJaJuLMGoZm2IULwyg3w,10977
67
- supervisely/api/video/video_api.py,sha256=2yFm1pbL-ziHl8vDyrf8z1qLbZxlo_22FyqjKPQbNg4,94228
67
+ supervisely/api/video/video_api.py,sha256=KO_Nfqa4xDWrc7FqOR14PciC0TX8PF0g0peqgPnctEE,94677
68
68
  supervisely/api/video/video_figure_api.py,sha256=quksohjhgrK2l2-PtbbNE99fOW6uWXX59-_4xfc-I-k,6244
69
69
  supervisely/api/video/video_frame_api.py,sha256=4GwSI4xdCNYEUvTqzKc-Ewd44fw5zqkFoD24jrrN_aY,10214
70
70
  supervisely/api/video/video_object_api.py,sha256=IC0NP8EoIT_d3xxDRgz2cA3ixSiuJ5ymy64eS-RfmDM,2227
@@ -816,7 +816,7 @@ supervisely/nn/benchmark/visualization/widgets/sidebar/sidebar.py,sha256=tKPURRS
816
816
  supervisely/nn/benchmark/visualization/widgets/table/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
817
817
  supervisely/nn/benchmark/visualization/widgets/table/table.py,sha256=YiCpt-mdINJnNBWsUTPkRR_9w09Ne2Y0n93DY8vsE8I,4090
818
818
  supervisely/nn/inference/__init__.py,sha256=mtEci4Puu-fRXDnGn8RP47o97rv3VTE0hjbYO34Zwqg,1622
819
- supervisely/nn/inference/cache.py,sha256=WylgHgPQRIoA_RDks8FyKgHqeZZ_YFoyddxkVvOX2YQ,25713
819
+ supervisely/nn/inference/cache.py,sha256=KvzCgMbEBLdiJAxJDLicIPKAlYb52P9_kpNPWfiVY8Y,28194
820
820
  supervisely/nn/inference/inference.py,sha256=CmQe6QnhZuUV128jcIp2YKsgeggAtmc1NL7PdFnc_hw,116997
821
821
  supervisely/nn/inference/session.py,sha256=jmkkxbe2kH-lEgUU6Afh62jP68dxfhF5v6OGDfLU62E,35757
822
822
  supervisely/nn/inference/video_inference.py,sha256=8Bshjr6rDyLay5Za8IB8Dr6FURMO2R_v7aELasO8pR4,5746
@@ -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.232.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1001
- supervisely-6.73.232.dist-info/METADATA,sha256=xZnrkZw3qSVTsMB9IDC8aQsI6xxhZRlM_9LNc9MBjXY,33150
1002
- supervisely-6.73.232.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1003
- supervisely-6.73.232.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1004
- supervisely-6.73.232.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1005
- supervisely-6.73.232.dist-info/RECORD,,
1000
+ supervisely-6.73.233.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1001
+ supervisely-6.73.233.dist-info/METADATA,sha256=MJtm60rKHXwewU1uAmNhtaWHuI_g_Y4oGxJbqM-oiFM,33150
1002
+ supervisely-6.73.233.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1003
+ supervisely-6.73.233.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1004
+ supervisely-6.73.233.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1005
+ supervisely-6.73.233.dist-info/RECORD,,