vidformer 0.5.4__py3-none-any.whl → 0.6.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
vidformer/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """A Python library for creating and viewing videos with vidformer."""
2
+
3
+ __version__ = "0.6.1"
4
+
5
+ from .vf import *
@@ -0,0 +1 @@
1
+ from .vf_cv2 import *
@@ -0,0 +1,428 @@
1
+ from .. import vf
2
+
3
+ try:
4
+ import cv2 as _opencv2
5
+ except:
6
+ _opencv2 = None
7
+
8
+ import uuid
9
+ from fractions import Fraction
10
+ from bisect import bisect_right
11
+
12
+ CAP_PROP_POS_MSEC = 0
13
+ CAP_PROP_POS_FRAMES = 1
14
+ CAP_PROP_FRAME_WIDTH = 3
15
+ CAP_PROP_FRAME_HEIGHT = 4
16
+ CAP_PROP_FPS = 5
17
+
18
+ FONT_HERSHEY_SIMPLEX = 0
19
+ FONT_HERSHEY_PLAIN = 1
20
+ FONT_HERSHEY_DUPLEX = 2
21
+ FONT_HERSHEY_COMPLEX = 3
22
+ FONT_HERSHEY_TRIPLEX = 4
23
+ FONT_HERSHEY_COMPLEX_SMALL = 5
24
+ FONT_HERSHEY_SCRIPT_SIMPLEX = 6
25
+ FONT_HERSHEY_SCRIPT_COMPLEX = 7
26
+ FONT_ITALIC = 16
27
+
28
+ FILLED = -1
29
+ LINE_4 = 4
30
+ LINE_8 = 8
31
+ LINE_AA = 16
32
+
33
+ _filter_scale = vf.Filter("Scale")
34
+ _filter_rectangle = vf.Filter("cv2.rectangle")
35
+ _filter_putText = vf.Filter("cv2.putText")
36
+ _filter_arrowedLine = vf.Filter("cv2.arrowedLine")
37
+ _filter_line = vf.Filter("cv2.line")
38
+ _filter_circle = vf.Filter("cv2.circle")
39
+ _filter_addWeighted = vf.Filter("cv2.addWeighted")
40
+
41
+
42
+ def _ts_to_fps(timestamps):
43
+ return int(1 / (timestamps[1] - timestamps[0])) # TODO: Fix for non-integer fps
44
+
45
+
46
+ def _fps_to_ts(fps, n_frames):
47
+ assert type(fps) == int
48
+ return [Fraction(i, fps) for i in range(n_frames)]
49
+
50
+
51
+ _global_cv2_server = None
52
+
53
+
54
+ def _server():
55
+ global _global_cv2_server
56
+ if _global_cv2_server is None:
57
+ _global_cv2_server = vf.YrdenServer()
58
+ return _global_cv2_server
59
+
60
+
61
+ def set_cv2_server(server):
62
+ """Set the server to use for the cv2 frontend."""
63
+ global _global_cv2_server
64
+ assert isinstance(server, vf.YrdenServer)
65
+ _global_cv2_server = server
66
+
67
+
68
+ class _Frame:
69
+ def __init__(self, f):
70
+ self._f = f
71
+
72
+ # denotes that the frame has not yet been modified
73
+ # when a frame is modified, it is converted to rgb24 first
74
+ self._modified = False
75
+
76
+ def _mut(self):
77
+ self._modified = True
78
+ self._f = _filter_scale(self._f, pix_fmt="rgb24")
79
+
80
+
81
+ class VideoCapture:
82
+ def __init__(self, path):
83
+ self._path = path
84
+ server = _server()
85
+ self._source = vf.Source(server, str(uuid.uuid4()), path, 0)
86
+ self._next_frame_idx = 0
87
+
88
+ def isOpened(self):
89
+ return True
90
+
91
+ def get(self, prop):
92
+ if prop == CAP_PROP_FPS:
93
+ return _ts_to_fps(self._source.ts())
94
+ elif prop == CAP_PROP_FRAME_WIDTH:
95
+ return self._source.fmt()["width"]
96
+ elif prop == CAP_PROP_FRAME_HEIGHT:
97
+ return self._source.fmt()["height"]
98
+
99
+ raise Exception(f"Unknown property {prop}")
100
+
101
+ def set(self, prop, value):
102
+ if prop == CAP_PROP_POS_FRAMES:
103
+ assert value >= 0 and value < len(self._source.ts())
104
+ self._next_frame_idx = value
105
+ elif prop == CAP_PROP_POS_MSEC:
106
+ t = Fraction(value, 1000)
107
+ ts = self._source.ts()
108
+ next_frame_idx = bisect_right(ts, t)
109
+ self._next_frame_idx = next_frame_idx
110
+ else:
111
+ raise Exception(f"Unsupported property {prop}")
112
+
113
+ def read(self):
114
+ if self._next_frame_idx >= len(self._source.ts()):
115
+ return False, None
116
+ frame = self._source.iloc[self._next_frame_idx]
117
+ self._next_frame_idx += 1
118
+ frame = _Frame(frame)
119
+ return True, frame
120
+
121
+ def release(self):
122
+ pass
123
+
124
+
125
+ class VideoWriter:
126
+ def __init__(self, path, fourcc, fps, size):
127
+ assert isinstance(fourcc, VideoWriter_fourcc)
128
+ self._path = path
129
+ self._fourcc = fourcc
130
+ self._fps = fps
131
+ self._size = size
132
+
133
+ self._frames = []
134
+ self._pix_fmt = "yuv420p"
135
+
136
+ def write(self, frame):
137
+ if not isinstance(frame, _Frame):
138
+ raise Exception("frame must be a _Frame object")
139
+ if frame._modified:
140
+ f_obj = _filter_scale(frame._f, pix_fmt=self._pix_fmt)
141
+ self._frames.append(f_obj)
142
+ else:
143
+ self._frames.append(frame._f)
144
+
145
+ def release(self):
146
+ spec = self.vf_spec()
147
+ server = _server()
148
+ spec.save(server, self._path)
149
+
150
+ def vf_spec(self):
151
+ fmt = {
152
+ "width": self._size[0],
153
+ "height": self._size[1],
154
+ "pix_fmt": self._pix_fmt,
155
+ }
156
+ domain = _fps_to_ts(self._fps, len(self._frames))
157
+ spec = vf.Spec(domain, lambda t, i: self._frames[i], fmt)
158
+ return spec
159
+
160
+
161
+ class VideoWriter_fourcc:
162
+ def __init__(self, *args):
163
+ self._args = args
164
+
165
+
166
+ def rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None):
167
+ """
168
+ cv.rectangle( img, pt1, pt2, color[, thickness[, lineType[, shift]]] )
169
+ """
170
+
171
+ assert isinstance(img, _Frame)
172
+ img._mut()
173
+
174
+ assert len(pt1) == 2
175
+ assert len(pt2) == 2
176
+ assert all(isinstance(x, int) for x in pt1)
177
+ assert all(isinstance(x, int) for x in pt2)
178
+
179
+ assert len(color) == 3 or len(color) == 4
180
+ color = [float(x) for x in color]
181
+ if len(color) == 3:
182
+ color.append(255.0)
183
+
184
+ args = []
185
+ if thickness is not None:
186
+ assert isinstance(thickness, int)
187
+ args.append(thickness)
188
+ if lineType is not None:
189
+ assert isinstance(lineType, int)
190
+ assert thickness is not None
191
+ args.append(lineType)
192
+ if shift is not None:
193
+ assert isinstance(shift, int)
194
+ assert shift is not None
195
+ args.append(shift)
196
+
197
+ img._f = _filter_rectangle(img._f, pt1, pt2, color, *args)
198
+
199
+
200
+ def putText(
201
+ img,
202
+ text,
203
+ org,
204
+ fontFace,
205
+ fontScale,
206
+ color,
207
+ thickness=None,
208
+ lineType=None,
209
+ bottomLeftOrigin=None,
210
+ ):
211
+ """
212
+ cv.putText( img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]] )
213
+ """
214
+
215
+ assert isinstance(img, _Frame)
216
+ img._mut()
217
+
218
+ assert isinstance(text, str)
219
+
220
+ assert len(org) == 2
221
+ assert all(isinstance(x, int) for x in org)
222
+
223
+ assert isinstance(fontFace, int)
224
+ assert isinstance(fontScale, float) or isinstance(fontScale, int)
225
+ fontScale = float(fontScale)
226
+
227
+ assert len(color) == 3 or len(color) == 4
228
+ color = [float(x) for x in color]
229
+ if len(color) == 3:
230
+ color.append(255.0)
231
+
232
+ args = []
233
+ if thickness is not None:
234
+ assert isinstance(thickness, int)
235
+ args.append(thickness)
236
+ if lineType is not None:
237
+ assert isinstance(lineType, int)
238
+ assert thickness is not None
239
+ args.append(lineType)
240
+ if bottomLeftOrigin is not None:
241
+ assert isinstance(bottomLeftOrigin, bool)
242
+ assert lineType is not None
243
+ args.append(bottomLeftOrigin)
244
+
245
+ img._f = _filter_putText(img._f, text, org, fontFace, fontScale, color, *args)
246
+
247
+
248
+ def arrowedLine(
249
+ img, pt1, pt2, color, thickness=None, line_type=None, shift=None, tipLength=None
250
+ ):
251
+ """
252
+ cv.arrowedLine( img, pt1, pt2, color[, thickness[, line_type[, shift[, tipLength]]]] )
253
+ """
254
+ assert isinstance(img, _Frame)
255
+ img._mut()
256
+
257
+ assert len(pt1) == 2
258
+ assert len(pt2) == 2
259
+ assert all(isinstance(x, int) for x in pt1)
260
+ assert all(isinstance(x, int) for x in pt2)
261
+
262
+ assert len(color) == 3 or len(color) == 4
263
+ color = [float(x) for x in color]
264
+ if len(color) == 3:
265
+ color.append(255.0)
266
+
267
+ args = []
268
+ if thickness is not None:
269
+ assert isinstance(thickness, int)
270
+ args.append(thickness)
271
+ if line_type is not None:
272
+ assert isinstance(line_type, int)
273
+ assert thickness is not None
274
+ args.append(line_type)
275
+ if shift is not None:
276
+ assert isinstance(shift, int)
277
+ assert shift is not None
278
+ args.append(shift)
279
+ if tipLength is not None:
280
+ assert isinstance(tipLength, float)
281
+ assert shift is not None
282
+ args.append(tipLength)
283
+
284
+ img._f = _filter_arrowedLine(img._f, pt1, pt2, color, *args)
285
+
286
+
287
+ def line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None):
288
+ assert isinstance(img, _Frame)
289
+ img._mut()
290
+
291
+ assert len(pt1) == 2
292
+ assert len(pt2) == 2
293
+ assert all(isinstance(x, int) for x in pt1)
294
+ assert all(isinstance(x, int) for x in pt2)
295
+
296
+ assert len(color) == 3 or len(color) == 4
297
+ color = [float(x) for x in color]
298
+ if len(color) == 3:
299
+ color.append(255.0)
300
+
301
+ args = []
302
+ if thickness is not None:
303
+ assert isinstance(thickness, int)
304
+ args.append(thickness)
305
+ if lineType is not None:
306
+ assert isinstance(lineType, int)
307
+ assert thickness is not None
308
+ args.append(lineType)
309
+ if shift is not None:
310
+ assert isinstance(shift, int)
311
+ assert shift is not None
312
+ args.append(shift)
313
+
314
+ img._f = _filter_line(img._f, pt1, pt2, color, *args)
315
+
316
+
317
+ def circle(img, center, radius, color, thickness=None, lineType=None, shift=None):
318
+ assert isinstance(img, _Frame)
319
+ img._mut()
320
+
321
+ assert len(center) == 2
322
+ assert all(isinstance(x, int) for x in center)
323
+
324
+ assert isinstance(radius, int)
325
+
326
+ assert len(color) == 3 or len(color) == 4
327
+ color = [float(x) for x in color]
328
+ if len(color) == 3:
329
+ color.append(255.0)
330
+
331
+ args = []
332
+ if thickness is not None:
333
+ assert isinstance(thickness, int)
334
+ args.append(thickness)
335
+ if lineType is not None:
336
+ assert isinstance(lineType, int)
337
+ assert thickness is not None
338
+ args.append(lineType)
339
+ if shift is not None:
340
+ assert isinstance(shift, int)
341
+ assert shift is not None
342
+ args.append(shift)
343
+
344
+ img._f = _filter_circle(img._f, center, radius, color, *args)
345
+
346
+
347
+ def getFontScaleFromHeight(*args, **kwargs):
348
+ """
349
+ cv.getFontScaleFromHeight( fontFace, pixelHeight[, thickness] )
350
+ """
351
+ if _opencv2 is None:
352
+ raise NotImplementedError("getFontScaleFromHeight requires the cv2 module")
353
+ return _opencv2.getFontScaleFromHeight(*args, **kwargs)
354
+
355
+
356
+ def getTextSize(*args, **kwargs):
357
+ """
358
+ cv.getTextSize( text, fontFace, fontScale, thickness )
359
+ """
360
+ if _opencv2 is None:
361
+ raise NotImplementedError("getTextSize requires the cv2 module")
362
+ return _opencv2.getTextSize(*args, **kwargs)
363
+
364
+
365
+ def addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=-1):
366
+ """
367
+ cv.addWeighted( src1, alpha, src2, beta, gamma[, dst[, dtype]] ) -> dst
368
+ """
369
+ assert isinstance(src1, _Frame)
370
+ assert isinstance(src2, _Frame)
371
+ src1._mut()
372
+ src2._mut()
373
+
374
+ if dst is None:
375
+ dst = _Frame(src1._f)
376
+ else:
377
+ assert isinstance(dst, _Frame)
378
+ dst._mut()
379
+
380
+ assert isinstance(alpha, float) or isinstance(alpha, int)
381
+ assert isinstance(beta, float) or isinstance(beta, int)
382
+ assert isinstance(gamma, float) or isinstance(gamma, int)
383
+ alpha = float(alpha)
384
+ beta = float(beta)
385
+ gamma = float(gamma)
386
+
387
+ if dtype != -1:
388
+ raise Exception("addWeighted does not support the dtype argument")
389
+
390
+ dst._f = _filter_addWeighted(src1._f, alpha, src2._f, beta, gamma)
391
+ return dst
392
+
393
+
394
+ # Stubs for unimplemented functions
395
+
396
+
397
+ def clipLine(*args, **kwargs):
398
+ raise NotImplementedError("clipLine is not yet implemented in the cv2 frontend")
399
+
400
+
401
+ def drawContours(*args, **kwargs):
402
+ raise NotImplementedError("drawContours is not yet implemented in the cv2 frontend")
403
+
404
+
405
+ def drawMarker(*args, **kwargs):
406
+ raise NotImplementedError("drawMarker is not yet implemented in the cv2 frontend")
407
+
408
+
409
+ def ellipse(*args, **kwargs):
410
+ raise NotImplementedError("ellipse is not yet implemented in the cv2 frontend")
411
+
412
+
413
+ def ellipse2Poly(*args, **kwargs):
414
+ raise NotImplementedError("ellipse2Poly is not yet implemented in the cv2 frontend")
415
+
416
+
417
+ def fillConvexPoly(*args, **kwargs):
418
+ raise NotImplementedError(
419
+ "fillConvexPoly is not yet implemented in the cv2 frontend"
420
+ )
421
+
422
+
423
+ def fillPoly(*args, **kwargs):
424
+ raise NotImplementedError("fillPoly is not yet implemented in the cv2 frontend")
425
+
426
+
427
+ def polylines(*args, **kwargs):
428
+ raise NotImplementedError("polylines is not yet implemented in the cv2 frontend")
@@ -1,7 +1,3 @@
1
- """A Python library for creating and viewing videos with vidformer."""
2
-
3
- __version__ = "0.5.4"
4
-
5
1
  import subprocess
6
2
  from fractions import Fraction
7
3
  import random
@@ -21,6 +17,8 @@ import requests
21
17
  import msgpack
22
18
  import numpy as np
23
19
 
20
+ from . import __version__
21
+
24
22
  _in_notebook = False
25
23
  try:
26
24
  from IPython import get_ipython
@@ -355,7 +353,7 @@ class Loader:
355
353
  class YrdenServer:
356
354
  """A connection to a Yrden server"""
357
355
 
358
- def __init__(self, domain=None, port=None, bin="vidformer-cli"):
356
+ def __init__(self, domain=None, port=None, bin=None):
359
357
  """Connect to a Yrden server
360
358
 
361
359
  Can either connect to an existing server, if domain and port are provided, or start a new server using the provided binary
@@ -365,7 +363,12 @@ class YrdenServer:
365
363
  self._port = port
366
364
  self._proc = None
367
365
  if self._port is None:
368
- assert bin is not None
366
+ if bin is None:
367
+ if os.getenv("VIDFORMER_BIN") is not None:
368
+ bin = os.getenv("VIDFORMER_BIN")
369
+ else:
370
+ bin = "vidformer-cli"
371
+
369
372
  self._domain = "localhost"
370
373
  self._port = random.randint(49152, 65535)
371
374
  cmd = [bin, "yrden", "--port", str(self._port)]
@@ -579,17 +582,31 @@ class StorageService:
579
582
  return f"{self._service}(config={self._config})"
580
583
 
581
584
 
582
- def _json_arg(arg):
585
+ def _json_arg(arg, skip_data_anot=False):
583
586
  if type(arg) == FilterExpr or type(arg) == SourceExpr:
584
587
  return {"Frame": arg._to_json_spec()}
585
588
  elif type(arg) == int:
589
+ if skip_data_anot:
590
+ return {"Int": arg}
586
591
  return {"Data": {"Int": arg}}
587
592
  elif type(arg) == str:
593
+ if skip_data_anot:
594
+ return {"String": arg}
588
595
  return {"Data": {"String": arg}}
596
+ elif type(arg) == float:
597
+ if skip_data_anot:
598
+ return {"Float": arg}
599
+ return {"Data": {"Float": arg}}
589
600
  elif type(arg) == bool:
601
+ if skip_data_anot:
602
+ return {"Bool": arg}
590
603
  return {"Data": {"Bool": arg}}
604
+ elif type(arg) == tuple or type(arg) == list:
605
+ if skip_data_anot:
606
+ return {"List": [_json_arg(x, True) for x in list(arg)]}
607
+ return {"Data": {"List": [_json_arg(x, True) for x in list(arg)]}}
591
608
  else:
592
- assert False
609
+ raise Exception(f"Unknown arg type: {type(arg)}")
593
610
 
594
611
 
595
612
  class Filter:
@@ -751,9 +768,9 @@ class UDF:
751
768
  keys = list(obj.keys())
752
769
  assert len(keys) == 1
753
770
  type_key = keys[0]
754
- assert type_key in ["Frame", "String", "Int", "Bool"]
771
+ assert type_key in ["FrameType", "String", "Int", "Bool"]
755
772
 
756
- if type_key == "Frame":
773
+ if type_key == "FrameType":
757
774
  frame = obj[type_key]
758
775
  assert type(frame) == dict
759
776
  assert "width" in frame
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.1
2
+ Name: vidformer
3
+ Version: 0.6.1
4
+ Summary: A Python library for creating and viewing videos with vidformer.
5
+ Author-email: Dominik Winecki <dominikwinecki@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Dist: requests
11
+ Requires-Dist: msgpack
12
+ Requires-Dist: numpy
13
+ Project-URL: Documentation, https://ixlab.github.io/vidformer/vidformer-py/
14
+ Project-URL: Homepage, https://ixlab.github.io/vidformer/
15
+ Project-URL: Issues, https://github.com/ixlab/vidformer/issues
16
+
17
+ # vidformer-py
18
+
19
+ [![PyPI version](https://img.shields.io/pypi/v/vidformer.svg)](https://pypi.org/project/vidformer/)
20
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/ixlab/vidformer/blob/main/LICENSE)
21
+
22
+
23
+ vidformer-py is our Python 🐍 interface for [vidformer](https://github.com/ixlab/vidformer).
24
+ Our [getting started guide](https://ixlab.github.io/vidformer/getting-started.html) explains how to use it.
25
+
26
+ **Quick links:**
27
+ * [📦 PyPI](https://pypi.org/project/vidformer/)
28
+ * [📘 Documentation](https://ixlab.github.io/vidformer/vidformer-py/)
29
+ * [🧑‍💻 Source Code](https://github.com/ixlab/vidformer/tree/main/vidformer-py/)
30
+
31
+ **Publish:**
32
+ ```bash
33
+ export FLIT_USERNAME='__token__' FLIT_PASSWORD='<token>'
34
+ flit publish
35
+ ```
36
+
@@ -0,0 +1,7 @@
1
+ vidformer/__init__.py,sha256=C-kb3m7hPUh0Sw09vty3JKJHMbJTQcdqSmt8m2V9HIM,113
2
+ vidformer/vf.py,sha256=gexrp0PQ8cbkixCPLY9BCquHeHWfD6iUcA_wbSxGmFQ,29511
3
+ vidformer/cv2/__init__.py,sha256=wOjDsYyUKlP_Hye8-tyz-msu9xwaPMpN2sGMu3Lh3-w,22
4
+ vidformer/cv2/vf_cv2.py,sha256=m05MNPklhaaAfFQfTWetJ_FqWq0u_s77INfABUnHVoA,11664
5
+ vidformer-0.6.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
6
+ vidformer-0.6.1.dist-info/METADATA,sha256=gbvJy_0NGLbnq-EvDsDSoUm7EmHhlfUQL5au6pKCsXk,1383
7
+ vidformer-0.6.1.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: vidformer
3
- Version: 0.5.4
4
- Summary: A Python library for creating and viewing videos with vidformer.
5
- Author-email: Dominik Winecki <dominikwinecki@gmail.com>
6
- Requires-Python: >=3.8
7
- Description-Content-Type: text/markdown
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Operating System :: OS Independent
10
- Requires-Dist: requests
11
- Requires-Dist: msgpack
12
- Requires-Dist: numpy
13
- Project-URL: Homepage, https://ixlab.github.io/vidformer/
14
- Project-URL: Issues, https://ixlab.github.io/vidformer/issues
15
-
16
- # vidformer-py
17
-
18
- ## Publish
19
-
20
- ```bash
21
- export FLIT_USERNAME='__token__' FLIT_PASSWORD='<token>'
22
- flit publish
23
- ```
24
-
@@ -1,4 +0,0 @@
1
- vidformer.py,sha256=11H5DONF82OWWdd4DxE30u9puuT_Y3sy3bFEhvKZs54,28821
2
- vidformer-0.5.4.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
3
- vidformer-0.5.4.dist-info/METADATA,sha256=Sn-s_MobObWQkbOiqDqeKNB69Td5kjM79TdXN-YXgHs,643
4
- vidformer-0.5.4.dist-info/RECORD,,