vidformer 0.6.5__py3-none-any.whl → 0.8.0__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.
vidformer/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """A Python library for creating and viewing videos with vidformer."""
2
2
 
3
- __version__ = "0.6.5"
3
+ __version__ = "0.8.0"
4
4
 
5
5
  from .vf import *
vidformer/cv2/vf_cv2.py CHANGED
@@ -45,6 +45,11 @@ LINE_4 = 4
45
45
  LINE_8 = 8
46
46
  LINE_AA = 16
47
47
 
48
+ _inline_mat = vf.Filter("_inline_mat")
49
+ _slice_mat = vf.Filter("_slice_mat")
50
+ _slice_write_mat = vf.Filter("_slice_write_mat")
51
+
52
+
48
53
  _filter_scale = vf.Filter("Scale")
49
54
  _filter_rectangle = vf.Filter("cv2.rectangle")
50
55
  _filter_putText = vf.Filter("cv2.putText")
@@ -96,8 +101,9 @@ class Frame:
96
101
  return
97
102
 
98
103
  self._modified = True
99
- self._f = _filter_scale(self._f, pix_fmt="rgb24")
100
- self._fmt["pix_fmt"] = "rgb24"
104
+ if self._fmt["pix_fmt"] != "rgb24":
105
+ self._f = _filter_scale(self._f, pix_fmt="rgb24")
106
+ self._fmt["pix_fmt"] = "rgb24"
101
107
 
102
108
  def numpy(self):
103
109
  """
@@ -113,8 +119,112 @@ class Frame:
113
119
  assert len(frame_raster_rgb24) == self.shape[0] * self.shape[1] * 3
114
120
  raw_data_array = np.frombuffer(frame_raster_rgb24, dtype=np.uint8)
115
121
  frame = raw_data_array.reshape(self.shape)
122
+ frame = frame[:, :, ::-1] # convert RGB to BGR
116
123
  return frame
117
124
 
125
+ def __getitem__(self, key):
126
+ if not isinstance(key, tuple):
127
+ raise NotImplementedError("Only 2D slicing is supported")
128
+
129
+ if len(key) != 2:
130
+ raise NotImplementedError("Only 2D slicing is supported")
131
+
132
+ if not all(isinstance(x, slice) for x in key):
133
+ raise NotImplementedError("Only 2D slicing is supported")
134
+
135
+ miny = key[0].start if key[0].start is not None else 0
136
+ maxy = key[0].stop if key[0].stop is not None else self.shape[0]
137
+ minx = key[1].start if key[1].start is not None else 0
138
+ maxx = key[1].stop if key[1].stop is not None else self.shape[1]
139
+
140
+ # handle negative indices
141
+ if miny < 0:
142
+ miny = self.shape[0] + miny
143
+ if maxy < 0:
144
+ maxy = self.shape[0] + maxy
145
+ if minx < 0:
146
+ minx = self.shape[1] + minx
147
+ if maxx < 0:
148
+ maxx = self.shape[1] + maxx
149
+
150
+ if (
151
+ maxy <= miny
152
+ or maxx <= minx
153
+ or miny < 0
154
+ or minx < 0
155
+ or maxy > self.shape[0]
156
+ or maxx > self.shape[1]
157
+ ):
158
+ raise NotImplementedError("Invalid slice")
159
+
160
+ f = _slice_mat(self._f, miny, maxy, minx, maxx)
161
+ fmt = self._fmt.copy()
162
+ fmt["width"] = maxx - minx
163
+ fmt["height"] = maxy - miny
164
+ return Frame(f, fmt)
165
+
166
+ def __setitem__(self, key, value):
167
+ value = frameify(value, "value")
168
+
169
+ if not isinstance(key, tuple):
170
+ raise NotImplementedError("Only 2D slicing is supported")
171
+
172
+ if len(key) != 2:
173
+ raise NotImplementedError("Only 2D slicing is supported")
174
+
175
+ if not all(isinstance(x, slice) for x in key):
176
+ raise NotImplementedError("Only 2D slicing is supported")
177
+
178
+ miny = key[0].start if key[0].start is not None else 0
179
+ maxy = key[0].stop if key[0].stop is not None else self.shape[0]
180
+ minx = key[1].start if key[1].start is not None else 0
181
+ maxx = key[1].stop if key[1].stop is not None else self.shape[1]
182
+
183
+ # handle negative indices
184
+ if miny < 0:
185
+ miny = self.shape[0] + miny
186
+ if maxy < 0:
187
+ maxy = self.shape[0] + maxy
188
+ if minx < 0:
189
+ minx = self.shape[1] + minx
190
+ if maxx < 0:
191
+ maxx = self.shape[1] + maxx
192
+
193
+ if (
194
+ maxy <= miny
195
+ or maxx <= minx
196
+ or miny < 0
197
+ or minx < 0
198
+ or maxy > self.shape[0]
199
+ or maxx > self.shape[1]
200
+ ):
201
+ raise NotImplementedError("Invalid slice")
202
+
203
+ if value.shape[0] != maxy - miny or value.shape[1] != maxx - minx:
204
+ raise NotImplementedError("Shape mismatch")
205
+
206
+ self._mut()
207
+ value._mut()
208
+
209
+ self._f = _slice_write_mat(self._f, value._f, miny, maxy, minx, maxx)
210
+
211
+
212
+ def _inline_frame(arr):
213
+ assert arr.dtype == np.uint8
214
+ assert arr.ndim == 3
215
+ assert arr.shape[2] == 3
216
+
217
+ # convert BGR to RGB
218
+ arr = arr[:, :, ::-1]
219
+
220
+ width = arr.shape[1]
221
+ height = arr.shape[0]
222
+ pix_fmt = "rgb24"
223
+
224
+ f = _inline_mat(arr.tobytes(), width=width, height=height, pix_fmt=pix_fmt)
225
+ fmt = {"width": width, "height": height, "pix_fmt": pix_fmt}
226
+ return Frame(f, fmt)
227
+
118
228
 
119
229
  class VideoCapture:
120
230
  def __init__(self, path):
@@ -178,9 +288,9 @@ class VideoWriter:
178
288
  self._pix_fmt = "yuv420p"
179
289
 
180
290
  def write(self, frame):
181
- if not isinstance(frame, Frame):
182
- raise Exception("frame must be a vidformer.cv2.Frame object")
183
- if frame._modified:
291
+ frame = frameify(frame, "frame")
292
+
293
+ if frame._fmt["pix_fmt"] != self._pix_fmt:
184
294
  f_obj = _filter_scale(frame._f, pix_fmt=self._pix_fmt)
185
295
  self._frames.append(f_obj)
186
296
  else:
@@ -210,6 +320,24 @@ class VideoWriter_fourcc:
210
320
  self._args = args
211
321
 
212
322
 
323
+ def frameify(obj, field_name=None):
324
+ """
325
+ Turn an object (e.g., ndarray) into a Frame.
326
+ """
327
+
328
+ if isinstance(obj, Frame):
329
+ return obj
330
+ elif isinstance(obj, np.ndarray):
331
+ return _inline_frame(obj)
332
+ else:
333
+ if field_name is not None:
334
+ raise Exception(
335
+ f"Unsupported type for field {field_name}, expected Frame or np.ndarray"
336
+ )
337
+ else:
338
+ raise Exception("Unsupported type, expected Frame or np.ndarray")
339
+
340
+
213
341
  def imread(path, *args):
214
342
  if len(args) > 0:
215
343
  raise NotImplementedError("imread does not support additional arguments")
@@ -225,8 +353,7 @@ def imwrite(path, img, *args):
225
353
  if len(args) > 0:
226
354
  raise NotImplementedError("imwrite does not support additional arguments")
227
355
 
228
- if not isinstance(img, Frame):
229
- raise Exception("img must be a vidformer.cv2.Frame object")
356
+ img = frameify(img)
230
357
 
231
358
  fmt = img._fmt.copy()
232
359
  width = fmt["width"]
@@ -282,7 +409,7 @@ def rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None):
282
409
  cv.rectangle( img, pt1, pt2, color[, thickness[, lineType[, shift]]] )
283
410
  """
284
411
 
285
- assert isinstance(img, Frame)
412
+ img = frameify(img)
286
413
  img._mut()
287
414
 
288
415
  assert len(pt1) == 2
@@ -326,7 +453,7 @@ def putText(
326
453
  cv.putText( img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]] )
327
454
  """
328
455
 
329
- assert isinstance(img, Frame)
456
+ img = frameify(img)
330
457
  img._mut()
331
458
 
332
459
  assert isinstance(text, str)
@@ -365,7 +492,7 @@ def arrowedLine(
365
492
  """
366
493
  cv.arrowedLine( img, pt1, pt2, color[, thickness[, line_type[, shift[, tipLength]]]] )
367
494
  """
368
- assert isinstance(img, Frame)
495
+ img = frameify(img)
369
496
  img._mut()
370
497
 
371
498
  assert len(pt1) == 2
@@ -399,7 +526,7 @@ def arrowedLine(
399
526
 
400
527
 
401
528
  def line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None):
402
- assert isinstance(img, Frame)
529
+ img = frameify(img)
403
530
  img._mut()
404
531
 
405
532
  assert len(pt1) == 2
@@ -429,7 +556,7 @@ def line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None):
429
556
 
430
557
 
431
558
  def circle(img, center, radius, color, thickness=None, lineType=None, shift=None):
432
- assert isinstance(img, Frame)
559
+ img = frameify(img)
433
560
  img._mut()
434
561
 
435
562
  assert len(center) == 2
@@ -480,15 +607,15 @@ def addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=-1):
480
607
  """
481
608
  cv.addWeighted( src1, alpha, src2, beta, gamma[, dst[, dtype]] ) -> dst
482
609
  """
483
- assert isinstance(src1, Frame)
484
- assert isinstance(src2, Frame)
610
+ src1 = frameify(src1, "src1")
611
+ src2 = frameify(src2, "src2")
485
612
  src1._mut()
486
613
  src2._mut()
487
614
 
488
615
  if dst is None:
489
616
  dst = Frame(src1._f, src1._fmt.copy())
490
617
  else:
491
- assert isinstance(dst, Frame)
618
+ assert isinstance(dst, Frame), "dst must be a Frame"
492
619
  dst._mut()
493
620
 
494
621
  assert isinstance(alpha, float) or isinstance(alpha, int)
vidformer/vf.py CHANGED
@@ -638,6 +638,11 @@ def _json_arg(arg, skip_data_anot=False):
638
638
  if skip_data_anot:
639
639
  return {"String": arg}
640
640
  return {"Data": {"String": arg}}
641
+ elif type(arg) == bytes:
642
+ arg = list(arg)
643
+ if skip_data_anot:
644
+ return {"Bytes": arg}
645
+ return {"Data": {"Bytes": arg}}
641
646
  elif type(arg) == float:
642
647
  if skip_data_anot:
643
648
  return {"Float": arg}
@@ -837,7 +842,7 @@ class UDF:
837
842
  assert type(obj[type_key]) == bool
838
843
  return obj[type_key]
839
844
  else:
840
- assert False
845
+ assert False, f"Unknown type: {type_key}"
841
846
 
842
847
  def _deser_filter(self, obj):
843
848
  assert type(obj) == dict
@@ -873,7 +878,7 @@ class UDF:
873
878
  assert type(obj[type_key]) == bool
874
879
  return obj[type_key]
875
880
  else:
876
- assert False
881
+ assert False, f"Unknown type: {type_key}"
877
882
 
878
883
  def _host(self, socket_path: str):
879
884
  if os.path.exists(socket_path):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: vidformer
3
- Version: 0.6.5
3
+ Version: 0.8.0
4
4
  Summary: A Python library for creating and viewing videos with vidformer.
5
5
  Author-email: Dominik Winecki <dominikwinecki@gmail.com>
6
6
  Requires-Python: >=3.8
@@ -0,0 +1,7 @@
1
+ vidformer/__init__.py,sha256=scMlj2LLMBZXdv9ob_Dhb4ObK7RZLzxVgELyaR650xU,113
2
+ vidformer/vf.py,sha256=GjgaKnbk3o75lwrXP3Ue0LDyTxSf-l0njL5X-6QYZvs,31496
3
+ vidformer/cv2/__init__.py,sha256=wOjDsYyUKlP_Hye8-tyz-msu9xwaPMpN2sGMu3Lh3-w,22
4
+ vidformer/cv2/vf_cv2.py,sha256=8shv614pmNHQyHMqjJSZf08j3eNxE_XtfdLd_kyh5no,19396
5
+ vidformer-0.8.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
6
+ vidformer-0.8.0.dist-info/METADATA,sha256=aXFYRxtNx4hfWlqW7Zx_RW-X2CuN3-adYwRrCUkLtI4,1487
7
+ vidformer-0.8.0.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- vidformer/__init__.py,sha256=WDRsfzSyzVQEEuzspuxEn94sNB9jGZpaYEiZsLqOC7U,113
2
- vidformer/vf.py,sha256=GT7t4hFgqK-66m9ejVtdeeHmWnShG-lxENPfMhV9vcg,31284
3
- vidformer/cv2/__init__.py,sha256=wOjDsYyUKlP_Hye8-tyz-msu9xwaPMpN2sGMu3Lh3-w,22
4
- vidformer/cv2/vf_cv2.py,sha256=sSoZGwi-NGNd263ZdiVbu2iXVF0fxbXKBVof5KR0-cw,15584
5
- vidformer-0.6.5.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
6
- vidformer-0.6.5.dist-info/METADATA,sha256=fgeoJMLG2KZJLxzHbRrOEZVXQtbWWFtAfqdKJ1mEqhQ,1487
7
- vidformer-0.6.5.dist-info/RECORD,,