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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpyimage
3
- Version: 3.4.0
3
+ Version: 3.4.2
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
@@ -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, radius, radius)
211
+ center = (radius,) * ndims
212
212
  imset_kwargs['convention'] = 'center'
213
213
  return_image = True
214
-
215
- norm = lambda v: np.sqrt(sum(v**2))
216
- perpendicular = np.array(perpendicular)
217
- if eq(norm(perpendicular), 0):
218
- print('WARNING: Perpendicular had 0 length. No circle was drawn.')
219
- perpendicular = perpendicular / norm(perpendicular)
220
-
221
- ax = np.array((1,) + (0,) * (ndims-1))
222
- v0 = np.cross(ax, perpendicular)
223
- if eq(norm(v0), 0):
224
- v0 = np.cross(np.flip(ax), perpendicular)
225
- v1 = np.cross(v0, perpendicular)
226
- v0 = v0 / norm(v0)
227
- v1 = v1 / norm(v1)
228
-
229
- num_pts = iceil(math.pi*radius/spacing) + 1
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 convert_to_8bit and data.dtype != np.uint8:
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, isint, find_channel_axis
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 isinstance(factor, int):
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 isint(im2_offset):
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 [isinstance(a, int) or np.issubdtype(type(a), np.integer)
56
- for a in n]
75
+ return [np.issubdtype(type(a), np.integer) for a in n]
57
76
  except TypeError:
58
- return isinstance(n, int) or np.issubdtype(type(n), np.integer)
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 isinstance(possible_channel_axes, int):
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 isinstance(possible_channel_lengths, int):
160
+ if np.issubdtype(type(possible_channel_lengths), np.integer):
142
161
  possible_channel_lengths = [possible_channel_lengths]
143
162
 
144
- if isinstance(minimum_image_size, int):
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 isinstance(index['framerate'], int):
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 isinstance(key, tuple):
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpyimage
3
- Version: 3.4.0
3
+ Version: 3.4.2
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
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'numpyimage'
7
- version = '3.4.0'
7
+ version = '3.4.2'
8
8
  description = 'Load, save, & manipulate image files as numpy arrays'
9
9
  readme.file = 'README.md'
10
10
  readme.content-type = 'text/markdown'
File without changes
File without changes
File without changes
File without changes
File without changes