numpyimage 3.4.0__tar.gz → 3.4.2__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.0/numpyimage.egg-info → numpyimage-3.4.2}/PKG-INFO +1 -1
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/graphics.py +31 -18
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/imageio.py +3 -1
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/operations.py +7 -3
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/utils.py +26 -7
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/vidio.py +23 -12
- {numpyimage-3.4.0 → numpyimage-3.4.2/numpyimage.egg-info}/PKG-INFO +1 -1
- {numpyimage-3.4.0 → numpyimage-3.4.2}/pyproject.toml +1 -1
- {numpyimage-3.4.0 → numpyimage-3.4.2}/LICENSE +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/README.md +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/__init__.py +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/align.py +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/npimage/nrrd_utils.py +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/numpyimage.egg-info/SOURCES.txt +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/numpyimage.egg-info/dependency_links.txt +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/numpyimage.egg-info/requires.txt +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/numpyimage.egg-info/top_level.txt +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/setup.cfg +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/tests/test_heic.py +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/tests/test_pbm.py +0 -0
- {numpyimage-3.4.0 → numpyimage-3.4.2}/tests/test_video_writers.py +0 -0
|
@@ -204,29 +204,42 @@ def drawcircle(image, center, perpendicular, radius, value,
|
|
|
204
204
|
- out_of_bounds: Literal['ignore', 'wrap', 'raise'] = 'ignore'
|
|
205
205
|
- add_missing_dims: Literal[None, 'start', 'end'] = None
|
|
206
206
|
"""
|
|
207
|
-
ndims = 3 # TODO code up logic for determining this from the input
|
|
208
207
|
return_image = False
|
|
209
208
|
if image is None and center is None:
|
|
209
|
+
ndims = len(perpendicular) if perpendicular is not None else 2
|
|
210
210
|
image = np.zeros((2*iceil(radius) + 1,)*ndims, dtype=np.uint8)
|
|
211
|
-
center = (radius,
|
|
211
|
+
center = (radius,) * ndims
|
|
212
212
|
imset_kwargs['convention'] = 'center'
|
|
213
213
|
return_image = True
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
214
|
+
if image is None:
|
|
215
|
+
raise ValueError("Specifying center without image doesn't make sense.")
|
|
216
|
+
ndims = image.ndim
|
|
217
|
+
|
|
218
|
+
if ndims == 1:
|
|
219
|
+
raise ValueError("Can't draw a circle on 1D array.")
|
|
220
|
+
elif ndims == 2:
|
|
221
|
+
if perpendicular is not None:
|
|
222
|
+
print('[npimage.drawcircle] WARNING: perpendicular ignored since ndims is 2.')
|
|
223
|
+
v0 = np.array((1, 0))
|
|
224
|
+
v1 = np.array((0, 1))
|
|
225
|
+
elif perpendicular is None:
|
|
226
|
+
raise ValueError("Must specify perpendicular for ndims > 2")
|
|
227
|
+
else:
|
|
228
|
+
norm = lambda v: np.sqrt(sum(v**2))
|
|
229
|
+
perpendicular = np.array(perpendicular)
|
|
230
|
+
if eq(norm(perpendicular), 0):
|
|
231
|
+
print('WARNING: Perpendicular had 0 length. No circle was drawn.')
|
|
232
|
+
perpendicular = perpendicular / norm(perpendicular)
|
|
233
|
+
|
|
234
|
+
ax = np.array((1,) + (0,) * (ndims-1))
|
|
235
|
+
v0 = np.cross(ax, perpendicular)
|
|
236
|
+
if eq(norm(v0), 0):
|
|
237
|
+
v0 = np.cross(np.flip(ax), perpendicular)
|
|
238
|
+
v1 = np.cross(v0, perpendicular)
|
|
239
|
+
v0 = v0 / norm(v0)
|
|
240
|
+
v1 = v1 / norm(v1)
|
|
241
|
+
|
|
242
|
+
num_pts = iceil(math.pi * radius / spacing) + 1
|
|
230
243
|
angles = np.linspace(0, math.pi, num_pts)
|
|
231
244
|
half1 = (np.outer(np.cos(angles), v0)
|
|
232
245
|
+ np.outer(np.sin(angles), v1)) * radius + center
|
|
@@ -411,7 +411,9 @@ def show(data,
|
|
|
411
411
|
if utils.isint(channel_axis) and channel_axis != -1:
|
|
412
412
|
data = np.moveaxis(data, utils.find_channel_axis(data), -1)
|
|
413
413
|
|
|
414
|
-
if
|
|
414
|
+
if data.dtype == bool:
|
|
415
|
+
data = data.astype(np.uint8) * 255
|
|
416
|
+
elif convert_to_8bit and data.dtype != np.uint8:
|
|
415
417
|
if any(key in convert_kwargs for key in
|
|
416
418
|
['bottom_value', 'bottom_percentile', 'top_value', 'top_percentile']):
|
|
417
419
|
if 'maximize_contrast' not in convert_kwargs:
|
|
@@ -16,7 +16,7 @@ from typing import Iterable, Literal, Union, Optional, Tuple, List
|
|
|
16
16
|
import numpy as np
|
|
17
17
|
from tqdm import tqdm
|
|
18
18
|
|
|
19
|
-
from .utils import iround, eq,
|
|
19
|
+
from .utils import iround, eq, find_channel_axis
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def squeeze_dtype(image: np.ndarray, minimum_bits=1):
|
|
@@ -134,6 +134,10 @@ def cast(image: np.ndarray,
|
|
|
134
134
|
else:
|
|
135
135
|
raise TypeError(f'Unsupported dtype: {output_dtype}')
|
|
136
136
|
|
|
137
|
+
if (bottom_value is not None or top_value is not None
|
|
138
|
+
or bottom_percentile != 0.05 or top_percentile != 99.95):
|
|
139
|
+
maximize_contrast = True
|
|
140
|
+
|
|
137
141
|
if not maximize_contrast:
|
|
138
142
|
if (round_before_cast_to_int
|
|
139
143
|
and np.issubdtype(output_dtype, np.integer)
|
|
@@ -266,7 +270,7 @@ def downsample(image: np.ndarray,
|
|
|
266
270
|
array([[3.5, 5.5]])
|
|
267
271
|
"""
|
|
268
272
|
channel_axis = find_channel_axis(image)
|
|
269
|
-
if
|
|
273
|
+
if np.issubdtype(type(factor), np.integer):
|
|
270
274
|
if channel_axis is not None:
|
|
271
275
|
# If RGB/RGBA image, don't downsample the colors axis
|
|
272
276
|
factor = (factor,) * (len(image.shape) - 1)
|
|
@@ -617,7 +621,7 @@ def overlay_two_images(im1: np.ndarray,
|
|
|
617
621
|
"""
|
|
618
622
|
Overlay two images, with the second image offset by the given amount.
|
|
619
623
|
"""
|
|
620
|
-
if
|
|
624
|
+
if any(np.issubdtype(type(im2_offset), t) for t in [np.integer, np.floating]):
|
|
621
625
|
im2_offset = [im2_offset] * im2.ndim
|
|
622
626
|
if expand_bounds:
|
|
623
627
|
offsets = ([max(0, -o) for o in im2_offset],
|
|
@@ -49,13 +49,32 @@ def eq(a, b, tolerance=1e-8):
|
|
|
49
49
|
return abs(a - b) < tolerance
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
#TODO duck type this to accept a more general class of objects that extend ints
|
|
53
52
|
def isint(n):
|
|
53
|
+
"""
|
|
54
|
+
Check whether the given variable is an integer (either a built-in
|
|
55
|
+
int or a numpy integer type). If the argument is iterable, return
|
|
56
|
+
a list of booleans indicating whether each element is an integer
|
|
57
|
+
(again either a built-in int or a numpy integer type).
|
|
58
|
+
|
|
59
|
+
Notes
|
|
60
|
+
-----
|
|
61
|
+
You might think that isinstance(n, int) is what you want, but that
|
|
62
|
+
has the undesirable behavior of returning True for bools, and
|
|
63
|
+
returning False for numpy integer types.
|
|
64
|
+
To check whether n is a built-in int or np.integer _but not an iterable
|
|
65
|
+
of them_, use `if npimage.isint(n) is True`, or just
|
|
66
|
+
call `if np.issubdtype(type(n), np.integer)` yourself.
|
|
67
|
+
This function does NOT recognize integer types from other packages
|
|
68
|
+
including TensorFlow, PyTorch, or JAX.
|
|
69
|
+
"""
|
|
70
|
+
if isinstance(n, np.ndarray) and n.ndim > 1:
|
|
71
|
+
raise TypeError("npimage.isint is meant for scalars and vectors,"
|
|
72
|
+
" not matrices. Use np.issubdtype(n.dtype, np.integer)"
|
|
73
|
+
" directly if you want to check your array's type.")
|
|
54
74
|
try:
|
|
55
|
-
return [
|
|
56
|
-
for a in n]
|
|
75
|
+
return [np.issubdtype(type(a), np.integer) for a in n]
|
|
57
76
|
except TypeError:
|
|
58
|
-
return
|
|
77
|
+
return np.issubdtype(type(n), np.integer)
|
|
59
78
|
|
|
60
79
|
|
|
61
80
|
def find_channel_axis(data,
|
|
@@ -133,15 +152,15 @@ def find_channel_axis(data,
|
|
|
133
152
|
>>> npimage.find_channel_axis(np.empty((30, 4)), minimum_image_size=0)
|
|
134
153
|
1
|
|
135
154
|
"""
|
|
136
|
-
if
|
|
155
|
+
if np.issubdtype(type(possible_channel_axes), np.integer):
|
|
137
156
|
possible_channel_axes = [possible_channel_axes]
|
|
138
157
|
if possible_channel_axes is None:
|
|
139
158
|
possible_channel_axes = range(data.ndim)
|
|
140
159
|
|
|
141
|
-
if
|
|
160
|
+
if np.issubdtype(type(possible_channel_lengths), np.integer):
|
|
142
161
|
possible_channel_lengths = [possible_channel_lengths]
|
|
143
162
|
|
|
144
|
-
if
|
|
163
|
+
if np.issubdtype(type(minimum_image_size), np.integer):
|
|
145
164
|
minimum_image_size = (minimum_image_size,)
|
|
146
165
|
|
|
147
166
|
for axis in possible_channel_axes:
|
|
@@ -280,7 +280,7 @@ class VideoStreamer:
|
|
|
280
280
|
self.frames_pts = index['frames_pts']
|
|
281
281
|
else:
|
|
282
282
|
self.pts0 = index['pts0']
|
|
283
|
-
if
|
|
283
|
+
if np.issubdtype(type(index['framerate']), np.integer):
|
|
284
284
|
self._framerate = index['framerate']
|
|
285
285
|
else:
|
|
286
286
|
self._framerate = Fraction(index['framerate']['numerator'],
|
|
@@ -343,15 +343,29 @@ class VideoStreamer:
|
|
|
343
343
|
return (pts - self.pts0) // self.pts_delta
|
|
344
344
|
|
|
345
345
|
def __getitem__(self, key) -> np.ndarray:
|
|
346
|
-
if
|
|
347
|
-
frame_idx = key[0]
|
|
348
|
-
frame = self._get_frame(frame_idx)
|
|
349
|
-
if len(key) == 1:
|
|
350
|
-
return frame
|
|
351
|
-
else:
|
|
352
|
-
return frame[key[1:]]
|
|
353
|
-
else:
|
|
346
|
+
if np.issubdtype(type(key), np.integer):
|
|
354
347
|
return self._get_frame(key)
|
|
348
|
+
if isinstance(key, slice): # Support slicing
|
|
349
|
+
key = (key,) # Logic is handled in the tuple case below
|
|
350
|
+
if not isinstance(key, tuple):
|
|
351
|
+
raise TypeError('Key must be an int, slice, or a tuple of ints/slices')
|
|
352
|
+
|
|
353
|
+
frame_idx = key[0]
|
|
354
|
+
if np.issubdtype(type(frame_idx), np.integer):
|
|
355
|
+
frames = self._get_frame(frame_idx)
|
|
356
|
+
key = key[1:]
|
|
357
|
+
elif isinstance(frame_idx, slice): # Support slicing
|
|
358
|
+
start, stop, step = frame_idx.indices(self.n_frames)
|
|
359
|
+
frames = np.array([self._get_frame(i) for i in range(start, stop, step)])
|
|
360
|
+
key = (slice(None),) + key[1:]
|
|
361
|
+
elif isinstance(frame_idx, (list, tuple, np.ndarray)): # Support sequences of ints
|
|
362
|
+
if not all(utils.isint(frame_idx)):
|
|
363
|
+
raise TypeError('Sequences of frame indices must contain only integers')
|
|
364
|
+
frames = np.array([self._get_frame(i) for i in frame_idx])
|
|
365
|
+
key = (slice(None),) + key[1:]
|
|
366
|
+
else:
|
|
367
|
+
raise TypeError("Key's first element must be an int, slice, or sequence of ints")
|
|
368
|
+
return frames[key]
|
|
355
369
|
|
|
356
370
|
def _get_frame(self, frame_number) -> np.ndarray:
|
|
357
371
|
"""
|
|
@@ -390,9 +404,6 @@ class VideoStreamer:
|
|
|
390
404
|
f'{target_pts}). Last seen frame was {self._current_frame_number}'
|
|
391
405
|
f' (PTS {self.frame_number_to_pts(self._current_frame_number)}')
|
|
392
406
|
|
|
393
|
-
if isinstance(frame_number, slice): # Support slicing
|
|
394
|
-
start, stop, step = frame_number.indices(self.n_frames)
|
|
395
|
-
return np.array([self._get_frame(i) for i in range(start, stop, step)])
|
|
396
407
|
with self._lock:
|
|
397
408
|
frame_number = self._normalize_frame_number(frame_number)
|
|
398
409
|
if (self._current_frame_number is None
|
|
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
|