numpyimage 1.3.0__tar.gz → 2.0.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-2.0.0/PKG-INFO +52 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/core.py +146 -75
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/operations.py +5 -5
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/utils.py +10 -3
- numpyimage-2.0.0/numpyimage.egg-info/PKG-INFO +52 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/numpyimage.egg-info/SOURCES.txt +1 -2
- {numpyimage-1.3.0 → numpyimage-2.0.0}/setup.py +1 -1
- numpyimage-1.3.0/PKG-INFO +0 -58
- numpyimage-1.3.0/numpyimage.egg-info/PKG-INFO +0 -58
- numpyimage-1.3.0/tests/tests.py +0 -39
- {numpyimage-1.3.0 → numpyimage-2.0.0}/LICENSE +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/MANIFEST.in +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/README.md +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/__init__.py +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/align.py +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/filetypes/__init__.py +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/filetypes/pbm.py +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/graphics.py +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/npimage/nrrd_utils.py +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/numpyimage.egg-info/dependency_links.txt +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/numpyimage.egg-info/requires.txt +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/numpyimage.egg-info/top_level.txt +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/requirements.txt +0 -0
- {numpyimage-1.3.0 → numpyimage-2.0.0}/setup.cfg +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: numpyimage
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Load, save, and manipulate image files as numpy arrays
|
|
5
|
+
Home-page: https://github.com/jasper-tms/npimage
|
|
6
|
+
Author: Jasper Phelps
|
|
7
|
+
Author-email: jasper.s.phelps@gmail.com
|
|
8
|
+
License: GNU GPL v3
|
|
9
|
+
Description: # npimage
|
|
10
|
+
Need to load pixel values from image files as numpy arrays, and hate having to remember whether you should use PIL, tifffile, matplotlib, or something else? Hate having to deal with the fact that those libraries all use different function names and syntaxes? Wish you could just provide a filename and get back a numpy array? This library's `core.py` does that, with `array = load(filename)`, `save(array, filename)`, and `show(array)` functions that let you easily handle a number of common image file formats without having to remember library-specific syntax. (Another choice of library to consider for accomplishing similar goals is [imageio](https://pypi.org/project/imageio/), which also supports loading videos through the FFmpeg wrapper library [pyav](https://pypi.org/project/av/).)
|
|
11
|
+
|
|
12
|
+
Want to draw simple shapes like lines, triangles, and circles into 3D numpy arrays? Frustrated that the python libraries you can find online like `opencv` and `skimage.draw` work on 2D arrays but not 3D? I wrote some functions in `graphics.py` that do the trick in 3D. (If you know of another library that can do this, please let me know!)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Documentation
|
|
16
|
+
- `core.py`: load, save, or show images.
|
|
17
|
+
- `graphics.py`: draw points, lines, triangles, circles, or spheres into 2D or 3D numpy arrays representing image volumes.
|
|
18
|
+
- `nrrd_utils.py`: compress or read metadata from `.nrrd` files.
|
|
19
|
+
- `operations.py`: perform operations on images.
|
|
20
|
+
|
|
21
|
+
For now, check each function's docstring for more. A jupyter notebook demonstrating this package's functions will come later.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Installation
|
|
25
|
+
|
|
26
|
+
As is always the case in python, consider making a virtual environment (using your preference of conda, virtualenv, or virtualenvwrapper) before installing.
|
|
27
|
+
|
|
28
|
+
**Option 1:** `pip install` from PyPI:
|
|
29
|
+
|
|
30
|
+
pip install numpyimage
|
|
31
|
+
|
|
32
|
+
(Unfortunately the name `npimage` was already taken on PyPI, so `pip install npimage` will get you a different package.)
|
|
33
|
+
|
|
34
|
+
**Option 2:** `pip install` directly from GitHub:
|
|
35
|
+
|
|
36
|
+
pip install git+https://github.com/jasper-tms/npimage.git
|
|
37
|
+
|
|
38
|
+
**Option 3:** First `git clone` this repo and then `pip install` it from your clone:
|
|
39
|
+
|
|
40
|
+
cd ~/repos # Or wherever on your computer you want to download this code to
|
|
41
|
+
git clone https://github.com/jasper-tms/npimage.git
|
|
42
|
+
cd npimage
|
|
43
|
+
pip install .
|
|
44
|
+
|
|
45
|
+
**After installing,** you can import this package in python using `import npimage` (not `import numpyimage`!)
|
|
46
|
+
|
|
47
|
+
Platform: UNKNOWN
|
|
48
|
+
Classifier: Programming Language :: Python :: 3
|
|
49
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
50
|
+
Classifier: Operating System :: OS Independent
|
|
51
|
+
Requires-Python: >=3.6
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
@@ -15,7 +15,7 @@ from builtins import open as builtin_open
|
|
|
15
15
|
|
|
16
16
|
import numpy as np
|
|
17
17
|
|
|
18
|
-
from . import utils
|
|
18
|
+
from . import operations, utils
|
|
19
19
|
|
|
20
20
|
supported_extensions = [
|
|
21
21
|
'tif', 'tiff', 'jpg', 'jpeg', 'png', 'pbm',
|
|
@@ -30,9 +30,7 @@ def load(filename, dim_order='zyx', **kwargs):
|
|
|
30
30
|
As is typical for Python, the returned array will by default have
|
|
31
31
|
dimensions ordered as zyx for 3D image volumes, yx for 1-channel 2D
|
|
32
32
|
images, or yxc for multi-channel (RGB/RGBA) 2D images.
|
|
33
|
-
Set dim_order='xy' if you
|
|
34
|
-
xyz for 3D image volumes, xy for 1-channel 2D images, or
|
|
35
|
-
xyc for multi-channel 2D images.
|
|
33
|
+
Set dim_order='xy' if you want to reverse the order of the axes.
|
|
36
34
|
"""
|
|
37
35
|
filename = str(filename)
|
|
38
36
|
while filename.endswith('/'):
|
|
@@ -109,13 +107,7 @@ def load(filename, dim_order='zyx', **kwargs):
|
|
|
109
107
|
data = zarr.open(TODO) #TODO check zyx/xyz order
|
|
110
108
|
|
|
111
109
|
if 'xy' in dim_order:
|
|
112
|
-
|
|
113
|
-
# Can't just transpose because if data is a multi-channel 2D
|
|
114
|
-
# image, need the channel axis to stay as the last axis.
|
|
115
|
-
data = data.swapaxes(0, 1)
|
|
116
|
-
else:
|
|
117
|
-
data = data.T
|
|
118
|
-
|
|
110
|
+
data = data.T
|
|
119
111
|
if extension == 'nrrd': # TODO check if other formats need this
|
|
120
112
|
utils.transpose_metadata(metadata, inplace=True)
|
|
121
113
|
|
|
@@ -142,6 +134,7 @@ def save(data,
|
|
|
142
134
|
pixel_size=None,
|
|
143
135
|
units=None,
|
|
144
136
|
compress=None,
|
|
137
|
+
compression_level=3,
|
|
145
138
|
metadata=None):
|
|
146
139
|
"""
|
|
147
140
|
Save a numpy array to file with a file type specified by the
|
|
@@ -170,13 +163,15 @@ def save(data,
|
|
|
170
163
|
'.nrrd. Whether or not compression occurs now will depend on '
|
|
171
164
|
'the format you are saving to.')
|
|
172
165
|
|
|
166
|
+
channel_axis = find_channel_axis(data)
|
|
173
167
|
if 'xy' in dim_order:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
168
|
+
data = data.T
|
|
169
|
+
if hasattr(pixel_size, '__iter__') and not isinstance(pixel_size, str):
|
|
170
|
+
pixel_size = pixel_size[::-1]
|
|
171
|
+
if hasattr(units, '__iter__') and not isinstance(units, str):
|
|
172
|
+
units = units[::-1]
|
|
173
|
+
utils.transpose_metadata(metadata, inplace=True)
|
|
174
|
+
# The spatial axes and associated metadata are now in zyx order.
|
|
180
175
|
|
|
181
176
|
if extension in ['tif', 'tiff']:
|
|
182
177
|
import tifffile
|
|
@@ -199,30 +194,60 @@ def save(data,
|
|
|
199
194
|
metadata = {}
|
|
200
195
|
else:
|
|
201
196
|
metadata = metadata.copy()
|
|
197
|
+
custom_field_map = {}
|
|
198
|
+
|
|
202
199
|
if compress is True:
|
|
203
200
|
metadata.update({'encoding': 'gzip'})
|
|
204
201
|
if compress is False or 'encoding' not in metadata:
|
|
205
202
|
metadata.update({'encoding': 'raw'})
|
|
203
|
+
|
|
204
|
+
if isinstance(metadata.get('space directions', None), str):
|
|
205
|
+
custom_field_map['space directions'] = 'string'
|
|
206
206
|
if pixel_size is not None:
|
|
207
|
+
if 'space directions' in metadata:
|
|
208
|
+
raise ValueError('Cannot specify both "space directions" in'
|
|
209
|
+
' metadata and "pixel_size" as an argument.')
|
|
210
|
+
|
|
207
211
|
try:
|
|
208
212
|
iter(pixel_size)
|
|
213
|
+
if len(pixel_size) == data.ndim - 1 and channel_axis is not None:
|
|
214
|
+
pixel_size.insert(channel_axis, np.nan)
|
|
209
215
|
except TypeError:
|
|
210
|
-
|
|
216
|
+
if channel_axis is not None:
|
|
217
|
+
pixel_size = [pixel_size] * (data.ndim - 1)
|
|
218
|
+
pixel_size.insert(channel_axis, np.nan)
|
|
219
|
+
else:
|
|
220
|
+
pixel_size = [pixel_size] * data.ndim
|
|
221
|
+
if len(pixel_size) != data.ndim:
|
|
222
|
+
raise ValueError(f'pixel_size has length {len(pixel_size)},'
|
|
223
|
+
' but data has {data.ndim} dimensions.')
|
|
224
|
+
|
|
225
|
+
pixel_size_not_none = [size for size in pixel_size
|
|
226
|
+
if size is not None and size != np.nan]
|
|
227
|
+
space_directions = np.diag(pixel_size_not_none).astype(float)
|
|
228
|
+
# nrrd.format_optional_matrix() expects an entire row of
|
|
229
|
+
# np.nan for non-spatial dimensions, so insert row(s) for that.
|
|
230
|
+
none_indices = [i for i, size in enumerate(pixel_size)
|
|
231
|
+
if size is None or size == np.nan]
|
|
232
|
+
space_directions = np.insert(space_directions, none_indices, np.nan, axis=0)
|
|
233
|
+
metadata.update({'space directions': space_directions})
|
|
211
234
|
|
|
212
|
-
if 'xy' in dim_order:
|
|
213
|
-
pixel_size = np.flip(pixel_size)
|
|
214
|
-
metadata.update({'space directions': np.flip(np.diag(pixel_size),
|
|
215
|
-
axis=-1)})
|
|
216
235
|
if 'space dimension' not in metadata and 'space' not in metadata:
|
|
217
236
|
# If the number of spatial dimensions is not specified, assume
|
|
218
|
-
# it's the number of dimensions in the data array, minus
|
|
219
|
-
# channel axis
|
|
220
|
-
if
|
|
237
|
+
# it's the number of dimensions in the data array, minus 1 if
|
|
238
|
+
# a channel axis is present.
|
|
239
|
+
if find_channel_axis(data) is not None:
|
|
221
240
|
metadata.update({'space dimension': data.ndim - 1})
|
|
222
241
|
else:
|
|
223
242
|
metadata.update({'space dimension': data.ndim})
|
|
224
243
|
if units is not None:
|
|
225
|
-
|
|
244
|
+
if hasattr(units, '__iter__') and not isinstance(units, str):
|
|
245
|
+
units = list(units)
|
|
246
|
+
elif 'space dimension' in metadata:
|
|
247
|
+
units = [units] * metadata['space dimension']
|
|
248
|
+
else:
|
|
249
|
+
units = [units] * data.ndim
|
|
250
|
+
metadata.update({'space units': units})
|
|
226
251
|
|
|
227
252
|
# From https://pynrrd.readthedocs.io/en/stable/background/index-ordering.html
|
|
228
253
|
# "C-order is the index order used in Python and many Python libraries
|
|
@@ -241,7 +266,12 @@ def save(data,
|
|
|
241
266
|
# index_order='C' to the nrrd.write command below, we also need to flip
|
|
242
267
|
# the order of any per-axis metadata fields.
|
|
243
268
|
utils.transpose_metadata(metadata, inplace=True)
|
|
244
|
-
nrrd.write(filename,
|
|
269
|
+
nrrd.write(filename,
|
|
270
|
+
data,
|
|
271
|
+
header=metadata,
|
|
272
|
+
custom_field_map=custom_field_map,
|
|
273
|
+
compression_level=compression_level,
|
|
274
|
+
index_order='C')
|
|
245
275
|
|
|
246
276
|
if extension in ['raw', 'vol']:
|
|
247
277
|
raise NotImplementedError
|
|
@@ -251,12 +281,10 @@ def save(data,
|
|
|
251
281
|
|
|
252
282
|
if extension == 'ng':
|
|
253
283
|
from cloudvolume import CloudVolume
|
|
284
|
+
from cloudvolume.exceptions import InfoUnavailableError
|
|
254
285
|
|
|
255
286
|
# CloudVolume expects data in Fortran order
|
|
256
|
-
|
|
257
|
-
data = data.swapaxes(0, 1)
|
|
258
|
-
else:
|
|
259
|
-
data = data.T
|
|
287
|
+
data = data.T
|
|
260
288
|
|
|
261
289
|
resolution = 1
|
|
262
290
|
if pixel_size is not None:
|
|
@@ -265,35 +293,46 @@ def save(data,
|
|
|
265
293
|
iter(resolution)
|
|
266
294
|
except TypeError:
|
|
267
295
|
resolution = [resolution] * data.ndim
|
|
268
|
-
if compress is True or compress
|
|
296
|
+
if compress is True or compress in ['lossy', 'jpeg', 'jpg']:
|
|
269
297
|
encoding = 'jpeg'
|
|
298
|
+
gzip = False
|
|
299
|
+
elif compress is None or compress in ['lossless', 'gzip']:
|
|
300
|
+
if compress is None:
|
|
301
|
+
print('Using gzip compression by default for .ng format.')
|
|
302
|
+
encoding = 'raw'
|
|
270
303
|
gzip = True
|
|
271
|
-
elif compress
|
|
272
|
-
encoding = 'raw',
|
|
273
|
-
gzip = True
|
|
274
|
-
elif compress is False or compress is None:
|
|
304
|
+
elif compress is False:
|
|
275
305
|
encoding = 'raw'
|
|
276
306
|
gzip = False
|
|
277
307
|
else:
|
|
278
|
-
raise ValueError('For .ng format, compress must be
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
info = CloudVolume.create_new_info(
|
|
282
|
-
num_channels=1,
|
|
283
|
-
layer_type='image',
|
|
284
|
-
data_type=data.dtype,
|
|
285
|
-
encoding=encoding,
|
|
286
|
-
resolution=resolution,
|
|
287
|
-
voxel_offset=[0, 0, 0],
|
|
288
|
-
chunk_size=[64, 64, 64],
|
|
289
|
-
volume_size=data.shape
|
|
290
|
-
)
|
|
308
|
+
raise ValueError('For .ng format, compress must be '
|
|
309
|
+
'True/"lossy"/"jpeg"/"jpg", "lossless"/"gzip",'
|
|
310
|
+
f' or False, but was "{compress}"')
|
|
291
311
|
|
|
292
312
|
if not any(filename.startswith(prefix)
|
|
293
313
|
for prefix in ['file://', 'gs://', 's3://']):
|
|
294
314
|
filename = 'file://' + filename
|
|
295
|
-
|
|
296
|
-
|
|
315
|
+
|
|
316
|
+
try:
|
|
317
|
+
vol = CloudVolume(filename, compress=gzip)
|
|
318
|
+
if (vol.shape[:data.ndim] != data.shape
|
|
319
|
+
or any(s != 1 for s in vol.shape[data.ndim:])):
|
|
320
|
+
raise ValueError('Dataset already exists at the specified path,'
|
|
321
|
+
' but its shape does not match the given data.')
|
|
322
|
+
except InfoUnavailableError:
|
|
323
|
+
info = CloudVolume.create_new_info(
|
|
324
|
+
num_channels=1,
|
|
325
|
+
layer_type='image',
|
|
326
|
+
data_type=data.dtype,
|
|
327
|
+
encoding=encoding,
|
|
328
|
+
resolution=resolution,
|
|
329
|
+
voxel_offset=[0, 0, 0],
|
|
330
|
+
chunk_size=[64, 64, 64],
|
|
331
|
+
volume_size=data.shape
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
vol = CloudVolume(filename, info=info, compress=gzip)
|
|
335
|
+
vol.commit_info()
|
|
297
336
|
|
|
298
337
|
vol[:] = data
|
|
299
338
|
|
|
@@ -309,11 +348,6 @@ def save_video(data, filename, overwrite=False, dim_order='yx', time_axis=0,
|
|
|
309
348
|
|
|
310
349
|
Follows the PyAV cookbook section on generating video from numpy arrays:
|
|
311
350
|
https://pyav.basswood-io.com/docs/develop/cookbook/numpy.html#generating-video
|
|
312
|
-
|
|
313
|
-
Parameters
|
|
314
|
-
----------
|
|
315
|
-
data : numpy.ndarray or list of filenames
|
|
316
|
-
A 3D numpy array of pixel values, with the time axis as the first axis.
|
|
317
351
|
"""
|
|
318
352
|
if not data.ndim == 3:
|
|
319
353
|
raise ValueError('Input data must be a 3D numpy array.')
|
|
@@ -351,7 +385,11 @@ def save_video(data, filename, overwrite=False, dim_order='yx', time_axis=0,
|
|
|
351
385
|
container.close()
|
|
352
386
|
|
|
353
387
|
|
|
354
|
-
def show(data,
|
|
388
|
+
def show(data,
|
|
389
|
+
dim_order='yx',
|
|
390
|
+
mode='PIL',
|
|
391
|
+
convert_to_8bit=True,
|
|
392
|
+
**kwargs):
|
|
355
393
|
"""
|
|
356
394
|
Display a numpy array of pixel values as an image. Supported types:
|
|
357
395
|
1-channel (grayscale) : data.shape must be (y, x)
|
|
@@ -359,7 +397,7 @@ def show(data, dim_order='yx', mode='PIL', **kwargs):
|
|
|
359
397
|
4-channel (RGBA) : data.shape must be (y, x, 4)
|
|
360
398
|
|
|
361
399
|
If `dim_order` is set to 'xy' (instead of the default 'yx'), then
|
|
362
|
-
swap the y and x above.
|
|
400
|
+
swap the y and x above.
|
|
363
401
|
|
|
364
402
|
Images will be shown using either `PIL.Image.fromarray(data).show()`
|
|
365
403
|
or `matplotlib.pyplot.imshow(data)` depending on 'mode'. Uses PIL by
|
|
@@ -374,18 +412,22 @@ def show(data, dim_order='yx', mode='PIL', **kwargs):
|
|
|
374
412
|
if os.path.exists(data):
|
|
375
413
|
data = load(data)
|
|
376
414
|
|
|
377
|
-
if not
|
|
378
|
-
m = ('
|
|
379
|
-
|
|
380
|
-
|
|
415
|
+
if (not data.ndim == 2) and not (data.ndim == 3 and find_channel_axis(data) is not None):
|
|
416
|
+
m = ('Data must have shape (y, x) for grayscale, '
|
|
417
|
+
'(y, x, 3) for RGB, or (y, x, 4) for RGBA but had '
|
|
418
|
+
f'shape {data.shape}')
|
|
381
419
|
if 'xy' in dim_order:
|
|
382
420
|
m = m.replace('y, x', 'x, y')
|
|
383
421
|
raise ValueError(m)
|
|
384
422
|
|
|
385
423
|
if 'xy' in dim_order:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
424
|
+
data = data.T
|
|
425
|
+
channel_axis = find_channel_axis(data, expected_channel_axis=-1)
|
|
426
|
+
if channel_axis is not None and channel_axis != -1:
|
|
427
|
+
data = np.moveaxis(data, find_channel_axis(data), -1)
|
|
428
|
+
|
|
429
|
+
if convert_to_8bit and data.dtype != np.uint8:
|
|
430
|
+
data = operations.to_8bit(data)
|
|
389
431
|
|
|
390
432
|
colorbar = False
|
|
391
433
|
if 'colorbar' in kwargs:
|
|
@@ -407,16 +449,45 @@ def show(data, dim_order='yx', mode='PIL', **kwargs):
|
|
|
407
449
|
imshow = show # Function name alias
|
|
408
450
|
|
|
409
451
|
|
|
410
|
-
def
|
|
452
|
+
def find_channel_axis(data, expected_channel_axis=[0, -1]):
|
|
411
453
|
"""
|
|
412
|
-
|
|
413
|
-
that
|
|
414
|
-
|
|
415
|
-
data.shape == (i, j, 3) -> it's RGB, return True
|
|
416
|
-
data.shape == (i, j, 4) -> it's RGBA, return True
|
|
417
|
-
data.shape == anything else -> return False
|
|
454
|
+
If the given numpy array has a shape suggesting that it has a
|
|
455
|
+
channel (color) axis (that is, any axis with length 2 (2-color),
|
|
456
|
+
3 (RGB), or 4 (RGBA)), return the index of that axis.
|
|
418
457
|
|
|
458
|
+
Parameters
|
|
459
|
+
----------
|
|
460
|
+
data : numpy.ndarray
|
|
461
|
+
The numpy array to check for a channel axis.
|
|
462
|
+
|
|
463
|
+
expected_channel_axis : int or list of int, default [0, -1]
|
|
464
|
+
If None, any axis having length 2, 3, or 4 will be considered
|
|
465
|
+
a channel axis.
|
|
466
|
+
If an int, only that axis index will be checked.
|
|
467
|
+
If a list of ints, all axes with those indices will be checked.
|
|
468
|
+
The default value of [0, -1] checks the first and last axes, which is
|
|
469
|
+
almost always where a channel axis will be found.
|
|
470
|
+
|
|
471
|
+
Returns
|
|
472
|
+
-------
|
|
473
|
+
int or None
|
|
474
|
+
The index of the channel axis, or None if no channel axis was found.
|
|
475
|
+
|
|
476
|
+
If expected_channel_axis is given, the returned value will be one of
|
|
477
|
+
the expected_channel_axis values, or None if no channel axis was found.
|
|
478
|
+
|
|
479
|
+
If expected_channel_axis is None, the returned value will be between
|
|
480
|
+
0 and data.ndim - 1, inclusive, or None if no channel axis was found.
|
|
481
|
+
|
|
482
|
+
Note that returning 0 means the channel axis was found and is the first
|
|
483
|
+
axis, so be careful not to do a test like `if find_channel_axis(data):`
|
|
484
|
+
because 0 will evaluate to False even though the data has a channel axis.
|
|
419
485
|
"""
|
|
420
|
-
if
|
|
421
|
-
|
|
422
|
-
|
|
486
|
+
if isinstance(expected_channel_axis, int):
|
|
487
|
+
expected_channel_axis = [expected_channel_axis]
|
|
488
|
+
if expected_channel_axis is None:
|
|
489
|
+
expected_channel_axis = range(data.ndim)
|
|
490
|
+
for axis in expected_channel_axis:
|
|
491
|
+
if data.shape[axis] in [2, 3, 4]:
|
|
492
|
+
return axis
|
|
493
|
+
return None
|
|
@@ -11,7 +11,7 @@ Function list:
|
|
|
11
11
|
- overlay_two_images: Overlay two images with the second one offset.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
from typing import Iterable, Literal, Union, Optional
|
|
14
|
+
from typing import Iterable, Literal, Union, Optional, Tuple, List
|
|
15
15
|
import gc
|
|
16
16
|
|
|
17
17
|
import numpy as np
|
|
@@ -136,8 +136,8 @@ def cast(image: np.ndarray,
|
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
def adjust_brightness(image: np.ndarray,
|
|
139
|
-
starting_range:
|
|
140
|
-
target_range:
|
|
139
|
+
starting_range: Tuple[float, float],
|
|
140
|
+
target_range: Tuple[float, float],
|
|
141
141
|
output_dtype: Optional[Union[str, np.dtype]] = None,
|
|
142
142
|
clip: bool = False) -> np.ndarray:
|
|
143
143
|
"""
|
|
@@ -436,8 +436,8 @@ def paste(image: np.ndarray,
|
|
|
436
436
|
target[tuple(target_range)] = image[tuple(source_range)]
|
|
437
437
|
|
|
438
438
|
|
|
439
|
-
def overlay(ims:
|
|
440
|
-
offsets:
|
|
439
|
+
def overlay(ims: List[np.ndarray],
|
|
440
|
+
offsets: List[Tuple[float]],
|
|
441
441
|
later_images_on_top=True,
|
|
442
442
|
expand_bounds=False,
|
|
443
443
|
fill_value=0):
|
|
@@ -68,10 +68,17 @@ def transpose_metadata(metadata: dict or OrderedDict,
|
|
|
68
68
|
Designed to work with OrderedDicts that contain nrrd files'
|
|
69
69
|
metadata, but may be useful for metadata from other formats.
|
|
70
70
|
"""
|
|
71
|
+
if metadata is None:
|
|
72
|
+
return None
|
|
71
73
|
if not inplace:
|
|
72
74
|
metadata = metadata.copy()
|
|
73
|
-
for key in metadata:
|
|
74
|
-
if
|
|
75
|
-
|
|
75
|
+
for key, value in metadata.items():
|
|
76
|
+
if isinstance(value, str) or not hasattr(value, '__iter__'):
|
|
77
|
+
continue
|
|
78
|
+
if isinstance(value, np.ndarray):
|
|
79
|
+
value = np.flip(value)
|
|
80
|
+
else:
|
|
81
|
+
value = value[::-1]
|
|
82
|
+
metadata[key] = value
|
|
76
83
|
if not inplace:
|
|
77
84
|
return metadata
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: numpyimage
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Load, save, and manipulate image files as numpy arrays
|
|
5
|
+
Home-page: https://github.com/jasper-tms/npimage
|
|
6
|
+
Author: Jasper Phelps
|
|
7
|
+
Author-email: jasper.s.phelps@gmail.com
|
|
8
|
+
License: GNU GPL v3
|
|
9
|
+
Description: # npimage
|
|
10
|
+
Need to load pixel values from image files as numpy arrays, and hate having to remember whether you should use PIL, tifffile, matplotlib, or something else? Hate having to deal with the fact that those libraries all use different function names and syntaxes? Wish you could just provide a filename and get back a numpy array? This library's `core.py` does that, with `array = load(filename)`, `save(array, filename)`, and `show(array)` functions that let you easily handle a number of common image file formats without having to remember library-specific syntax. (Another choice of library to consider for accomplishing similar goals is [imageio](https://pypi.org/project/imageio/), which also supports loading videos through the FFmpeg wrapper library [pyav](https://pypi.org/project/av/).)
|
|
11
|
+
|
|
12
|
+
Want to draw simple shapes like lines, triangles, and circles into 3D numpy arrays? Frustrated that the python libraries you can find online like `opencv` and `skimage.draw` work on 2D arrays but not 3D? I wrote some functions in `graphics.py` that do the trick in 3D. (If you know of another library that can do this, please let me know!)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Documentation
|
|
16
|
+
- `core.py`: load, save, or show images.
|
|
17
|
+
- `graphics.py`: draw points, lines, triangles, circles, or spheres into 2D or 3D numpy arrays representing image volumes.
|
|
18
|
+
- `nrrd_utils.py`: compress or read metadata from `.nrrd` files.
|
|
19
|
+
- `operations.py`: perform operations on images.
|
|
20
|
+
|
|
21
|
+
For now, check each function's docstring for more. A jupyter notebook demonstrating this package's functions will come later.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Installation
|
|
25
|
+
|
|
26
|
+
As is always the case in python, consider making a virtual environment (using your preference of conda, virtualenv, or virtualenvwrapper) before installing.
|
|
27
|
+
|
|
28
|
+
**Option 1:** `pip install` from PyPI:
|
|
29
|
+
|
|
30
|
+
pip install numpyimage
|
|
31
|
+
|
|
32
|
+
(Unfortunately the name `npimage` was already taken on PyPI, so `pip install npimage` will get you a different package.)
|
|
33
|
+
|
|
34
|
+
**Option 2:** `pip install` directly from GitHub:
|
|
35
|
+
|
|
36
|
+
pip install git+https://github.com/jasper-tms/npimage.git
|
|
37
|
+
|
|
38
|
+
**Option 3:** First `git clone` this repo and then `pip install` it from your clone:
|
|
39
|
+
|
|
40
|
+
cd ~/repos # Or wherever on your computer you want to download this code to
|
|
41
|
+
git clone https://github.com/jasper-tms/npimage.git
|
|
42
|
+
cd npimage
|
|
43
|
+
pip install .
|
|
44
|
+
|
|
45
|
+
**After installing,** you can import this package in python using `import npimage` (not `import numpyimage`!)
|
|
46
|
+
|
|
47
|
+
Platform: UNKNOWN
|
|
48
|
+
Classifier: Programming Language :: Python :: 3
|
|
49
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
50
|
+
Classifier: Operating System :: OS Independent
|
|
51
|
+
Requires-Python: >=3.6
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
@@ -9,7 +9,7 @@ with open("requirements.txt", "r") as f:
|
|
|
9
9
|
|
|
10
10
|
setuptools.setup(
|
|
11
11
|
name="numpyimage",
|
|
12
|
-
version="
|
|
12
|
+
version="2.0.0",
|
|
13
13
|
author="Jasper Phelps",
|
|
14
14
|
author_email="jasper.s.phelps@gmail.com",
|
|
15
15
|
description="Load, save, and manipulate image files as numpy arrays",
|
numpyimage-1.3.0/PKG-INFO
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: numpyimage
|
|
3
|
-
Version: 1.3.0
|
|
4
|
-
Summary: Load, save, and manipulate image files as numpy arrays
|
|
5
|
-
Home-page: https://github.com/jasper-tms/npimage
|
|
6
|
-
Author: Jasper Phelps
|
|
7
|
-
Author-email: jasper.s.phelps@gmail.com
|
|
8
|
-
License: GNU GPL v3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.6
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: numpy
|
|
16
|
-
Requires-Dist: pillow
|
|
17
|
-
Requires-Dist: tifffile
|
|
18
|
-
Requires-Dist: pynrrd
|
|
19
|
-
Requires-Dist: matplotlib
|
|
20
|
-
Requires-Dist: opencv-python-headless
|
|
21
|
-
|
|
22
|
-
# npimage
|
|
23
|
-
Need to load pixel values from image files as numpy arrays, and hate having to remember whether you should use PIL, tifffile, matplotlib, or something else? Hate having to deal with the fact that those libraries all use different function names and syntaxes? Wish you could just provide a filename and get back a numpy array? This library's `core.py` does that, with `array = load(filename)`, `save(array, filename)`, and `show(array)` functions that let you easily handle a number of common image file formats without having to remember library-specific syntax. (Another choice of library to consider for accomplishing similar goals is [imageio](https://pypi.org/project/imageio/), which also supports loading videos through the FFmpeg wrapper library [pyav](https://pypi.org/project/av/).)
|
|
24
|
-
|
|
25
|
-
Want to draw simple shapes like lines, triangles, and circles into 3D numpy arrays? Frustrated that the python libraries you can find online like `opencv` and `skimage.draw` work on 2D arrays but not 3D? I wrote some functions in `graphics.py` that do the trick in 3D. (If you know of another library that can do this, please let me know!)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
### Documentation
|
|
29
|
-
- `core.py`: load, save, or show images.
|
|
30
|
-
- `graphics.py`: draw points, lines, triangles, circles, or spheres into 2D or 3D numpy arrays representing image volumes.
|
|
31
|
-
- `nrrd_utils.py`: compress or read metadata from `.nrrd` files.
|
|
32
|
-
- `operations.py`: perform operations on images.
|
|
33
|
-
|
|
34
|
-
For now, check each function's docstring for more. A jupyter notebook demonstrating this package's functions will come later.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
### Installation
|
|
38
|
-
|
|
39
|
-
As is always the case in python, consider making a virtual environment (using your preference of conda, virtualenv, or virtualenvwrapper) before installing.
|
|
40
|
-
|
|
41
|
-
**Option 1:** `pip install` from PyPI:
|
|
42
|
-
|
|
43
|
-
pip install numpyimage
|
|
44
|
-
|
|
45
|
-
(Unfortunately the name `npimage` was already taken on PyPI, so `pip install npimage` will get you a different package.)
|
|
46
|
-
|
|
47
|
-
**Option 2:** `pip install` directly from GitHub:
|
|
48
|
-
|
|
49
|
-
pip install git+https://github.com/jasper-tms/npimage.git
|
|
50
|
-
|
|
51
|
-
**Option 3:** First `git clone` this repo and then `pip install` it from your clone:
|
|
52
|
-
|
|
53
|
-
cd ~/repos # Or wherever on your computer you want to download this code to
|
|
54
|
-
git clone https://github.com/jasper-tms/npimage.git
|
|
55
|
-
cd npimage
|
|
56
|
-
pip install .
|
|
57
|
-
|
|
58
|
-
**After installing,** you can import this package in python using `import npimage` (not `import numpyimage`!)
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: numpyimage
|
|
3
|
-
Version: 1.3.0
|
|
4
|
-
Summary: Load, save, and manipulate image files as numpy arrays
|
|
5
|
-
Home-page: https://github.com/jasper-tms/npimage
|
|
6
|
-
Author: Jasper Phelps
|
|
7
|
-
Author-email: jasper.s.phelps@gmail.com
|
|
8
|
-
License: GNU GPL v3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.6
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: numpy
|
|
16
|
-
Requires-Dist: pillow
|
|
17
|
-
Requires-Dist: tifffile
|
|
18
|
-
Requires-Dist: pynrrd
|
|
19
|
-
Requires-Dist: matplotlib
|
|
20
|
-
Requires-Dist: opencv-python-headless
|
|
21
|
-
|
|
22
|
-
# npimage
|
|
23
|
-
Need to load pixel values from image files as numpy arrays, and hate having to remember whether you should use PIL, tifffile, matplotlib, or something else? Hate having to deal with the fact that those libraries all use different function names and syntaxes? Wish you could just provide a filename and get back a numpy array? This library's `core.py` does that, with `array = load(filename)`, `save(array, filename)`, and `show(array)` functions that let you easily handle a number of common image file formats without having to remember library-specific syntax. (Another choice of library to consider for accomplishing similar goals is [imageio](https://pypi.org/project/imageio/), which also supports loading videos through the FFmpeg wrapper library [pyav](https://pypi.org/project/av/).)
|
|
24
|
-
|
|
25
|
-
Want to draw simple shapes like lines, triangles, and circles into 3D numpy arrays? Frustrated that the python libraries you can find online like `opencv` and `skimage.draw` work on 2D arrays but not 3D? I wrote some functions in `graphics.py` that do the trick in 3D. (If you know of another library that can do this, please let me know!)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
### Documentation
|
|
29
|
-
- `core.py`: load, save, or show images.
|
|
30
|
-
- `graphics.py`: draw points, lines, triangles, circles, or spheres into 2D or 3D numpy arrays representing image volumes.
|
|
31
|
-
- `nrrd_utils.py`: compress or read metadata from `.nrrd` files.
|
|
32
|
-
- `operations.py`: perform operations on images.
|
|
33
|
-
|
|
34
|
-
For now, check each function's docstring for more. A jupyter notebook demonstrating this package's functions will come later.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
### Installation
|
|
38
|
-
|
|
39
|
-
As is always the case in python, consider making a virtual environment (using your preference of conda, virtualenv, or virtualenvwrapper) before installing.
|
|
40
|
-
|
|
41
|
-
**Option 1:** `pip install` from PyPI:
|
|
42
|
-
|
|
43
|
-
pip install numpyimage
|
|
44
|
-
|
|
45
|
-
(Unfortunately the name `npimage` was already taken on PyPI, so `pip install npimage` will get you a different package.)
|
|
46
|
-
|
|
47
|
-
**Option 2:** `pip install` directly from GitHub:
|
|
48
|
-
|
|
49
|
-
pip install git+https://github.com/jasper-tms/npimage.git
|
|
50
|
-
|
|
51
|
-
**Option 3:** First `git clone` this repo and then `pip install` it from your clone:
|
|
52
|
-
|
|
53
|
-
cd ~/repos # Or wherever on your computer you want to download this code to
|
|
54
|
-
git clone https://github.com/jasper-tms/npimage.git
|
|
55
|
-
cd npimage
|
|
56
|
-
pip install .
|
|
57
|
-
|
|
58
|
-
**After installing,** you can import this package in python using `import npimage` (not `import numpyimage`!)
|
numpyimage-1.3.0/tests/tests.py
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import fire
|
|
5
|
-
|
|
6
|
-
import npimage
|
|
7
|
-
import npimage.operations
|
|
8
|
-
|
|
9
|
-
test_im = np.zeros((8, 8), dtype=np.uint8)
|
|
10
|
-
test_im[0:1, 0:2] = 255
|
|
11
|
-
test_im[1:3, 2:4] = 255
|
|
12
|
-
test_im[3:7, 3:7] = 255
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def mplshow(*args):
|
|
16
|
-
npimage.show(*args, mode='matplotlib')
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def test_offset():
|
|
20
|
-
mplshow(test_im)
|
|
21
|
-
mplshow(npimage.operations.offset(test_im, (0.5, 0)))
|
|
22
|
-
mplshow(npimage.operations.offset(test_im, (0, 0.5)))
|
|
23
|
-
mplshow(npimage.operations.offset(test_im, (0.5, 0.5)))
|
|
24
|
-
mplshow(npimage.operations.offset(test_im, (1, 1)))
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def test_paste():
|
|
28
|
-
offsets = [('++', [100, 50]),
|
|
29
|
-
('+-', [100, -50]),
|
|
30
|
-
('-+', [-100, 50]),
|
|
31
|
-
('--', [-100, -50])]
|
|
32
|
-
for offset in offsets:
|
|
33
|
-
im = npimage.load('firefox-logo.png', dim_order='xy')
|
|
34
|
-
npimage.operations.paste(im, im, offset[1])
|
|
35
|
-
npimage.save(im, 'firefox-logo_paste' + offset[0] + '.png', dim_order='xy')
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if __name__ == '__main__':
|
|
39
|
-
fire.Fire()
|
|
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
|