numpyimage 3.4.2__tar.gz → 3.5.0__tar.gz
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.
- {numpyimage-3.4.2/numpyimage.egg-info → numpyimage-3.5.0}/PKG-INFO +2 -2
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/vidio.py +57 -41
- {numpyimage-3.4.2 → numpyimage-3.5.0/numpyimage.egg-info}/PKG-INFO +2 -2
- {numpyimage-3.4.2 → numpyimage-3.5.0}/pyproject.toml +3 -3
- {numpyimage-3.4.2 → numpyimage-3.5.0}/LICENSE +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/README.md +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/__init__.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/align.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/graphics.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/imageio.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/nrrd_utils.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/operations.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/npimage/utils.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/numpyimage.egg-info/SOURCES.txt +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/numpyimage.egg-info/dependency_links.txt +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/numpyimage.egg-info/requires.txt +1 -1
- {numpyimage-3.4.2 → numpyimage-3.5.0}/numpyimage.egg-info/top_level.txt +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/setup.cfg +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/tests/test_heic.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/tests/test_pbm.py +0 -0
- {numpyimage-3.4.2 → numpyimage-3.5.0}/tests/test_video_writers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: numpyimage
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0
|
|
4
4
|
Summary: Load, save, & manipulate image files as numpy arrays
|
|
5
5
|
Author-email: Jasper Phelps <jasper.s.phelps@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -36,6 +36,7 @@ Requires-Python: >=3.6
|
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
License-File: LICENSE
|
|
38
38
|
Requires-Dist: numpy
|
|
39
|
+
Requires-Dist: tqdm
|
|
39
40
|
Requires-Dist: pillow
|
|
40
41
|
Requires-Dist: pillow-heif
|
|
41
42
|
Requires-Dist: tifffile
|
|
@@ -43,7 +44,6 @@ Requires-Dist: pynrrd
|
|
|
43
44
|
Requires-Dist: matplotlib
|
|
44
45
|
Requires-Dist: opencv-python-headless
|
|
45
46
|
Provides-Extra: all
|
|
46
|
-
Requires-Dist: tqdm; extra == "all"
|
|
47
47
|
Requires-Dist: av; extra == "all"
|
|
48
48
|
Dynamic: license-file
|
|
49
49
|
|
|
@@ -25,6 +25,7 @@ import json
|
|
|
25
25
|
from fractions import Fraction
|
|
26
26
|
|
|
27
27
|
import numpy as np
|
|
28
|
+
from tqdm import tqdm
|
|
28
29
|
|
|
29
30
|
from . import utils
|
|
30
31
|
|
|
@@ -44,6 +45,15 @@ codec_aliases = {
|
|
|
44
45
|
supported_extensions = ['mp4', 'mkv', 'avi', 'mov', 'webm']
|
|
45
46
|
|
|
46
47
|
|
|
48
|
+
def _import_av():
|
|
49
|
+
try:
|
|
50
|
+
import av
|
|
51
|
+
return av
|
|
52
|
+
except ImportError:
|
|
53
|
+
raise ImportError('Missing optional dependency for video processing,'
|
|
54
|
+
' run `pip install av` and try again')
|
|
55
|
+
|
|
56
|
+
|
|
47
57
|
def load_video(filename,
|
|
48
58
|
return_framerate=False,
|
|
49
59
|
progress_bar=True) -> Union[np.ndarray, Tuple[np.ndarray, float]]:
|
|
@@ -69,13 +79,7 @@ def load_video(filename,
|
|
|
69
79
|
framerate : float
|
|
70
80
|
The frame rate of the video in frames per second
|
|
71
81
|
"""
|
|
72
|
-
|
|
73
|
-
import av
|
|
74
|
-
from tqdm import tqdm
|
|
75
|
-
except ImportError:
|
|
76
|
-
raise ImportError('Missing optional dependency for video processing,'
|
|
77
|
-
' run `pip install av tqdm`')
|
|
78
|
-
|
|
82
|
+
av = _import_av()
|
|
79
83
|
with av.open(filename) as container:
|
|
80
84
|
stream = container.streams.video[0]
|
|
81
85
|
num_frames = stream.frames
|
|
@@ -132,11 +136,7 @@ def lazy_load_video(filename) -> Iterator[np.ndarray]:
|
|
|
132
136
|
frame : np.ndarray
|
|
133
137
|
Video frame as a numpy array, shape (height, width, colors).
|
|
134
138
|
"""
|
|
135
|
-
|
|
136
|
-
import av
|
|
137
|
-
except ImportError:
|
|
138
|
-
raise ImportError('Missing optional dependency for video processing,'
|
|
139
|
-
' run `pip install av tqdm`')
|
|
139
|
+
av = _import_av()
|
|
140
140
|
with av.open(Path(filename).expanduser()) as container:
|
|
141
141
|
stream = container.streams.video[0]
|
|
142
142
|
for frame in container.decode(stream):
|
|
@@ -149,19 +149,33 @@ class VideoSeekError(RuntimeError):
|
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
class VideoStreamer:
|
|
152
|
-
def __init__(self,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
def __init__(self,
|
|
153
|
+
filename: str,
|
|
154
|
+
verbose: bool = False,
|
|
155
|
+
cache_index: Literal['auto', True, False] = 'auto'):
|
|
156
|
+
"""
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
filename : str
|
|
160
|
+
Path to the video file.
|
|
161
|
+
|
|
162
|
+
verbose : bool, default False
|
|
163
|
+
If True, print progress messages.
|
|
164
|
+
|
|
165
|
+
cache_index : 'auto' (default), True, or False
|
|
166
|
+
**Definitely set this to True in code where speed matters!**
|
|
167
|
+
Whether to cache the frame timestamp index to a .index file
|
|
168
|
+
next to the video file for faster loading next time.
|
|
169
|
+
If 'auto', the index is cached only if building it takes
|
|
170
|
+
more than 0.5 seconds, which only happens for ~1+ GB videos.
|
|
171
|
+
"""
|
|
172
|
+
self.av = _import_av()
|
|
159
173
|
self.verbose = verbose
|
|
160
174
|
self.filename = Path(filename).expanduser()
|
|
161
175
|
if not self.filename.exists():
|
|
162
176
|
raise FileNotFoundError(f'File {filename} not found')
|
|
163
177
|
|
|
164
|
-
self.container = av.open(str(self.filename))
|
|
178
|
+
self.container = self.av.open(str(self.filename))
|
|
165
179
|
self.stream = self.container.streams.video[0]
|
|
166
180
|
self.time_base = self.stream.time_base
|
|
167
181
|
self._frame_iterator = self.container.decode(self.stream)
|
|
@@ -175,12 +189,17 @@ class VideoStreamer:
|
|
|
175
189
|
self._lock = threading.Lock()
|
|
176
190
|
|
|
177
191
|
self.index_filename = self.filename.with_suffix(self.filename.suffix + '.index')
|
|
178
|
-
self.
|
|
192
|
+
self._build_index(cache_index=cache_index)
|
|
179
193
|
|
|
180
|
-
def _build_index(self):
|
|
194
|
+
def _build_index(self, cache_index='auto'):
|
|
195
|
+
if self.index_filename.exists():
|
|
196
|
+
return self._load_index()
|
|
181
197
|
if self.verbose:
|
|
182
198
|
print('Building frame timestamp index for fast random frame access...')
|
|
183
199
|
|
|
200
|
+
import time
|
|
201
|
+
start_time = time.time()
|
|
202
|
+
|
|
184
203
|
frames_pts = []
|
|
185
204
|
# Try getting frame PTS values fast using PyAV
|
|
186
205
|
try:
|
|
@@ -255,15 +274,16 @@ class VideoStreamer:
|
|
|
255
274
|
index['frames_pts'] = frames_pts
|
|
256
275
|
else:
|
|
257
276
|
index['pts0'] = self.pts0
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
277
|
+
|
|
278
|
+
if cache_index is True or (cache_index == 'auto'
|
|
279
|
+
and time.time() - start_time > 0.5):
|
|
280
|
+
with open(self.index_filename, 'w') as f:
|
|
281
|
+
json.dump(index, f)
|
|
282
|
+
if self.verbose:
|
|
283
|
+
print(f'Cached index at "{self.index_filename}"')
|
|
262
284
|
|
|
263
285
|
def _load_index(self):
|
|
264
|
-
if
|
|
265
|
-
self._build_index()
|
|
266
|
-
elif self.verbose:
|
|
286
|
+
if self.verbose:
|
|
267
287
|
print(f'Loading frame timestamp index from "{self.index_filename}"')
|
|
268
288
|
|
|
269
289
|
with open(self.index_filename, 'r') as f:
|
|
@@ -517,6 +537,12 @@ class VideoStreamer:
|
|
|
517
537
|
except Exception:
|
|
518
538
|
pass
|
|
519
539
|
|
|
540
|
+
def __enter__(self):
|
|
541
|
+
return self
|
|
542
|
+
|
|
543
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
544
|
+
self.close()
|
|
545
|
+
|
|
520
546
|
|
|
521
547
|
class AVVideoWriter:
|
|
522
548
|
"""
|
|
@@ -550,12 +576,7 @@ class AVVideoWriter:
|
|
|
550
576
|
def __init__(self, filename, framerate=30, crf=23, compression_speed='medium',
|
|
551
577
|
codec: Literal['libx264', 'libx265'] = 'libx264',
|
|
552
578
|
overwrite=False):
|
|
553
|
-
|
|
554
|
-
import av
|
|
555
|
-
except ImportError:
|
|
556
|
-
raise ImportError('Missing optional dependency for video processing,'
|
|
557
|
-
' run `pip install av tqdm`')
|
|
558
|
-
self.av = av
|
|
579
|
+
self.av = _import_av()
|
|
559
580
|
filename = Path(filename).expanduser()
|
|
560
581
|
if filename.exists() and not overwrite:
|
|
561
582
|
raise FileExistsError(f'File {filename} already exists. '
|
|
@@ -565,7 +586,7 @@ class AVVideoWriter:
|
|
|
565
586
|
self.crf = crf
|
|
566
587
|
self.compression_speed = compression_speed
|
|
567
588
|
self.codec = codec_aliases[codec.lower()]
|
|
568
|
-
self.container = av.open(filename, mode='w')
|
|
589
|
+
self.container = self.av.open(filename, mode='w')
|
|
569
590
|
self.stream = self.container.add_stream(self.codec, rate=self._framerate)
|
|
570
591
|
self.stream.pix_fmt = 'yuv420p'
|
|
571
592
|
self.stream.options = {'crf': str(crf), 'preset': compression_speed}
|
|
@@ -849,11 +870,6 @@ def save_video(data, filename, time_axis=0, color_axis=None, overwrite=False,
|
|
|
849
870
|
The video codec to use for encoding. Can be any of a number of aliases for
|
|
850
871
|
these two codecs, including avc1/h264 vs hevc/hvc1/hev1/h265.
|
|
851
872
|
"""
|
|
852
|
-
try:
|
|
853
|
-
from tqdm import tqdm
|
|
854
|
-
except ImportError:
|
|
855
|
-
raise ImportError('Missing optional dependency for video processing,'
|
|
856
|
-
' run `pip install av tqdm`')
|
|
857
873
|
|
|
858
874
|
filename = str(filename)
|
|
859
875
|
if filename.split('.')[-1].lower() not in supported_extensions:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: numpyimage
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0
|
|
4
4
|
Summary: Load, save, & manipulate image files as numpy arrays
|
|
5
5
|
Author-email: Jasper Phelps <jasper.s.phelps@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -36,6 +36,7 @@ Requires-Python: >=3.6
|
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
License-File: LICENSE
|
|
38
38
|
Requires-Dist: numpy
|
|
39
|
+
Requires-Dist: tqdm
|
|
39
40
|
Requires-Dist: pillow
|
|
40
41
|
Requires-Dist: pillow-heif
|
|
41
42
|
Requires-Dist: tifffile
|
|
@@ -43,7 +44,6 @@ Requires-Dist: pynrrd
|
|
|
43
44
|
Requires-Dist: matplotlib
|
|
44
45
|
Requires-Dist: opencv-python-headless
|
|
45
46
|
Provides-Extra: all
|
|
46
|
-
Requires-Dist: tqdm; extra == "all"
|
|
47
47
|
Requires-Dist: av; extra == "all"
|
|
48
48
|
Dynamic: license-file
|
|
49
49
|
|
|
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = 'numpyimage'
|
|
7
|
-
version = '3.
|
|
7
|
+
version = '3.5.0'
|
|
8
8
|
description = 'Load, save, & manipulate image files as numpy arrays'
|
|
9
9
|
readme.file = 'README.md'
|
|
10
10
|
readme.content-type = 'text/markdown'
|
|
@@ -22,6 +22,7 @@ classifiers = [
|
|
|
22
22
|
urls = {Repository = 'https://github.com/jasper-tms/npimage'}
|
|
23
23
|
dependencies = [
|
|
24
24
|
'numpy',
|
|
25
|
+
'tqdm',
|
|
25
26
|
'pillow',
|
|
26
27
|
'pillow-heif',
|
|
27
28
|
'tifffile',
|
|
@@ -32,8 +33,7 @@ dependencies = [
|
|
|
32
33
|
|
|
33
34
|
[project.optional-dependencies]
|
|
34
35
|
all = [
|
|
35
|
-
|
|
36
|
-
"av"
|
|
36
|
+
'av'
|
|
37
37
|
]
|
|
38
38
|
|
|
39
39
|
[tool.setuptools.packages.find]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|