cellects 0.1.0.dev1__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.
- cellects/__init__.py +0 -0
- cellects/__main__.py +49 -0
- cellects/config/__init__.py +0 -0
- cellects/config/all_vars_dict.py +154 -0
- cellects/core/__init__.py +0 -0
- cellects/core/cellects_paths.py +30 -0
- cellects/core/cellects_threads.py +1464 -0
- cellects/core/motion_analysis.py +1931 -0
- cellects/core/one_image_analysis.py +1065 -0
- cellects/core/one_video_per_blob.py +679 -0
- cellects/core/program_organizer.py +1347 -0
- cellects/core/script_based_run.py +154 -0
- cellects/gui/__init__.py +0 -0
- cellects/gui/advanced_parameters.py +1258 -0
- cellects/gui/cellects.py +189 -0
- cellects/gui/custom_widgets.py +789 -0
- cellects/gui/first_window.py +449 -0
- cellects/gui/if_several_folders_window.py +239 -0
- cellects/gui/image_analysis_window.py +1909 -0
- cellects/gui/required_output.py +232 -0
- cellects/gui/video_analysis_window.py +656 -0
- cellects/icons/__init__.py +0 -0
- cellects/icons/cellects_icon.icns +0 -0
- cellects/icons/cellects_icon.ico +0 -0
- cellects/image_analysis/__init__.py +0 -0
- cellects/image_analysis/cell_leaving_detection.py +54 -0
- cellects/image_analysis/cluster_flux_study.py +102 -0
- cellects/image_analysis/extract_exif.py +61 -0
- cellects/image_analysis/fractal_analysis.py +184 -0
- cellects/image_analysis/fractal_functions.py +108 -0
- cellects/image_analysis/image_segmentation.py +272 -0
- cellects/image_analysis/morphological_operations.py +867 -0
- cellects/image_analysis/network_functions.py +1244 -0
- cellects/image_analysis/one_image_analysis_threads.py +289 -0
- cellects/image_analysis/progressively_add_distant_shapes.py +246 -0
- cellects/image_analysis/shape_descriptors.py +981 -0
- cellects/utils/__init__.py +0 -0
- cellects/utils/formulas.py +881 -0
- cellects/utils/load_display_save.py +1016 -0
- cellects/utils/utilitarian.py +516 -0
- cellects-0.1.0.dev1.dist-info/LICENSE.odt +0 -0
- cellects-0.1.0.dev1.dist-info/METADATA +131 -0
- cellects-0.1.0.dev1.dist-info/RECORD +46 -0
- cellects-0.1.0.dev1.dist-info/WHEEL +5 -0
- cellects-0.1.0.dev1.dist-info/entry_points.txt +2 -0
- cellects-0.1.0.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
This script contains functions and classes to load, display and save various files
|
|
4
|
+
For example:
|
|
5
|
+
- PickleRick: to write and read files without conflicts
|
|
6
|
+
- See: Display an image using opencv
|
|
7
|
+
- write_video: Write a video on hard drive
|
|
8
|
+
"""
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
import pickle
|
|
12
|
+
import time
|
|
13
|
+
import h5py
|
|
14
|
+
from timeit import default_timer
|
|
15
|
+
import numpy as np
|
|
16
|
+
import cv2
|
|
17
|
+
from numpy import any, unique, load, zeros, arange, empty, save, int16, isin, vstack, nonzero, concatenate, linspace
|
|
18
|
+
from cv2 import VideoWriter, imshow, waitKey, destroyAllWindows, resize, VideoCapture, CAP_PROP_FRAME_COUNT, CAP_PROP_FRAME_HEIGHT, CAP_PROP_FRAME_WIDTH
|
|
19
|
+
from matplotlib import pyplot as plt
|
|
20
|
+
from cellects.core.one_image_analysis import OneImageAnalysis
|
|
21
|
+
from cellects.image_analysis.image_segmentation import combine_color_spaces, get_color_spaces, generate_color_space_combination
|
|
22
|
+
from cellects.utils.formulas import bracket_to_uint8_image_contrast, sum_of_abs_differences
|
|
23
|
+
from cellects.utils.utilitarian import translate_dict
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PickleRick:
|
|
27
|
+
"""
|
|
28
|
+
A class to handle safe file reading and writing operations using pickle.
|
|
29
|
+
|
|
30
|
+
This class ensures that files are not being accessed concurrently by
|
|
31
|
+
creating a lock file (PickleRickX.pkl) to signal that the file is open.
|
|
32
|
+
It includes methods to check for the lock file, write data safely,
|
|
33
|
+
and read data safely.
|
|
34
|
+
|
|
35
|
+
Attributes
|
|
36
|
+
----------
|
|
37
|
+
wait_for_pickle_rick : bool
|
|
38
|
+
Flag indicating if the lock file is present.
|
|
39
|
+
counter : int
|
|
40
|
+
Counter to track the number of operations performed.
|
|
41
|
+
pickle_rick_number : str
|
|
42
|
+
Unique identifier for the lock file.
|
|
43
|
+
first_check_time : float
|
|
44
|
+
Timestamp of the first check for the lock file.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
def __init__(self, pickle_rick_number=""):
|
|
48
|
+
self.wait_for_pickle_rick: bool = False
|
|
49
|
+
self.counter = 0
|
|
50
|
+
self.pickle_rick_number = pickle_rick_number
|
|
51
|
+
self.first_check_time = default_timer()
|
|
52
|
+
|
|
53
|
+
def check_that_file_is_not_open(self):
|
|
54
|
+
"""
|
|
55
|
+
Check if a specific pickle file exists and handle it accordingly.
|
|
56
|
+
|
|
57
|
+
This function checks whether a file named `PickleRick{self.pickle_rick_number}.pkl`
|
|
58
|
+
exists. If the file has not been modified for more than 2 seconds, it is removed.
|
|
59
|
+
The function then updates an attribute to indicate whether the file exists.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
self : PickleRickObject
|
|
64
|
+
The instance of the class containing this method.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
None
|
|
69
|
+
This function does not return any value.
|
|
70
|
+
It updates the `self.wait_for_pickle_rick` attribute.
|
|
71
|
+
|
|
72
|
+
Notes
|
|
73
|
+
-----
|
|
74
|
+
This function removes the pickle file if it has not been modified for more than 2 seconds.
|
|
75
|
+
The `self.wait_for_pickle_rick` attribute is updated based on the existence of the file.
|
|
76
|
+
|
|
77
|
+
Examples
|
|
78
|
+
--------
|
|
79
|
+
>>> pickle_rick_instance.check_that_file_is_not_open()
|
|
80
|
+
"""
|
|
81
|
+
if os.path.isfile(f"PickleRick{self.pickle_rick_number}.pkl"):
|
|
82
|
+
if default_timer() - self.first_check_time > 2:
|
|
83
|
+
os.remove(f"PickleRick{self.pickle_rick_number}.pkl")
|
|
84
|
+
# logging.error((f"Cannot read/write, Trying again... tip: unlock by deleting the file named PickleRick{self.pickle_rick_number}.pkl"))
|
|
85
|
+
self.wait_for_pickle_rick = os.path.isfile(f"PickleRick{self.pickle_rick_number}.pkl")
|
|
86
|
+
|
|
87
|
+
def write_pickle_rick(self):
|
|
88
|
+
"""
|
|
89
|
+
Write pickle data to a file for Pickle Rick.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
self : object
|
|
94
|
+
The instance of the class that this method belongs to.
|
|
95
|
+
This typically contains attributes and methods relevant to managing
|
|
96
|
+
pickle operations for Pickle Rick.
|
|
97
|
+
|
|
98
|
+
Raises
|
|
99
|
+
------
|
|
100
|
+
Exception
|
|
101
|
+
General exception raised if there is any issue with writing the file.
|
|
102
|
+
The error details are logged.
|
|
103
|
+
|
|
104
|
+
Notes
|
|
105
|
+
-----
|
|
106
|
+
This function creates a file named `PickleRick{self.pickle_rick_number}.pkl`
|
|
107
|
+
with a dictionary indicating readiness for Pickle Rick.
|
|
108
|
+
|
|
109
|
+
Examples
|
|
110
|
+
--------
|
|
111
|
+
>>> obj = PickleRick() # Assuming `YourClassInstance` is the class containing this method
|
|
112
|
+
>>> obj.pickle_rick_number = 1 # Set an example value for the attribute
|
|
113
|
+
>>> obj.write_pickle_rick() # Call the method to create and write to file
|
|
114
|
+
"""
|
|
115
|
+
try:
|
|
116
|
+
with open(f"PickleRick{self.pickle_rick_number}.pkl", 'wb') as file_to_write:
|
|
117
|
+
pickle.dump({'wait_for_pickle_rick': True}, file_to_write)
|
|
118
|
+
except Exception as exc:
|
|
119
|
+
logging.error(f"Don't know how but Pickle Rick failed... Error is: {exc}")
|
|
120
|
+
|
|
121
|
+
def delete_pickle_rick(self):
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
Delete a specific Pickle Rick file.
|
|
125
|
+
|
|
126
|
+
Deletes the pickle file associated with the current instance's
|
|
127
|
+
`pickle_rick_number`.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
None
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
None
|
|
136
|
+
|
|
137
|
+
Raises
|
|
138
|
+
------
|
|
139
|
+
FileNotFoundError
|
|
140
|
+
If the file with name `PickleRick{self.pickle_rick_number}.pkl` does not exist.
|
|
141
|
+
|
|
142
|
+
Notes
|
|
143
|
+
-----
|
|
144
|
+
This function attempts to delete the specified pickle file.
|
|
145
|
+
If the file does not exist, a `FileNotFoundError` will be raised.
|
|
146
|
+
|
|
147
|
+
Examples
|
|
148
|
+
--------
|
|
149
|
+
>>> obj = PickleRick()
|
|
150
|
+
>>> obj.pickle_rick_number = 1 # Set an example value for the attribute
|
|
151
|
+
>>> obj.write_pickle_rick()
|
|
152
|
+
>>> delete_pickle_rick()
|
|
153
|
+
>>> os.path.isfile("PickleRick1.pkl")
|
|
154
|
+
False
|
|
155
|
+
"""
|
|
156
|
+
if os.path.isfile(f"PickleRick{self.pickle_rick_number}.pkl"):
|
|
157
|
+
os.remove(f"PickleRick{self.pickle_rick_number}.pkl")
|
|
158
|
+
|
|
159
|
+
def write_file(self, file_content, file_name):
|
|
160
|
+
"""
|
|
161
|
+
Write content to a file with error handling and retry logic.
|
|
162
|
+
|
|
163
|
+
This function attempts to write the provided content into a file.
|
|
164
|
+
If it fails, it retries up to 100 times with some additional checks
|
|
165
|
+
and delays. Note that the content is serialized using pickle.
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
file_content : Any
|
|
170
|
+
The data to be written into the file. This will be pickled.
|
|
171
|
+
file_name : str
|
|
172
|
+
The name of the file where data should be written.
|
|
173
|
+
|
|
174
|
+
Other Parameters
|
|
175
|
+
----------------
|
|
176
|
+
None
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
None
|
|
181
|
+
|
|
182
|
+
Raises
|
|
183
|
+
------
|
|
184
|
+
Exception
|
|
185
|
+
If the file cannot be written after 100 attempts, an error is logged.
|
|
186
|
+
|
|
187
|
+
Notes
|
|
188
|
+
-----
|
|
189
|
+
This function uses pickle to serialize the data, which can introduce security risks
|
|
190
|
+
if untrusted content is being written. It performs some internal state checks,
|
|
191
|
+
such as verifying that the target file isn't open and whether it should delete
|
|
192
|
+
some internal state, represented by `delete_pickle_rick`.
|
|
193
|
+
|
|
194
|
+
The function implements a retry mechanism with a backoff strategy that can include
|
|
195
|
+
random delays, though the example code does not specify these details explicitly.
|
|
196
|
+
|
|
197
|
+
Examples
|
|
198
|
+
--------
|
|
199
|
+
>>> result = PickleRick().write_file({'key': 'value'}, 'test.pkl')
|
|
200
|
+
Success to write file
|
|
201
|
+
"""
|
|
202
|
+
self.counter += 1
|
|
203
|
+
if self.counter < 100:
|
|
204
|
+
if self.counter > 95:
|
|
205
|
+
self.delete_pickle_rick()
|
|
206
|
+
# time.sleep(np.random.choice(np.arange(1, os.cpu_count(), 0.5)))
|
|
207
|
+
self.check_that_file_is_not_open()
|
|
208
|
+
if self.wait_for_pickle_rick:
|
|
209
|
+
time.sleep(2)
|
|
210
|
+
self.write_file(file_content, file_name)
|
|
211
|
+
else:
|
|
212
|
+
self.write_pickle_rick()
|
|
213
|
+
try:
|
|
214
|
+
with open(file_name, 'wb') as file_to_write:
|
|
215
|
+
pickle.dump(file_content, file_to_write, protocol=0)
|
|
216
|
+
self.delete_pickle_rick()
|
|
217
|
+
logging.info(f"Success to write file")
|
|
218
|
+
except Exception as exc:
|
|
219
|
+
logging.error(f"The Pickle error on the file {file_name} is: {exc}")
|
|
220
|
+
self.delete_pickle_rick()
|
|
221
|
+
self.write_file(file_content, file_name)
|
|
222
|
+
else:
|
|
223
|
+
logging.error(f"Failed to write {file_name}")
|
|
224
|
+
|
|
225
|
+
def read_file(self, file_name):
|
|
226
|
+
"""
|
|
227
|
+
Reads the contents of a file using pickle and returns it.
|
|
228
|
+
|
|
229
|
+
Parameters
|
|
230
|
+
----------
|
|
231
|
+
file_name : str
|
|
232
|
+
The name of the file to be read.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
Union[Any, None]
|
|
237
|
+
The content of the file if successfully read; otherwise, `None`.
|
|
238
|
+
|
|
239
|
+
Raises
|
|
240
|
+
------
|
|
241
|
+
Exception
|
|
242
|
+
If there is an error reading the file.
|
|
243
|
+
|
|
244
|
+
Notes
|
|
245
|
+
-----
|
|
246
|
+
This function attempts to read a file multiple times if it fails.
|
|
247
|
+
If the number of attempts exceeds 1000, it logs an error and returns `None`.
|
|
248
|
+
|
|
249
|
+
Examples
|
|
250
|
+
--------
|
|
251
|
+
>>> PickleRick().read_file("example.pkl")
|
|
252
|
+
Some content
|
|
253
|
+
|
|
254
|
+
>>> read_file("non_existent_file.pkl")
|
|
255
|
+
None
|
|
256
|
+
"""
|
|
257
|
+
self.counter += 1
|
|
258
|
+
if self.counter < 1000:
|
|
259
|
+
if self.counter > 950:
|
|
260
|
+
self.delete_pickle_rick()
|
|
261
|
+
self.check_that_file_is_not_open()
|
|
262
|
+
if self.wait_for_pickle_rick:
|
|
263
|
+
time.sleep(2)
|
|
264
|
+
self.read_file(file_name)
|
|
265
|
+
else:
|
|
266
|
+
self.write_pickle_rick()
|
|
267
|
+
try:
|
|
268
|
+
with open(file_name, 'rb') as fileopen:
|
|
269
|
+
file_content = pickle.load(fileopen)
|
|
270
|
+
except Exception as exc:
|
|
271
|
+
logging.error(f"The Pickle error on the file {file_name} is: {exc}")
|
|
272
|
+
file_content = None
|
|
273
|
+
self.delete_pickle_rick()
|
|
274
|
+
if file_content is None:
|
|
275
|
+
self.read_file(file_name)
|
|
276
|
+
else:
|
|
277
|
+
logging.info(f"Success to read file")
|
|
278
|
+
return file_content
|
|
279
|
+
else:
|
|
280
|
+
logging.error(f"Failed to read {file_name}")
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def show(img, interactive=True, cmap=None):
|
|
284
|
+
"""
|
|
285
|
+
Display an image using Matplotlib with optional interactivity and colormap.
|
|
286
|
+
|
|
287
|
+
Parameters
|
|
288
|
+
----------
|
|
289
|
+
img : ndarray
|
|
290
|
+
The image data to be displayed.
|
|
291
|
+
interactive : bool, optional
|
|
292
|
+
If ``True``, turn on interactive mode. Default is ``True``.
|
|
293
|
+
cmap : str or Colormap, optional
|
|
294
|
+
The colormap to be used. If ``None``, the default colormap will
|
|
295
|
+
be used.
|
|
296
|
+
|
|
297
|
+
Other Parameters
|
|
298
|
+
----------------
|
|
299
|
+
interactive : bool, optional
|
|
300
|
+
If ``True``, turn on interactive mode. Default is ``True``.
|
|
301
|
+
cmap : str or Colormap, optional
|
|
302
|
+
The colormap to be used. If ``None``, the default colormap will
|
|
303
|
+
be used.
|
|
304
|
+
|
|
305
|
+
Returns
|
|
306
|
+
-------
|
|
307
|
+
fig : Figure
|
|
308
|
+
The Matplotlib figure object containing the displayed image.
|
|
309
|
+
ax : AxesSubplot
|
|
310
|
+
The axes on which the image is plotted.
|
|
311
|
+
|
|
312
|
+
Raises
|
|
313
|
+
------
|
|
314
|
+
ValueError
|
|
315
|
+
If `cmap` is not a recognized colormap name or object.
|
|
316
|
+
|
|
317
|
+
Notes
|
|
318
|
+
-----
|
|
319
|
+
If interactive mode is enabled, the user can manipulate the figure
|
|
320
|
+
window interactively.
|
|
321
|
+
|
|
322
|
+
Examples
|
|
323
|
+
--------
|
|
324
|
+
>>> img = np.random.rand(100, 100)
|
|
325
|
+
>>> fig, ax = show(img)
|
|
326
|
+
>>> print(fig) # doctest: +SKIP
|
|
327
|
+
<Figure size ... with ... Axes>
|
|
328
|
+
|
|
329
|
+
>>> fig, ax = show(img, interactive=False)
|
|
330
|
+
>>> print(fig) # doctest: +SKIP
|
|
331
|
+
<Figure size ... with ... Axes>
|
|
332
|
+
|
|
333
|
+
>>> fig, ax = show(img, cmap='gray')
|
|
334
|
+
>>> print(fig) # doctest: +SKIP
|
|
335
|
+
<Figure size ... with .... Axes>
|
|
336
|
+
"""
|
|
337
|
+
if interactive:
|
|
338
|
+
plt.ion()
|
|
339
|
+
else:
|
|
340
|
+
plt.ioff()
|
|
341
|
+
sizes = img.shape[0] / 100, img.shape[1] / 100
|
|
342
|
+
fig = plt.figure(figsize=(sizes[0], sizes[1]))
|
|
343
|
+
ax = fig.gca()
|
|
344
|
+
if cmap is None:
|
|
345
|
+
ax.imshow(img, interpolation="none")
|
|
346
|
+
else:
|
|
347
|
+
ax.imshow(img, cmap=cmap, interpolation="none")
|
|
348
|
+
fig.tight_layout()
|
|
349
|
+
fig.show()
|
|
350
|
+
return fig, ax
|
|
351
|
+
|
|
352
|
+
def save_fig(img, full_path, cmap=None):
|
|
353
|
+
"""
|
|
354
|
+
Save an image figure to a file with specified options.
|
|
355
|
+
|
|
356
|
+
This function creates a matplotlib figure from the given image,
|
|
357
|
+
optionally applies a colormap, displays it briefly, saves the
|
|
358
|
+
figure to disk at high resolution, and closes the figure.
|
|
359
|
+
|
|
360
|
+
Parameters
|
|
361
|
+
----------
|
|
362
|
+
img : array_like (M, N, 3)
|
|
363
|
+
Input image to be saved as a figure. Expected to be in RGB format.
|
|
364
|
+
full_path : str
|
|
365
|
+
The complete file path where the figure will be saved. Must include
|
|
366
|
+
extension (e.g., '.png', '.jpg').
|
|
367
|
+
cmap : str or None, optional
|
|
368
|
+
Colormap to be applied if the image should be displayed with a specific
|
|
369
|
+
color map. If `None`, no colormap is applied.
|
|
370
|
+
|
|
371
|
+
Returns
|
|
372
|
+
-------
|
|
373
|
+
None
|
|
374
|
+
|
|
375
|
+
This function does not return any value. It saves the figure to disk
|
|
376
|
+
at the specified location.
|
|
377
|
+
|
|
378
|
+
Raises
|
|
379
|
+
------
|
|
380
|
+
FileNotFoundError
|
|
381
|
+
If the directory in `full_path` does not exist.
|
|
382
|
+
|
|
383
|
+
Examples
|
|
384
|
+
--------
|
|
385
|
+
>>> img = np.random.rand(100, 100, 3) * 255
|
|
386
|
+
>>> save_fig(img, 'test.png')
|
|
387
|
+
Creates and saves a figure from the random image to 'test.png'.
|
|
388
|
+
|
|
389
|
+
>>> save_fig(img, 'colored_test.png', cmap='viridis')
|
|
390
|
+
Creates and saves a figure from the random image with 'viridis' colormap
|
|
391
|
+
to 'colored_test.png'.
|
|
392
|
+
"""
|
|
393
|
+
sizes = img.shape[0] / 100, img.shape[1] / 100
|
|
394
|
+
fig = plt.figure(figsize=(sizes[0], sizes[1]))
|
|
395
|
+
ax = fig.gca()
|
|
396
|
+
if cmap is None:
|
|
397
|
+
ax.imshow(img, interpolation="none")
|
|
398
|
+
else:
|
|
399
|
+
ax.imshow(img, cmap=cmap, interpolation="none")
|
|
400
|
+
plt.axis('off')
|
|
401
|
+
fig.tight_layout()
|
|
402
|
+
fig.show()
|
|
403
|
+
fig.savefig(full_path, bbox_inches='tight', pad_inches=0., transparent=True, dpi=500)
|
|
404
|
+
plt.close()
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def write_video(np_array, vid_name, is_color=True, fps=40):
|
|
408
|
+
"""
|
|
409
|
+
Write a video file from an array of images.
|
|
410
|
+
|
|
411
|
+
This function saves the provided NumPy array as either a `.npy` file
|
|
412
|
+
or encodes it into a video format such as .mp4, .avi, or .mkv based on
|
|
413
|
+
the provided file name and other parameters.
|
|
414
|
+
|
|
415
|
+
Parameters
|
|
416
|
+
----------
|
|
417
|
+
np_array : numpy.ndarray
|
|
418
|
+
A 4-d array representing a sequence of images. The shape should be
|
|
419
|
+
(num_frames, height, width, channels) where `channels` is 3 for color
|
|
420
|
+
images and 1 for grayscale.
|
|
421
|
+
|
|
422
|
+
vid_name : str
|
|
423
|
+
The name of the output file. If the extension is `.npy`, the array will be
|
|
424
|
+
saved in NumPy's binary format. Otherwise, a video file with the specified
|
|
425
|
+
extension will be created.
|
|
426
|
+
|
|
427
|
+
is_color : bool, optional
|
|
428
|
+
Whether the images are in color. Default is ``True``.
|
|
429
|
+
|
|
430
|
+
fps : int, optional
|
|
431
|
+
Frames per second for the video. Default is ``40``.
|
|
432
|
+
|
|
433
|
+
Returns
|
|
434
|
+
-------
|
|
435
|
+
None
|
|
436
|
+
|
|
437
|
+
Raises
|
|
438
|
+
------
|
|
439
|
+
ValueError
|
|
440
|
+
If the provided extension is not supported (.mp4, .avi, or .mkv).
|
|
441
|
+
|
|
442
|
+
Notes
|
|
443
|
+
-----
|
|
444
|
+
- The function supports `.mp4`, `.avi`, and `.mkv` extensions for video files.
|
|
445
|
+
- When specifying an extension, make sure it matches the intended codec.
|
|
446
|
+
|
|
447
|
+
Examples
|
|
448
|
+
--------
|
|
449
|
+
>>> import numpy as np
|
|
450
|
+
|
|
451
|
+
Create a dummy array of shape (10, 480, 640, 3):
|
|
452
|
+
>>> dummy_array = np.random.rand(10, 480, 640, 3)
|
|
453
|
+
|
|
454
|
+
Save it as a video file:
|
|
455
|
+
>>> write_video(dummy_array, 'output.mp4')
|
|
456
|
+
|
|
457
|
+
Save it as a .npy file:
|
|
458
|
+
>>> write_video(dummy_array, 'data.npy')
|
|
459
|
+
|
|
460
|
+
"""
|
|
461
|
+
#h265 ou h265 (mp4)
|
|
462
|
+
# linux: fourcc = 0x00000021 -> don't forget to change it bellow as well
|
|
463
|
+
if vid_name[-4:] == '.npy':
|
|
464
|
+
with open(vid_name, 'wb') as file:
|
|
465
|
+
np.save(file, np_array)
|
|
466
|
+
else:
|
|
467
|
+
valid_extensions = ['.mp4', '.avi', '.mkv']
|
|
468
|
+
vid_ext = vid_name[-4:]
|
|
469
|
+
if vid_ext not in valid_extensions:
|
|
470
|
+
vid_name = vid_name[:-4]
|
|
471
|
+
vid_name += '.mp4'
|
|
472
|
+
vid_ext = '.mp4'
|
|
473
|
+
if vid_ext =='.mp4':
|
|
474
|
+
fourcc = 0x7634706d# VideoWriter_fourcc(*'FMP4') #(*'MP4V') (*'h265') (*'x264') (*'DIVX')
|
|
475
|
+
else:
|
|
476
|
+
fourcc = cv2.VideoWriter_fourcc('F', 'F', 'V', '1') # lossless
|
|
477
|
+
size = np_array.shape[2], np_array.shape[1]
|
|
478
|
+
vid = cv2.VideoWriter(vid_name, fourcc, float(fps), tuple(size), is_color)
|
|
479
|
+
for image_i in np.arange(np_array.shape[0]):
|
|
480
|
+
image = np_array[image_i, ...]
|
|
481
|
+
vid.write(image)
|
|
482
|
+
vid.release()
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def video2numpy(vid_name, conversion_dict=None, background=None, true_frame_width=None):
|
|
486
|
+
"""
|
|
487
|
+
Convert a video file to a NumPy array.
|
|
488
|
+
|
|
489
|
+
This function reads a video file and converts it into a NumPy array.
|
|
490
|
+
If a conversion dictionary is provided, the function also generates
|
|
491
|
+
a converted version of the video using the specified color space conversions.
|
|
492
|
+
If true_frame_width is provided, and it matches half of the actual frame width,
|
|
493
|
+
the function adjusts the frame width accordingly.
|
|
494
|
+
|
|
495
|
+
Parameters
|
|
496
|
+
----------
|
|
497
|
+
vid_name : str
|
|
498
|
+
Path to the video file or .npy file containing the video data.
|
|
499
|
+
conversion_dict : dict, optional
|
|
500
|
+
Dictionary specifying color space conversions. Default is None.
|
|
501
|
+
background : bool, optional
|
|
502
|
+
Whether to subtract the background from the video frames. Default is None.
|
|
503
|
+
true_frame_width : int, optional
|
|
504
|
+
The true width of the video frames. Default is None.
|
|
505
|
+
|
|
506
|
+
Other Parameters
|
|
507
|
+
----------------
|
|
508
|
+
background : bool, optional
|
|
509
|
+
Whether to subtract the background from the video frames. Default is None.
|
|
510
|
+
true_frame_width : int, optional
|
|
511
|
+
The true width of the video frames. Default is None.
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
-------
|
|
515
|
+
video : numpy.ndarray or tuple(numpy.ndarray, numpy.ndarray)
|
|
516
|
+
If conversion_dict is None, returns the video as a NumPy array.
|
|
517
|
+
Otherwise, returns a tuple containing the original and converted videos.
|
|
518
|
+
|
|
519
|
+
Raises
|
|
520
|
+
------
|
|
521
|
+
ValueError
|
|
522
|
+
If the video file cannot be opened or if there is an error in processing.
|
|
523
|
+
|
|
524
|
+
Notes
|
|
525
|
+
-----
|
|
526
|
+
- This function uses OpenCV to read video files.
|
|
527
|
+
- If true_frame_width is provided and it matches half of the actual frame width,
|
|
528
|
+
the function adjusts the frame width accordingly.
|
|
529
|
+
- The conversion dictionary should contain color space mappings for transformation.
|
|
530
|
+
|
|
531
|
+
Examples
|
|
532
|
+
--------
|
|
533
|
+
>>> vid_array = video2numpy('example_video.mp4')
|
|
534
|
+
>>> print(vid_array.shape)
|
|
535
|
+
(100, 720, 1280, 3)
|
|
536
|
+
|
|
537
|
+
>>> vid_array, converted_vid = video2numpy('example_video.mp4', {'rgb': 'gray'}, True)
|
|
538
|
+
>>> print(vid_array.shape, converted_vid.shape)
|
|
539
|
+
(100, 720, 1280, 3) (100, 720, 640)
|
|
540
|
+
|
|
541
|
+
>>> vid_array = video2numpy('example_video.npy')
|
|
542
|
+
>>> print(vid_array.shape)
|
|
543
|
+
(100, 720, 1920, 3)
|
|
544
|
+
|
|
545
|
+
>>> vid_array = video2numpy('example_video.npy', true_frame_width=1920)
|
|
546
|
+
>>> print(vid_array.shape)
|
|
547
|
+
(100, 720, 960, 3)
|
|
548
|
+
|
|
549
|
+
>>> vid_array = video2numpy('example_video.npy', {'rgb': 'gray'}, True, 960)
|
|
550
|
+
>>> print(vid_array.shape)
|
|
551
|
+
(100, 720, 960)"""
|
|
552
|
+
if vid_name[-4:] == ".npy":
|
|
553
|
+
video = np.load(vid_name) # , allow_pickle='TRUE'
|
|
554
|
+
frame_width = video.shape[2]
|
|
555
|
+
if true_frame_width is not None:
|
|
556
|
+
if frame_width == 2 * true_frame_width:
|
|
557
|
+
frame_width = true_frame_width
|
|
558
|
+
if conversion_dict is not None:
|
|
559
|
+
converted_video = np.zeros((video.shape[0], video.shape[1], frame_width), dtype=np.uint8)
|
|
560
|
+
for counter in np.arange(video.shape[0]):
|
|
561
|
+
img = video[counter, :, :frame_width, :]
|
|
562
|
+
greyscale_image, greyscale_image2 = generate_color_space_combination(img, list(conversion_dict.keys()),
|
|
563
|
+
conversion_dict, background=background,
|
|
564
|
+
convert_to_uint8=True)
|
|
565
|
+
converted_video[counter, ...] = greyscale_image
|
|
566
|
+
video = video[:, :, :frame_width, ...]
|
|
567
|
+
else:
|
|
568
|
+
|
|
569
|
+
cap = cv2.VideoCapture(vid_name)
|
|
570
|
+
frame_number = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
571
|
+
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
|
572
|
+
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
|
573
|
+
if true_frame_width is not None:
|
|
574
|
+
if frame_width == 2 * true_frame_width:
|
|
575
|
+
frame_width = true_frame_width
|
|
576
|
+
|
|
577
|
+
# 2) Create empty arrays to store video analysis data
|
|
578
|
+
|
|
579
|
+
video = np.empty((frame_number, frame_height, frame_width, 3), dtype=np.uint8)
|
|
580
|
+
if conversion_dict is not None:
|
|
581
|
+
converted_video = np.empty((frame_number, frame_height, frame_width), dtype=np.uint8)
|
|
582
|
+
# 3) Read and convert the video frame by frame
|
|
583
|
+
counter = 0
|
|
584
|
+
while cap.isOpened() and counter < frame_number:
|
|
585
|
+
ret, frame = cap.read()
|
|
586
|
+
frame = frame[:, :frame_width, ...]
|
|
587
|
+
video[counter, ...] = frame
|
|
588
|
+
if conversion_dict is not None:
|
|
589
|
+
conversion_dict = translate_dict(conversion_dict)
|
|
590
|
+
c_spaces = get_color_spaces(frame, list(conversion_dict.keys()))
|
|
591
|
+
csc = combine_color_spaces(conversion_dict, c_spaces, subtract_background=background)
|
|
592
|
+
converted_video[counter, ...] = csc
|
|
593
|
+
counter += 1
|
|
594
|
+
cap.release()
|
|
595
|
+
|
|
596
|
+
if conversion_dict is None:
|
|
597
|
+
return video
|
|
598
|
+
else:
|
|
599
|
+
return video, converted_video
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def movie(video, keyboard=1, increase_contrast=True):
|
|
603
|
+
"""
|
|
604
|
+
Summary
|
|
605
|
+
-------
|
|
606
|
+
Processes a video to display each frame with optional contrast increase and resizing.
|
|
607
|
+
|
|
608
|
+
Parameters
|
|
609
|
+
----------
|
|
610
|
+
video : numpy.ndarray
|
|
611
|
+
The input video represented as a 3D NumPy array.
|
|
612
|
+
keyboard : int, optional
|
|
613
|
+
Key for waiting during display (default is 1).
|
|
614
|
+
increase_contrast : bool, optional
|
|
615
|
+
Flag to increase the contrast of each frame (default is True).
|
|
616
|
+
|
|
617
|
+
Other Parameters
|
|
618
|
+
----------------
|
|
619
|
+
keyboard : int, optional
|
|
620
|
+
Key to wait for during the display of each frame.
|
|
621
|
+
increase_contrast : bool, optional
|
|
622
|
+
Whether to increase contrast for the displayed frames.
|
|
623
|
+
|
|
624
|
+
Returns
|
|
625
|
+
-------
|
|
626
|
+
None
|
|
627
|
+
|
|
628
|
+
Raises
|
|
629
|
+
------
|
|
630
|
+
ValueError
|
|
631
|
+
If `video` is not a 3D NumPy array.
|
|
632
|
+
|
|
633
|
+
Notes
|
|
634
|
+
-----
|
|
635
|
+
This function uses OpenCV's `imshow` to display each frame. Ensure that the required
|
|
636
|
+
OpenCV dependencies are met.
|
|
637
|
+
|
|
638
|
+
Examples
|
|
639
|
+
--------
|
|
640
|
+
>>> movie(video)
|
|
641
|
+
Processes and displays a video with default settings.
|
|
642
|
+
>>> movie(video, keyboard=0)
|
|
643
|
+
Processes and displays a video waiting for the SPACE key between frames.
|
|
644
|
+
>>> movie(video, increase_contrast=False)
|
|
645
|
+
Processes and displays a video without increasing contrast.
|
|
646
|
+
|
|
647
|
+
"""
|
|
648
|
+
for i in np.arange(video.shape[0]):
|
|
649
|
+
image = video[i, :, :]
|
|
650
|
+
if np.any(image):
|
|
651
|
+
if increase_contrast:
|
|
652
|
+
image = bracket_to_uint8_image_contrast(image)
|
|
653
|
+
final_img = resize(image, (500, 500))
|
|
654
|
+
cv2.imshow('Motion analysis', final_img)
|
|
655
|
+
cv2.waitKey(keyboard)
|
|
656
|
+
cv2.destroyAllWindows()
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
opencv_accepted_formats = [
|
|
660
|
+
'bmp', 'BMP', 'dib', 'DIB', 'exr', 'EXR', 'hdr', 'HDR', 'jp2', 'JP2',
|
|
661
|
+
'jpe', 'JPE', 'jpeg', 'JPEG', 'jpg', 'JPG', 'pbm', 'PBM', 'pfm', 'PFM',
|
|
662
|
+
'pgm', 'PGM', 'pic', 'PIC', 'png', 'PNG', 'pnm', 'PNM', 'ppm', 'PPM',
|
|
663
|
+
'ras', 'RAS', 'sr', 'SR', 'tif', 'TIF', 'tiff', 'TIFF', 'webp', 'WEBP'
|
|
664
|
+
]
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def is_raw_image(image_path):
|
|
668
|
+
"""
|
|
669
|
+
Determine if the image path corresponds to a raw image.
|
|
670
|
+
|
|
671
|
+
Parameters
|
|
672
|
+
----------
|
|
673
|
+
image_path : str
|
|
674
|
+
The file path of the image.
|
|
675
|
+
|
|
676
|
+
Returns
|
|
677
|
+
-------
|
|
678
|
+
bool
|
|
679
|
+
True if the image is considered raw, False otherwise.
|
|
680
|
+
|
|
681
|
+
Examples
|
|
682
|
+
--------
|
|
683
|
+
>>> result = is_raw_image("image.jpg")
|
|
684
|
+
>>> print(result)
|
|
685
|
+
False
|
|
686
|
+
"""
|
|
687
|
+
ext = image_path.split(".")[-1]
|
|
688
|
+
if np.isin(ext, opencv_accepted_formats):
|
|
689
|
+
raw_image = False
|
|
690
|
+
else:
|
|
691
|
+
raw_image = True
|
|
692
|
+
return raw_image
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
def readim(image_path, raw_image=False):
|
|
696
|
+
"""
|
|
697
|
+
Read an image from a file and optionally process it.
|
|
698
|
+
|
|
699
|
+
Parameters
|
|
700
|
+
----------
|
|
701
|
+
image_path : str
|
|
702
|
+
Path to the image file.
|
|
703
|
+
raw_image : bool, optional
|
|
704
|
+
If True, logs an error message indicating that the raw image format cannot be processed. Default is False.
|
|
705
|
+
|
|
706
|
+
Returns
|
|
707
|
+
-------
|
|
708
|
+
ndarray
|
|
709
|
+
The decoded image represented as a NumPy array of shape (height, width, channels).
|
|
710
|
+
|
|
711
|
+
Raises
|
|
712
|
+
------
|
|
713
|
+
RuntimeError
|
|
714
|
+
If `raw_image` is set to True, logs an error indicating that the raw image format cannot be processed.
|
|
715
|
+
|
|
716
|
+
Notes
|
|
717
|
+
-----
|
|
718
|
+
Although `raw_image` is set to False by default, currently it does not perform any raw image processing.
|
|
719
|
+
|
|
720
|
+
Examples
|
|
721
|
+
--------
|
|
722
|
+
>>> cv2.imread("example.jpg")
|
|
723
|
+
array([[[255, 0, 0],
|
|
724
|
+
[255, 0, 0]],
|
|
725
|
+
|
|
726
|
+
[[ 0, 255, 0],
|
|
727
|
+
[ 0, 255, 0]],
|
|
728
|
+
|
|
729
|
+
[[ 0, 0, 255],
|
|
730
|
+
[ 0, 0, 255]]], dtype=uint8)
|
|
731
|
+
"""
|
|
732
|
+
if raw_image:
|
|
733
|
+
logging.error("Cannot read this image format. If the rawpy package can, ask for a version of Cellects using it.")
|
|
734
|
+
# import rawpy
|
|
735
|
+
# raw = rawpy.imread(image_path)
|
|
736
|
+
# raw = raw.postprocess()
|
|
737
|
+
# return cv2.cvtColor(raw, COLOR_RGB2BGR)
|
|
738
|
+
return cv2.imread(image_path)
|
|
739
|
+
else:
|
|
740
|
+
return cv2.imread(image_path)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def read_and_rotate(image_name, prev_img, raw_images, is_landscape):
|
|
744
|
+
"""
|
|
745
|
+
Reads an image from the given source and rotates it 90 degrees clockwise or counterclockwise if necessary.
|
|
746
|
+
|
|
747
|
+
Parameters
|
|
748
|
+
----------
|
|
749
|
+
image_name : str
|
|
750
|
+
The name or path of the image to be read.
|
|
751
|
+
prev_img : np.ndarray or None
|
|
752
|
+
The previous image in int16 format to compare differences, if applicable.
|
|
753
|
+
raw_images : dict
|
|
754
|
+
A dictionary containing raw images for the given `image_name`.
|
|
755
|
+
is_landscape : bool
|
|
756
|
+
If True, assumes the image should be in landscape orientation.
|
|
757
|
+
|
|
758
|
+
Returns
|
|
759
|
+
-------
|
|
760
|
+
np.ndarray
|
|
761
|
+
The processed and potentially rotated image.
|
|
762
|
+
|
|
763
|
+
Raises
|
|
764
|
+
------
|
|
765
|
+
FileNotFoundError
|
|
766
|
+
If the specified `image_name` does not exist in `raw_images`.
|
|
767
|
+
ValueError
|
|
768
|
+
If the image dimensions are inconsistent during rotation operations.
|
|
769
|
+
|
|
770
|
+
Notes
|
|
771
|
+
-----
|
|
772
|
+
- This function assumes that raw images are stored in the `raw_images` dictionary with keys as image names.
|
|
773
|
+
- Rotation decisions are based on whether the image is required to be in landscape orientation.
|
|
774
|
+
|
|
775
|
+
Examples
|
|
776
|
+
--------
|
|
777
|
+
>>> img = read_and_rotate("sample.jpg", prev_img=None, raw_images=False, is_landscape=True)
|
|
778
|
+
Rotated image of sample.jpg
|
|
779
|
+
"""
|
|
780
|
+
img = readim(image_name, raw_images)
|
|
781
|
+
if (img.shape[0] > img.shape[1] and is_landscape) or (img.shape[0] < img.shape[1] and not is_landscape):
|
|
782
|
+
clockwise = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
|
|
783
|
+
if prev_img is not None:
|
|
784
|
+
prev_img = np.int16(prev_img)
|
|
785
|
+
clock_diff = sum_of_abs_differences(prev_img, np.int16(clockwise))
|
|
786
|
+
counter_clockwise = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
|
|
787
|
+
counter_clock_diff = sum_of_abs_differences(prev_img, np.int16(counter_clockwise))
|
|
788
|
+
if clock_diff > counter_clock_diff:
|
|
789
|
+
img = counter_clockwise
|
|
790
|
+
else:
|
|
791
|
+
img = clockwise
|
|
792
|
+
else:
|
|
793
|
+
img = clockwise
|
|
794
|
+
return img
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
def vstack_h5_array(file_name, table, key="data"):
|
|
798
|
+
"""
|
|
799
|
+
Append a new table to an existing HDF5 dataset or create a new one if it doesn't exist.
|
|
800
|
+
|
|
801
|
+
Given a file name, table data and an optional key, this function will
|
|
802
|
+
check for existence of the HDF5 file. If it exists, append to the dataset
|
|
803
|
+
identified by `key` in the file. Otherwise create a new HDF5 file and dataset.
|
|
804
|
+
|
|
805
|
+
Parameters
|
|
806
|
+
----------
|
|
807
|
+
file_name : str
|
|
808
|
+
The name of the HDF5 file.
|
|
809
|
+
table : np.ndarray
|
|
810
|
+
New data to be added or stored in the HDF5 file.
|
|
811
|
+
key : str, optional
|
|
812
|
+
The dataset name within the HDF5 file. Default is "data".
|
|
813
|
+
|
|
814
|
+
Returns
|
|
815
|
+
-------
|
|
816
|
+
None
|
|
817
|
+
|
|
818
|
+
Raises
|
|
819
|
+
------
|
|
820
|
+
OSError
|
|
821
|
+
If there is an issue accessing the file system, e.g., due to permission errors.
|
|
822
|
+
IOError
|
|
823
|
+
If there is an issue writing the HDF5 file.
|
|
824
|
+
|
|
825
|
+
Notes
|
|
826
|
+
-----
|
|
827
|
+
The dataset will be appended to if it already exists. If the file does not exist,
|
|
828
|
+
a new HDF5 file will be created and the dataset will be initialized with `table`.
|
|
829
|
+
|
|
830
|
+
Examples
|
|
831
|
+
--------
|
|
832
|
+
>>> import numpy as np
|
|
833
|
+
>>> table1 = np.array([[1, 2], [3, 4]])
|
|
834
|
+
>>> vstack_h5_array('example.h5', table1) # create file and dataset
|
|
835
|
+
>>> table2 = np.array([[5, 6], [7, 8]])
|
|
836
|
+
>>> vstack_h5_array('example.h5', table2) # append to dataset
|
|
837
|
+
>>> with h5py.File('example.h5', 'r') as f:
|
|
838
|
+
... print(f['data'][:])
|
|
839
|
+
[[1 2]
|
|
840
|
+
[3 4]
|
|
841
|
+
[5 6]
|
|
842
|
+
[7 8]]
|
|
843
|
+
"""
|
|
844
|
+
if os.path.exists(file_name):
|
|
845
|
+
# Open the file in append mode
|
|
846
|
+
with h5py.File(file_name, 'a') as h5f:
|
|
847
|
+
if key in h5f:
|
|
848
|
+
# Append to the existing dataset
|
|
849
|
+
existing_data = h5f[key][:]
|
|
850
|
+
new_data = np.vstack((existing_data, table))
|
|
851
|
+
del h5f[key]
|
|
852
|
+
h5f.create_dataset(key, data=new_data)
|
|
853
|
+
else:
|
|
854
|
+
# Create a new dataset if the key doesn't exist
|
|
855
|
+
h5f.create_dataset(key, data=table)
|
|
856
|
+
else:
|
|
857
|
+
with h5py.File(file_name, 'w') as h5f:
|
|
858
|
+
h5f.create_dataset(key, data=table)
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
def read_h5_array(file_name, key="data"):
|
|
862
|
+
"""
|
|
863
|
+
Read data array from an HDF5 file.
|
|
864
|
+
|
|
865
|
+
This function reads a specific dataset from an HDF5 file using the provided key.
|
|
866
|
+
|
|
867
|
+
Parameters
|
|
868
|
+
----------
|
|
869
|
+
file_name : str
|
|
870
|
+
The path to the HDF5 file.
|
|
871
|
+
key : str, optional, default: 'data'
|
|
872
|
+
The dataset name within the HDF5 file.
|
|
873
|
+
|
|
874
|
+
Returns
|
|
875
|
+
-------
|
|
876
|
+
ndarray
|
|
877
|
+
The data array from the specified dataset in the HDF5 file.
|
|
878
|
+
|
|
879
|
+
Raises
|
|
880
|
+
------
|
|
881
|
+
KeyError
|
|
882
|
+
If the specified dataset key does not exist in the HDF5 file.
|
|
883
|
+
FileNotFoundError
|
|
884
|
+
If the specified HDF5 file does not exist.
|
|
885
|
+
|
|
886
|
+
Examples
|
|
887
|
+
--------
|
|
888
|
+
>>> data = read_h5_array('example.h5', 'data')
|
|
889
|
+
>>> print(data)
|
|
890
|
+
[[1 2 3]
|
|
891
|
+
[4 5 6]]
|
|
892
|
+
|
|
893
|
+
>>> data = read_h5_array('example.h5')
|
|
894
|
+
>>> print(data)
|
|
895
|
+
[[7 8 9]
|
|
896
|
+
[10 11 12]]
|
|
897
|
+
"""
|
|
898
|
+
try:
|
|
899
|
+
with h5py.File(file_name, 'r') as h5f:
|
|
900
|
+
if key in h5f:
|
|
901
|
+
data = h5f[key][:]
|
|
902
|
+
return data
|
|
903
|
+
else:
|
|
904
|
+
raise KeyError(f"Dataset '{key}' not found in file '{file_name}'.")
|
|
905
|
+
except FileNotFoundError:
|
|
906
|
+
raise FileNotFoundError(f"The file '{file_name}' does not exist.")
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
def get_h5_keys(file_name):
|
|
910
|
+
"""
|
|
911
|
+
Retrieve all keys from a given HDF5 file.
|
|
912
|
+
|
|
913
|
+
Parameters
|
|
914
|
+
----------
|
|
915
|
+
file_name : str
|
|
916
|
+
The path to the HDF5 file from which keys are to be retrieved.
|
|
917
|
+
|
|
918
|
+
Returns
|
|
919
|
+
-------
|
|
920
|
+
list of str
|
|
921
|
+
A list containing all the keys present in the specified HDF5 file.
|
|
922
|
+
|
|
923
|
+
Raises
|
|
924
|
+
------
|
|
925
|
+
FileNotFoundError
|
|
926
|
+
If the specified HDF5 file does not exist.
|
|
927
|
+
|
|
928
|
+
Examples
|
|
929
|
+
--------
|
|
930
|
+
>>> result = get_h5_keys("example.hdf5") # Ensure "example.hdf5" exists
|
|
931
|
+
>>> print(result)
|
|
932
|
+
['data', 'metadata']
|
|
933
|
+
"""
|
|
934
|
+
try:
|
|
935
|
+
with h5py.File(file_name, 'r') as h5f:
|
|
936
|
+
all_keys = list(h5f.keys())
|
|
937
|
+
return all_keys
|
|
938
|
+
except FileNotFoundError:
|
|
939
|
+
raise FileNotFoundError(f"The file '{file_name}' does not exist.")
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
def remove_h5_key(file_name, key="data"):
|
|
943
|
+
"""
|
|
944
|
+
Remove a specified key from an HDF5 file.
|
|
945
|
+
|
|
946
|
+
This function opens an HDF5 file in append mode and deletes the specified
|
|
947
|
+
key if it exists. It handles exceptions related to file not found
|
|
948
|
+
and other runtime errors.
|
|
949
|
+
|
|
950
|
+
Parameters
|
|
951
|
+
----------
|
|
952
|
+
file_name : str
|
|
953
|
+
The path to the HDF5 file from which the key should be removed.
|
|
954
|
+
key : str, optional
|
|
955
|
+
The name of the dataset or group to delete from the HDF5 file.
|
|
956
|
+
Default is "data".
|
|
957
|
+
|
|
958
|
+
Returns
|
|
959
|
+
-------
|
|
960
|
+
None
|
|
961
|
+
|
|
962
|
+
Raises
|
|
963
|
+
------
|
|
964
|
+
FileNotFoundError
|
|
965
|
+
If the specified file does not exist.
|
|
966
|
+
RuntimeError
|
|
967
|
+
If any other error occurs during file operations.
|
|
968
|
+
|
|
969
|
+
Notes
|
|
970
|
+
-----
|
|
971
|
+
This function modifies the HDF5 file in place. Ensure you have a backup if necessary.
|
|
972
|
+
|
|
973
|
+
Examples
|
|
974
|
+
--------
|
|
975
|
+
>>> remove_h5_key("example.h5", "data")
|
|
976
|
+
"""
|
|
977
|
+
try:
|
|
978
|
+
with h5py.File(file_name, 'a') as h5f: # Open in append mode to modify the file
|
|
979
|
+
if key in h5f:
|
|
980
|
+
del h5f[key]
|
|
981
|
+
except FileNotFoundError:
|
|
982
|
+
raise FileNotFoundError(f"The file '{file_name}' does not exist.")
|
|
983
|
+
except Exception as e:
|
|
984
|
+
raise RuntimeError(f"An error occurred: {e}")
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
def get_mpl_colormap(cmap_name):
|
|
988
|
+
"""
|
|
989
|
+
Returns a linear color range array for the given matplotlib colormap.
|
|
990
|
+
|
|
991
|
+
Parameters
|
|
992
|
+
----------
|
|
993
|
+
cmap_name : str
|
|
994
|
+
The name of the colormap to get.
|
|
995
|
+
|
|
996
|
+
Returns
|
|
997
|
+
-------
|
|
998
|
+
numpy.ndarray
|
|
999
|
+
A 256x1x3 array of bytes representing the linear color range.
|
|
1000
|
+
|
|
1001
|
+
Examples
|
|
1002
|
+
--------
|
|
1003
|
+
>>> result = get_mpl_colormap('viridis')
|
|
1004
|
+
>>> print(result.shape)
|
|
1005
|
+
(256, 1, 3)
|
|
1006
|
+
|
|
1007
|
+
"""
|
|
1008
|
+
cmap = plt.get_cmap(cmap_name)
|
|
1009
|
+
|
|
1010
|
+
# Initialize the matplotlib color map
|
|
1011
|
+
sm = plt.cm.ScalarMappable(cmap=cmap)
|
|
1012
|
+
|
|
1013
|
+
# Obtain linear color range
|
|
1014
|
+
color_range = sm.to_rgba(np.linspace(0, 1, 256), bytes=True)[:, 2::-1]
|
|
1015
|
+
|
|
1016
|
+
return color_range.reshape(256, 1, 3)
|