zea 0.0.7__py3-none-any.whl → 0.0.9__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.
- zea/__init__.py +3 -3
- zea/agent/masks.py +2 -2
- zea/agent/selection.py +3 -3
- zea/backend/__init__.py +1 -1
- zea/backend/tensorflow/dataloader.py +1 -5
- zea/beamform/beamformer.py +4 -2
- zea/beamform/pfield.py +2 -2
- zea/beamform/pixelgrid.py +1 -1
- zea/data/__init__.py +0 -9
- zea/data/augmentations.py +222 -29
- zea/data/convert/__init__.py +1 -6
- zea/data/convert/__main__.py +164 -0
- zea/data/convert/camus.py +106 -40
- zea/data/convert/echonet.py +184 -83
- zea/data/convert/echonetlvh/README.md +2 -3
- zea/data/convert/echonetlvh/{convert_raw_to_usbmd.py → __init__.py} +174 -103
- zea/data/convert/echonetlvh/manual_rejections.txt +73 -0
- zea/data/convert/echonetlvh/precompute_crop.py +43 -64
- zea/data/convert/picmus.py +37 -40
- zea/data/convert/utils.py +86 -0
- zea/data/convert/verasonics.py +1247 -0
- zea/data/data_format.py +124 -6
- zea/data/dataloader.py +12 -7
- zea/data/datasets.py +109 -70
- zea/data/file.py +119 -82
- zea/data/file_operations.py +496 -0
- zea/data/preset_utils.py +2 -2
- zea/display.py +8 -9
- zea/doppler.py +5 -5
- zea/func/__init__.py +109 -0
- zea/{tensor_ops.py → func/tensor.py} +113 -69
- zea/func/ultrasound.py +500 -0
- zea/internal/_generate_keras_ops.py +5 -5
- zea/internal/checks.py +6 -12
- zea/internal/operators.py +4 -0
- zea/io_lib.py +108 -160
- zea/metrics.py +6 -5
- zea/models/__init__.py +1 -1
- zea/models/diffusion.py +63 -12
- zea/models/echonetlvh.py +1 -1
- zea/models/gmm.py +1 -1
- zea/models/lv_segmentation.py +2 -0
- zea/ops/__init__.py +188 -0
- zea/ops/base.py +442 -0
- zea/{keras_ops.py → ops/keras_ops.py} +2 -2
- zea/ops/pipeline.py +1472 -0
- zea/ops/tensor.py +356 -0
- zea/ops/ultrasound.py +890 -0
- zea/probes.py +2 -10
- zea/scan.py +35 -28
- zea/tools/fit_scan_cone.py +90 -160
- zea/tools/selection_tool.py +1 -1
- zea/tracking/__init__.py +16 -0
- zea/tracking/base.py +94 -0
- zea/tracking/lucas_kanade.py +474 -0
- zea/tracking/segmentation.py +110 -0
- zea/utils.py +11 -2
- {zea-0.0.7.dist-info → zea-0.0.9.dist-info}/METADATA +5 -1
- {zea-0.0.7.dist-info → zea-0.0.9.dist-info}/RECORD +62 -48
- zea/data/convert/matlab.py +0 -1237
- zea/ops.py +0 -3294
- {zea-0.0.7.dist-info → zea-0.0.9.dist-info}/WHEEL +0 -0
- {zea-0.0.7.dist-info → zea-0.0.9.dist-info}/entry_points.txt +0 -0
- {zea-0.0.7.dist-info → zea-0.0.9.dist-info}/licenses/LICENSE +0 -0
zea/probes.py
CHANGED
|
@@ -22,7 +22,7 @@ We can initialize a generic probe with the following code:
|
|
|
22
22
|
|
|
23
23
|
>>> probe = Probe.from_name("generic")
|
|
24
24
|
>>> print(probe.get_parameters())
|
|
25
|
-
{'probe_geometry': None, 'center_frequency': None, 'sampling_frequency': None, 'xlims': None, 'zlims': None}
|
|
25
|
+
{'probe_geometry': None, 'center_frequency': None, 'sampling_frequency': None, 'xlims': None, 'zlims': None, 'n_el': None}
|
|
26
26
|
""" # noqa: E501
|
|
27
27
|
|
|
28
28
|
import numpy as np
|
|
@@ -114,6 +114,7 @@ class Probe(Object):
|
|
|
114
114
|
"sampling_frequency": self.sampling_frequency,
|
|
115
115
|
"xlims": self.xlims,
|
|
116
116
|
"zlims": self.zlims,
|
|
117
|
+
"n_el": self.n_el,
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
@classmethod
|
|
@@ -231,12 +232,3 @@ class Esaote_sll1543(Probe):
|
|
|
231
232
|
bandwidth_MHz=bandwidth_MHz,
|
|
232
233
|
probe_type="linear",
|
|
233
234
|
)
|
|
234
|
-
|
|
235
|
-
def get_parameters(self):
|
|
236
|
-
return {
|
|
237
|
-
"probe_geometry": self.probe_geometry,
|
|
238
|
-
"center_frequency": self.center_frequency,
|
|
239
|
-
"sampling_frequency": self.sampling_frequency,
|
|
240
|
-
"xlims": self.xlims,
|
|
241
|
-
"zlims": self.zlims,
|
|
242
|
-
}
|
zea/scan.py
CHANGED
|
@@ -153,13 +153,11 @@ class Scan(Parameters):
|
|
|
153
153
|
apply_lens_correction (bool, optional): Whether to apply lens correction to
|
|
154
154
|
delays. Defaults to False.
|
|
155
155
|
lens_thickness (float, optional): Thickness of the lens in meters.
|
|
156
|
-
Defaults to None.
|
|
157
156
|
f_number (float, optional): F-number of the transducer. Defaults to 1.0.
|
|
158
157
|
theta_range (tuple, optional): Range of theta angles for 3D imaging.
|
|
159
158
|
phi_range (tuple, optional): Range of phi angles for 3D imaging.
|
|
160
159
|
rho_range (tuple, optional): Range of rho (radial) distances for 3D imaging.
|
|
161
160
|
fill_value (float, optional): Value to use for out-of-bounds pixels.
|
|
162
|
-
Defaults to 0.0.
|
|
163
161
|
attenuation_coef (float, optional): Attenuation coefficient in dB/(MHz*cm).
|
|
164
162
|
Defaults to 0.0.
|
|
165
163
|
selected_transmits (None, str, int, list, slice, or np.ndarray, optional):
|
|
@@ -215,15 +213,15 @@ class Scan(Parameters):
|
|
|
215
213
|
"initial_times": {"type": np.ndarray},
|
|
216
214
|
"time_to_next_transmit": {"type": np.ndarray},
|
|
217
215
|
"tgc_gain_curve": {"type": np.ndarray},
|
|
218
|
-
"waveforms_one_way": {"type": np.ndarray},
|
|
219
|
-
"waveforms_two_way": {"type": np.ndarray},
|
|
216
|
+
"waveforms_one_way": {"type": np.ndarray, "default": None},
|
|
217
|
+
"waveforms_two_way": {"type": np.ndarray, "default": None},
|
|
220
218
|
"tx_waveform_indices": {"type": np.ndarray},
|
|
221
219
|
"t_peak": {"type": np.ndarray},
|
|
222
220
|
# scan conversion parameters
|
|
223
221
|
"theta_range": {"type": (tuple, list)},
|
|
224
222
|
"phi_range": {"type": (tuple, list)},
|
|
225
223
|
"rho_range": {"type": (tuple, list)},
|
|
226
|
-
"fill_value": {"type": float
|
|
224
|
+
"fill_value": {"type": float},
|
|
227
225
|
"resolution": {"type": float, "default": None},
|
|
228
226
|
}
|
|
229
227
|
|
|
@@ -242,16 +240,7 @@ class Scan(Parameters):
|
|
|
242
240
|
if selected_transmits_input is not None:
|
|
243
241
|
self.set_transmits(selected_transmits_input)
|
|
244
242
|
|
|
245
|
-
@cache_with_dependencies(
|
|
246
|
-
"xlims",
|
|
247
|
-
"zlims",
|
|
248
|
-
"grid_size_x",
|
|
249
|
-
"grid_size_z",
|
|
250
|
-
"sound_speed",
|
|
251
|
-
"center_frequency",
|
|
252
|
-
"pixels_per_wavelength",
|
|
253
|
-
"grid_type",
|
|
254
|
-
)
|
|
243
|
+
@cache_with_dependencies("xlims", "zlims", "grid_size_x", "grid_size_z", "grid_type")
|
|
255
244
|
def grid(self):
|
|
256
245
|
"""The beamforming grid of shape (grid_size_z, grid_size_x, 3)."""
|
|
257
246
|
if self.grid_type == "polar":
|
|
@@ -271,12 +260,7 @@ class Scan(Parameters):
|
|
|
271
260
|
"'cartesian' and 'polar'."
|
|
272
261
|
)
|
|
273
262
|
|
|
274
|
-
@cache_with_dependencies(
|
|
275
|
-
"xlims",
|
|
276
|
-
"wavelength",
|
|
277
|
-
"pixels_per_wavelength",
|
|
278
|
-
"grid_type",
|
|
279
|
-
)
|
|
263
|
+
@cache_with_dependencies("xlims", "wavelength", "pixels_per_wavelength")
|
|
280
264
|
def grid_size_x(self):
|
|
281
265
|
"""Grid width in pixels. For a cartesian grid, this is the lateral (x) pixels in the grid,
|
|
282
266
|
set to prevent aliasing if not provided. For a polar grid, this can be thought of as
|
|
@@ -311,7 +295,7 @@ class Scan(Parameters):
|
|
|
311
295
|
"""Calculate the wavelength based on sound speed and center frequency."""
|
|
312
296
|
return self.sound_speed / self.center_frequency
|
|
313
297
|
|
|
314
|
-
@cache_with_dependencies("zlims", "
|
|
298
|
+
@cache_with_dependencies("zlims", "polar_limits", "probe_geometry")
|
|
315
299
|
def xlims(self):
|
|
316
300
|
"""The x-limits of the beamforming grid [m]. If not explicitly set, it is computed based
|
|
317
301
|
on the polar limits and probe geometry.
|
|
@@ -508,7 +492,7 @@ class Scan(Parameters):
|
|
|
508
492
|
value = self._params.get("azimuth_angles")
|
|
509
493
|
if value is None:
|
|
510
494
|
log.warning("No azimuth angles provided, using zeros")
|
|
511
|
-
|
|
495
|
+
return np.zeros(self.n_tx_selected)
|
|
512
496
|
|
|
513
497
|
return value[self.selected_transmits]
|
|
514
498
|
|
|
@@ -529,7 +513,7 @@ class Scan(Parameters):
|
|
|
529
513
|
value = self._params.get("tx_apodizations")
|
|
530
514
|
if value is None:
|
|
531
515
|
log.warning("No transmit apodizations provided, using ones")
|
|
532
|
-
|
|
516
|
+
return np.ones((self.n_tx_selected, self.n_el))
|
|
533
517
|
|
|
534
518
|
return value[self.selected_transmits]
|
|
535
519
|
|
|
@@ -539,7 +523,7 @@ class Scan(Parameters):
|
|
|
539
523
|
value = self._params.get("focus_distances")
|
|
540
524
|
if value is None:
|
|
541
525
|
log.warning("No focus distances provided, using zeros")
|
|
542
|
-
|
|
526
|
+
return np.zeros(self.n_tx_selected)
|
|
543
527
|
|
|
544
528
|
return value[self.selected_transmits]
|
|
545
529
|
|
|
@@ -549,16 +533,28 @@ class Scan(Parameters):
|
|
|
549
533
|
value = self._params.get("initial_times")
|
|
550
534
|
if value is None:
|
|
551
535
|
log.warning("No initial times provided, using zeros")
|
|
552
|
-
|
|
536
|
+
return np.zeros(self.n_tx_selected)
|
|
553
537
|
|
|
554
538
|
return value[self.selected_transmits]
|
|
555
539
|
|
|
540
|
+
@property
|
|
541
|
+
def n_waveforms(self):
|
|
542
|
+
"""The number of unique transmit waveforms."""
|
|
543
|
+
|
|
544
|
+
if self.waveforms_one_way is not None:
|
|
545
|
+
return self.waveforms_one_way.shape[0]
|
|
546
|
+
|
|
547
|
+
if self.waveforms_two_way is not None:
|
|
548
|
+
return self.waveforms_two_way.shape[0]
|
|
549
|
+
|
|
550
|
+
return 1
|
|
551
|
+
|
|
556
552
|
@property
|
|
557
553
|
def t_peak(self):
|
|
558
554
|
"""The time of the peak of the pulse in seconds of shape (n_waveforms,)."""
|
|
559
555
|
t_peak = self._params.get("t_peak")
|
|
560
556
|
if t_peak is None:
|
|
561
|
-
t_peak = np.array([1 / self.center_frequency])
|
|
557
|
+
t_peak = np.array([1 / self.center_frequency] * self.n_waveforms)
|
|
562
558
|
|
|
563
559
|
return t_peak
|
|
564
560
|
|
|
@@ -617,7 +613,7 @@ class Scan(Parameters):
|
|
|
617
613
|
|
|
618
614
|
@cache_with_dependencies("pfield")
|
|
619
615
|
def flat_pfield(self):
|
|
620
|
-
"""Flattened pfield for weighting."""
|
|
616
|
+
"""Flattened pfield for weighting of shape (n_pix, n_tx)."""
|
|
621
617
|
return self.pfield.reshape(self.n_tx, -1).swapaxes(0, 1)
|
|
622
618
|
|
|
623
619
|
@cache_with_dependencies("zlims")
|
|
@@ -674,6 +670,17 @@ class Scan(Parameters):
|
|
|
674
670
|
otherwise 2D."""
|
|
675
671
|
return self.coordinates_3d if getattr(self, "phi_range", None) else self.coordinates_2d
|
|
676
672
|
|
|
673
|
+
@property
|
|
674
|
+
def pulse_repetition_frequency(self):
|
|
675
|
+
"""The pulse repetition frequency (PRF) [Hz]. Assumes a constant PRF."""
|
|
676
|
+
if self.time_to_next_transmit is None:
|
|
677
|
+
log.warning("Time to next transmit is not set, cannot compute PRF")
|
|
678
|
+
return None
|
|
679
|
+
|
|
680
|
+
pulse_repetition_interval = np.mean(self.time_to_next_transmit)
|
|
681
|
+
|
|
682
|
+
return 1 / pulse_repetition_interval
|
|
683
|
+
|
|
677
684
|
@cache_with_dependencies("time_to_next_transmit")
|
|
678
685
|
def frames_per_second(self):
|
|
679
686
|
"""The number of frames per second [Hz]. Assumes a constant frame rate.
|