zea 0.0.7__py3-none-any.whl → 0.0.8__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.
Files changed (43) hide show
  1. zea/__init__.py +1 -1
  2. zea/backend/tensorflow/dataloader.py +0 -4
  3. zea/beamform/pixelgrid.py +1 -1
  4. zea/data/__init__.py +0 -9
  5. zea/data/augmentations.py +221 -28
  6. zea/data/convert/__init__.py +1 -6
  7. zea/data/convert/__main__.py +123 -0
  8. zea/data/convert/camus.py +99 -39
  9. zea/data/convert/echonet.py +183 -82
  10. zea/data/convert/echonetlvh/README.md +2 -3
  11. zea/data/convert/echonetlvh/{convert_raw_to_usbmd.py → __init__.py} +173 -102
  12. zea/data/convert/echonetlvh/manual_rejections.txt +73 -0
  13. zea/data/convert/echonetlvh/precompute_crop.py +43 -64
  14. zea/data/convert/picmus.py +37 -40
  15. zea/data/convert/utils.py +86 -0
  16. zea/data/convert/{matlab.py → verasonics.py} +33 -61
  17. zea/data/data_format.py +124 -4
  18. zea/data/dataloader.py +12 -7
  19. zea/data/datasets.py +109 -70
  20. zea/data/file.py +91 -82
  21. zea/data/file_operations.py +496 -0
  22. zea/data/preset_utils.py +1 -1
  23. zea/display.py +7 -8
  24. zea/internal/checks.py +6 -12
  25. zea/internal/operators.py +4 -0
  26. zea/io_lib.py +108 -160
  27. zea/models/__init__.py +1 -1
  28. zea/models/diffusion.py +62 -11
  29. zea/models/lv_segmentation.py +2 -0
  30. zea/ops.py +398 -158
  31. zea/scan.py +18 -8
  32. zea/tensor_ops.py +82 -62
  33. zea/tools/fit_scan_cone.py +90 -160
  34. zea/tracking/__init__.py +16 -0
  35. zea/tracking/base.py +94 -0
  36. zea/tracking/lucas_kanade.py +474 -0
  37. zea/tracking/segmentation.py +110 -0
  38. zea/utils.py +11 -2
  39. {zea-0.0.7.dist-info → zea-0.0.8.dist-info}/METADATA +3 -1
  40. {zea-0.0.7.dist-info → zea-0.0.8.dist-info}/RECORD +43 -35
  41. {zea-0.0.7.dist-info → zea-0.0.8.dist-info}/WHEEL +0 -0
  42. {zea-0.0.7.dist-info → zea-0.0.8.dist-info}/entry_points.txt +0 -0
  43. {zea-0.0.7.dist-info → zea-0.0.8.dist-info}/licenses/LICENSE +0 -0
zea/data/file.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import enum
4
4
  from pathlib import Path
5
- from typing import List
5
+ from typing import List, Tuple, Union
6
6
 
7
7
  import h5py
8
8
  import numpy as np
@@ -16,6 +16,7 @@ from zea.internal.checks import (
16
16
  _REQUIRED_SCAN_KEYS,
17
17
  get_check,
18
18
  )
19
+ from zea.internal.core import DataTypes
19
20
  from zea.internal.utils import reduce_to_signature
20
21
  from zea.probes import Probe
21
22
  from zea.scan import Scan
@@ -111,64 +112,10 @@ class File(h5py.File):
111
112
  else:
112
113
  raise NotImplementedError
113
114
 
114
- @staticmethod
115
- def _prepare_indices(indices):
116
- """Prepare the indices for loading data from hdf5 files.
117
- Options:
118
- - str("all")
119
- - int -> single frame
120
- - list of ints -> indexes first axis (frames)
121
- - list of list, ranges or slices -> indexes multiple axes
122
-
123
- Returns:
124
- indices (tuple): A tuple of indices / slices to use for indexing.
125
- """
126
- _value_error_msg = (
127
- f"Invalid value for indices: {indices}. "
128
- "Indices can be a 'all', int or a List[int, tuple, list, slice, range]."
129
- )
130
-
131
- # Check all options that only index the first axis
132
- if isinstance(indices, str):
133
- if indices == "all":
134
- return slice(None)
135
- else:
136
- raise ValueError(_value_error_msg)
137
-
138
- if isinstance(indices, range):
139
- return list(indices)
140
-
141
- if isinstance(indices, (int, slice, np.integer)):
142
- return indices
143
-
144
- # At this point, indices should be a list or tuple
145
- assert isinstance(indices, (list, tuple, np.ndarray)), _value_error_msg
146
-
147
- assert all(
148
- isinstance(idx, (list, tuple, int, slice, range, np.ndarray, np.integer))
149
- for idx in indices
150
- ), _value_error_msg
151
-
152
- # Convert ranges to lists
153
- processed_indices = [list(idx) if isinstance(idx, range) else idx for idx in indices]
154
-
155
- # Check if items are list-like and cast to tuple (needed for hdf5)
156
- if any(isinstance(idx, (list, tuple, slice)) for idx in processed_indices):
157
- processed_indices = tuple(processed_indices)
158
-
159
- return processed_indices
160
-
161
115
  def load_scan(self, event=None):
162
116
  """Alias for get_scan_parameters."""
163
117
  return self.get_scan_parameters(event)
164
118
 
165
- @staticmethod
166
- def check_data(data, key):
167
- """Check the data for a given key. For example, will check if the shape matches
168
- the data type (such as raw_data, ...)"""
169
- if key in _DATA_TYPES:
170
- get_check(key)(data, with_batch_dim=None)
171
-
172
119
  def format_key(self, key):
173
120
  """Format the key to match the data type."""
174
121
  # TODO: support events
@@ -206,7 +153,7 @@ class File(h5py.File):
206
153
  def load_transmits(self, key, selected_transmits):
207
154
  """Load raw_data or aligned_data for a given list of transmits.
208
155
  Args:
209
- data_type (str): The type of data to load. Options are 'raw_data' and 'aligned_data'.
156
+ key (str): The type of data to load. Options are 'raw_data' and 'aligned_data'.
210
157
  selected_transmits (list, np.ndarray): The transmits to load.
211
158
  """
212
159
  key = self.format_key(key)
@@ -214,23 +161,18 @@ class File(h5py.File):
214
161
  assert data_type in ["raw_data", "aligned_data"], (
215
162
  f"Cannot load transmits for {data_type}. Only raw_data and aligned_data are supported."
216
163
  )
217
- indices = [slice(None), np.array(selected_transmits)]
164
+ # First axis: all frames, second axis: selected transmits
165
+ indices = (slice(None), np.array(selected_transmits))
218
166
  return self.load_data(key, indices)
219
167
 
220
- def load_data(self, data_type, indices: str | int | List[int] = "all"):
168
+ def load_data(
169
+ self,
170
+ data_type,
171
+ indices: Tuple[Union[list, slice, int], ...] | List[int] | int | None = None,
172
+ ):
221
173
  """Load data from the file.
222
174
 
223
- The indices parameter can be used to load a subset of the data. This can be
224
-
225
- - 'all' to load all data
226
-
227
- - an int to load a single frame
228
-
229
- - a list of ints to load specific frames
230
-
231
- - a tuple of lists, ranges or slices to index frames and transmits. Note that
232
- indexing with lists of indices for both axes is not supported. In that case,
233
- try to define one of the axes with a slice.
175
+ .. include:: ../common/file_indexing.rst
234
176
 
235
177
  .. doctest::
236
178
 
@@ -258,13 +200,12 @@ class File(h5py.File):
258
200
  Args:
259
201
  data_type (str): The type of data to load. Options are 'raw_data', 'aligned_data',
260
202
  'beamformed_data', 'envelope_data', 'image' and 'image_sc'.
261
- indices (str, int, list, optional): The indices to load. Defaults to "all" in
262
- which case all frames are loaded. If an int is provided, it will be used
263
- as a single index. If a list is provided, it will be used as a list of
264
- indices.
203
+ indices (optional): The indices to load. Defaults to `None` in
204
+ which case all data is loaded.
265
205
  """
266
206
  key = self.format_key(data_type)
267
- indices = self._prepare_indices(indices)
207
+ if indices is None or (isinstance(indices, str) and indices == "all"):
208
+ indices = slice(None)
268
209
 
269
210
  if self._simple_index(key):
270
211
  data = self[key]
@@ -274,7 +215,6 @@ class File(h5py.File):
274
215
  raise ValueError(
275
216
  f"Invalid indices {indices} for key {key}. {key} has shape {data.shape}."
276
217
  ) from exc
277
- self.check_data(data, key)
278
218
  elif self.events_have_same_shape(key):
279
219
  raise NotImplementedError
280
220
  else:
@@ -425,6 +365,21 @@ class File(h5py.File):
425
365
  ans[key] = self.recursively_load_dict_contents_from_group(path + "/" + key + "/")
426
366
  return ans
427
367
 
368
+ def has_key(self, key: str) -> bool:
369
+ """Check if the file has a specific key.
370
+
371
+ Args:
372
+ key (str): The key to check.
373
+
374
+ Returns:
375
+ bool: True if the key exists, False otherwise.
376
+ """
377
+ try:
378
+ key = self.format_key(key)
379
+ except AssertionError:
380
+ return False
381
+ return True
382
+
428
383
  @classmethod
429
384
  def get_shape(cls, path: str, key: str) -> tuple:
430
385
  """Get the shape of a key in a file.
@@ -490,10 +445,67 @@ class File(h5py.File):
490
445
  _print_hdf5_attrs(self)
491
446
 
492
447
 
448
+ def load_file_all_data_types(
449
+ path,
450
+ indices: Tuple[Union[list, slice, int], ...] | List[int] | int | None = None,
451
+ scan_kwargs: dict = None,
452
+ ):
453
+ """Loads a zea data files (h5py file).
454
+
455
+ Returns all data types together with a scan object containing the parameters
456
+ of the acquisition and a probe object containing the parameters of the probe.
457
+
458
+ Additionally, it can load a specific subset of frames / transmits.
459
+
460
+ .. include:: ../common/file_indexing.rst
461
+
462
+ Args:
463
+ path (str, pathlike): The path to the hdf5 file.
464
+ indices (optional): The indices to load. Defaults to None in
465
+ which case all frames are loaded.
466
+ scan_kwargs (Config, dict, optional): Additional keyword arguments
467
+ to pass to the Scan object. These will override the parameters from the file
468
+ if they are present in the file. Defaults to None.
469
+
470
+ Returns:
471
+ (dict): A dictionary with all data types as keys and the corresponding data as values.
472
+ (Scan): A scan object containing the parameters of the acquisition.
473
+ (Probe): A probe object containing the parameters of the probe.
474
+ """
475
+ # Define the additional keyword parameters from the scan object
476
+ if scan_kwargs is None:
477
+ scan_kwargs = {}
478
+
479
+ data_dict = {}
480
+
481
+ with File(path, mode="r") as file:
482
+ # Load the probe object from the file
483
+ probe = file.probe()
484
+
485
+ for data_type in DataTypes:
486
+ if not file.has_key(data_type.value):
487
+ data_dict[data_type.value] = None
488
+ continue
489
+
490
+ # Load the desired frames from the file
491
+ data_dict[data_type.value] = file.load_data(data_type.value, indices=indices)
492
+
493
+ # extract transmits from indices
494
+ # we only have to do this when the data has a n_tx dimension
495
+ # in that case we also have update scan parameters to match
496
+ # the number of selected transmits
497
+ if isinstance(indices, tuple) and len(indices) > 1:
498
+ scan_kwargs["selected_transmits"] = indices[1]
499
+
500
+ scan = file.scan(**scan_kwargs)
501
+
502
+ return data_dict, scan, probe
503
+
504
+
493
505
  def load_file(
494
506
  path,
495
507
  data_type="raw_data",
496
- indices: str | int | List[int] = "all",
508
+ indices: Tuple[Union[list, slice, int], ...] | List[int] | int | None = None,
497
509
  scan_kwargs: dict = None,
498
510
  ):
499
511
  """Loads a zea data files (h5py file).
@@ -503,17 +515,15 @@ def load_file(
503
515
 
504
516
  Additionally, it can load a specific subset of frames / transmits.
505
517
 
506
- # TODO: add support for event
518
+ .. include:: ../common/file_indexing.rst
507
519
 
508
520
  Args:
509
521
  path (str, pathlike): The path to the hdf5 file.
510
522
  data_type (str, optional): The type of data to load. Defaults to
511
523
  'raw_data'. Other options are 'aligned_data', 'beamformed_data',
512
524
  'envelope_data', 'image' and 'image_sc'.
513
- indices (str, int, list, optional): The indices to load. Defaults to "all" in
514
- which case all frames are loaded. If an int is provided, it will be used
515
- as a single index. If a list is provided, it will be used as a list of
516
- indices.
525
+ indices (optional): The indices to load. Defaults to None in
526
+ which case all frames are loaded.
517
527
  scan_kwargs (Config, dict, optional): Additional keyword arguments
518
528
  to pass to the Scan object. These will override the parameters from the file
519
529
  if they are present in the file. Defaults to None.
@@ -539,7 +549,6 @@ def load_file(
539
549
  # in that case we also have update scan parameters to match
540
550
  # the number of selected transmits
541
551
  if data_type in ["raw_data", "aligned_data"]:
542
- indices = File._prepare_indices(indices)
543
552
  if isinstance(indices, tuple) and len(indices) > 1:
544
553
  scan_kwargs["selected_transmits"] = indices[1]
545
554