zea 0.0.2__tar.gz → 0.0.4__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.
Files changed (105) hide show
  1. {zea-0.0.2 → zea-0.0.4}/PKG-INFO +13 -7
  2. {zea-0.0.2 → zea-0.0.4}/README.md +8 -3
  3. {zea-0.0.2 → zea-0.0.4}/pyproject.toml +5 -4
  4. {zea-0.0.2 → zea-0.0.4}/zea/__init__.py +1 -1
  5. {zea-0.0.2 → zea-0.0.4}/zea/agent/selection.py +47 -30
  6. {zea-0.0.2 → zea-0.0.4}/zea/backend/__init__.py +5 -3
  7. {zea-0.0.2 → zea-0.0.4}/zea/beamform/__init__.py +1 -1
  8. {zea-0.0.2 → zea-0.0.4}/zea/beamform/beamformer.py +5 -4
  9. {zea-0.0.2 → zea-0.0.4}/zea/beamform/pfield.py +6 -3
  10. {zea-0.0.2 → zea-0.0.4}/zea/beamform/pixelgrid.py +29 -28
  11. {zea-0.0.2 → zea-0.0.4}/zea/config.py +25 -5
  12. {zea-0.0.2 → zea-0.0.4}/zea/data/data_format.py +44 -40
  13. {zea-0.0.2 → zea-0.0.4}/zea/data/file.py +3 -18
  14. zea-0.0.4/zea/data/preset_utils.py +123 -0
  15. {zea-0.0.2 → zea-0.0.4}/zea/datapaths.py +3 -3
  16. {zea-0.0.2 → zea-0.0.4}/zea/display.py +2 -2
  17. {zea-0.0.2 → zea-0.0.4}/zea/interface.py +1 -1
  18. {zea-0.0.2 → zea-0.0.4}/zea/internal/checks.py +17 -8
  19. {zea-0.0.2 → zea-0.0.4}/zea/internal/config/parameters.py +2 -2
  20. {zea-0.0.2 → zea-0.0.4}/zea/internal/config/validation.py +2 -2
  21. {zea-0.0.2 → zea-0.0.4}/zea/internal/core.py +11 -42
  22. {zea-0.0.2 → zea-0.0.4}/zea/internal/parameters.py +204 -163
  23. {zea-0.0.2 → zea-0.0.4}/zea/internal/registry.py +16 -8
  24. {zea-0.0.2 → zea-0.0.4}/zea/internal/viewer.py +1 -1
  25. {zea-0.0.2 → zea-0.0.4}/zea/io_lib.py +2 -7
  26. {zea-0.0.2 → zea-0.0.4}/zea/log.py +8 -0
  27. {zea-0.0.2 → zea-0.0.4}/zea/models/base.py +1 -0
  28. {zea-0.0.2 → zea-0.0.4}/zea/models/diffusion.py +43 -17
  29. {zea-0.0.2 → zea-0.0.4}/zea/ops.py +195 -117
  30. {zea-0.0.2 → zea-0.0.4}/zea/probes.py +23 -5
  31. {zea-0.0.2 → zea-0.0.4}/zea/scan.py +97 -68
  32. {zea-0.0.2 → zea-0.0.4}/zea/tensor_ops.py +3 -3
  33. {zea-0.0.2 → zea-0.0.4}/zea/tools/selection_tool.py +1 -1
  34. {zea-0.0.2 → zea-0.0.4}/zea/utils.py +31 -0
  35. {zea-0.0.2 → zea-0.0.4}/zea/visualize.py +15 -7
  36. zea-0.0.2/zea/data/preset_utils.py +0 -109
  37. {zea-0.0.2 → zea-0.0.4}/LICENSE +0 -0
  38. {zea-0.0.2 → zea-0.0.4}/zea/__main__.py +0 -0
  39. {zea-0.0.2 → zea-0.0.4}/zea/agent/__init__.py +0 -0
  40. {zea-0.0.2 → zea-0.0.4}/zea/agent/gumbel.py +0 -0
  41. {zea-0.0.2 → zea-0.0.4}/zea/agent/masks.py +0 -0
  42. {zea-0.0.2 → zea-0.0.4}/zea/backend/autograd.py +0 -0
  43. {zea-0.0.2 → zea-0.0.4}/zea/backend/jax/__init__.py +0 -0
  44. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/__init__.py +0 -0
  45. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/dataloader.py +0 -0
  46. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/layers/__init__.py +0 -0
  47. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/layers/apodization.py +0 -0
  48. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/layers/utils.py +0 -0
  49. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/losses.py +0 -0
  50. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/models/__init__.py +0 -0
  51. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/models/lista.py +0 -0
  52. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/scripts/convert-echonet-dynamic.py +0 -0
  53. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/scripts/convert-taesd.py +0 -0
  54. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/utils/__init__.py +0 -0
  55. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/utils/callbacks.py +0 -0
  56. {zea-0.0.2 → zea-0.0.4}/zea/backend/tensorflow/utils/utils.py +0 -0
  57. {zea-0.0.2 → zea-0.0.4}/zea/backend/tf2jax.py +0 -0
  58. {zea-0.0.2 → zea-0.0.4}/zea/backend/torch/__init__.py +0 -0
  59. {zea-0.0.2 → zea-0.0.4}/zea/backend/torch/losses.py +0 -0
  60. {zea-0.0.2 → zea-0.0.4}/zea/beamform/delays.py +0 -0
  61. {zea-0.0.2 → zea-0.0.4}/zea/beamform/lens_correction.py +0 -0
  62. {zea-0.0.2 → zea-0.0.4}/zea/beamform/phantoms.py +0 -0
  63. {zea-0.0.2 → zea-0.0.4}/zea/data/__init__.py +0 -0
  64. {zea-0.0.2 → zea-0.0.4}/zea/data/__main__.py +0 -0
  65. {zea-0.0.2 → zea-0.0.4}/zea/data/augmentations.py +0 -0
  66. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/__init__.py +0 -0
  67. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/camus.py +0 -0
  68. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/echonet.py +0 -0
  69. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/echonetlvh/README.md +0 -0
  70. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/echonetlvh/convert_raw_to_usbmd.py +0 -0
  71. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/echonetlvh/precompute_crop.py +0 -0
  72. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/images.py +0 -0
  73. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/matlab.py +0 -0
  74. {zea-0.0.2 → zea-0.0.4}/zea/data/convert/picmus.py +0 -0
  75. {zea-0.0.2 → zea-0.0.4}/zea/data/dataloader.py +0 -0
  76. {zea-0.0.2 → zea-0.0.4}/zea/data/datasets.py +0 -0
  77. {zea-0.0.2 → zea-0.0.4}/zea/data/layers.py +0 -0
  78. {zea-0.0.2 → zea-0.0.4}/zea/data/utils.py +0 -0
  79. {zea-0.0.2 → zea-0.0.4}/zea/internal/cache.py +0 -0
  80. {zea-0.0.2 → zea-0.0.4}/zea/internal/config/create.py +0 -0
  81. {zea-0.0.2 → zea-0.0.4}/zea/internal/convert.py +0 -0
  82. {zea-0.0.2 → zea-0.0.4}/zea/internal/device.py +0 -0
  83. {zea-0.0.2 → zea-0.0.4}/zea/internal/git_info.py +0 -0
  84. {zea-0.0.2 → zea-0.0.4}/zea/internal/operators.py +0 -0
  85. {zea-0.0.2 → zea-0.0.4}/zea/internal/setup_zea.py +0 -0
  86. {zea-0.0.2 → zea-0.0.4}/zea/metrics.py +0 -0
  87. {zea-0.0.2 → zea-0.0.4}/zea/models/__init__.py +0 -0
  88. {zea-0.0.2 → zea-0.0.4}/zea/models/carotid_segmenter.py +0 -0
  89. {zea-0.0.2 → zea-0.0.4}/zea/models/dense.py +0 -0
  90. {zea-0.0.2 → zea-0.0.4}/zea/models/echonet.py +0 -0
  91. {zea-0.0.2 → zea-0.0.4}/zea/models/generative.py +0 -0
  92. {zea-0.0.2 → zea-0.0.4}/zea/models/gmm.py +0 -0
  93. {zea-0.0.2 → zea-0.0.4}/zea/models/layers.py +0 -0
  94. {zea-0.0.2 → zea-0.0.4}/zea/models/lpips.py +0 -0
  95. {zea-0.0.2 → zea-0.0.4}/zea/models/preset_utils.py +0 -0
  96. {zea-0.0.2 → zea-0.0.4}/zea/models/presets.py +0 -0
  97. {zea-0.0.2 → zea-0.0.4}/zea/models/taesd.py +0 -0
  98. {zea-0.0.2 → zea-0.0.4}/zea/models/unet.py +0 -0
  99. {zea-0.0.2 → zea-0.0.4}/zea/models/utils.py +0 -0
  100. {zea-0.0.2 → zea-0.0.4}/zea/simulator.py +0 -0
  101. {zea-0.0.2 → zea-0.0.4}/zea/tools/__init__.py +0 -0
  102. {zea-0.0.2 → zea-0.0.4}/zea/tools/fit_scan_cone.py +0 -0
  103. {zea-0.0.2 → zea-0.0.4}/zea/tools/hf.py +0 -0
  104. {zea-0.0.2 → zea-0.0.4}/zea/tools/wndb.py +0 -0
  105. {zea-0.0.2 → zea-0.0.4}/zea/zea_darkmode.mplstyle +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: zea
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: A Toolbox for Cognitive Ultrasound Imaging. Provides a set of tools for processing of ultrasound data, all built in your favorite machine learning framework.
5
5
  Keywords: ultrasound,machine learning,beamforming
6
6
  Author: Tristan Stevens
@@ -22,6 +22,8 @@ Provides-Extra: display-headless
22
22
  Provides-Extra: docs
23
23
  Provides-Extra: jax
24
24
  Provides-Extra: tests
25
+ Requires-Dist: IPython ; extra == "dev"
26
+ Requires-Dist: IPython ; extra == "docs"
25
27
  Requires-Dist: PyStemmer ; extra == "dev"
26
28
  Requires-Dist: PyStemmer ; extra == "docs"
27
29
  Requires-Dist: cloudpickle (>=3.1.1) ; extra == "dev"
@@ -54,7 +56,6 @@ Requires-Dist: papermill (>=2.4) ; extra == "tests"
54
56
  Requires-Dist: pillow (>=10)
55
57
  Requires-Dist: pre-commit ; extra == "dev"
56
58
  Requires-Dist: pre-commit ; extra == "tests"
57
- Requires-Dist: pydicom (>=2.4)
58
59
  Requires-Dist: pytest (>=8.1) ; extra == "dev"
59
60
  Requires-Dist: pytest (>=8.1) ; extra == "tests"
60
61
  Requires-Dist: pytest-cov ; extra == "dev"
@@ -83,8 +84,8 @@ Requires-Dist: torch ; extra == "backends"
83
84
  Requires-Dist: tqdm (>=4)
84
85
  Requires-Dist: wandb (>=0.18)
85
86
  Requires-Dist: wget (>=3.2)
86
- Project-URL: Homepage, https://github.com/tue-bmd/ultrasound-toolbox/
87
- Project-URL: Repository, https://github.com/tue-bmd/ultrasound-toolbox/
87
+ Project-URL: Homepage, https://github.com/tue-bmd/zea/
88
+ Project-URL: Repository, https://github.com/tue-bmd/zea/
88
89
  Description-Content-Type: text/markdown
89
90
 
90
91
  # zea <img src="https://raw.githubusercontent.com/tue-bmd/zea/main/docs/_static/zea-logo.png" width="120" height="120" align="right" alt="zea Logo" />
@@ -95,8 +96,14 @@ Description-Content-Type: text/markdown
95
96
  [![Documentation Status](https://readthedocs.org/projects/zea/badge/?version=latest)](https://zea.readthedocs.io/en/latest/?badge=latest)
96
97
  [![License](https://img.shields.io/github/license/tue-bmd/zea)](https://github.com/tue-bmd/zea/blob/main/LICENSE)
97
98
  [![codecov](https://codecov.io/gh/tue-bmd/zea/branch/main/graph/badge.svg)](https://codecov.io/gh/tue-bmd/zea)
99
+ [![status](https://joss.theoj.org/papers/fa923917ca41761fe0623ca6c350017d/status.svg)](https://joss.theoj.org/papers/fa923917ca41761fe0623ca6c350017d)
100
+ [![GitHub stars](https://img.shields.io/github/stars/tue-bmd/zea?style=social)](https://github.com/tue-bmd/zea/stargazers)
98
101
 
99
- Welcome to the documentation for the `zea` package: *A Toolbox for Cognitive Ultrasound Imaging.*
102
+ Welcome to the `zea` package: *A Toolbox for Cognitive Ultrasound Imaging.*
103
+
104
+ - 📚 Full documentation: [zea.readthedocs.io](https://zea.readthedocs.io)
105
+ - 🔬 Try hands-on examples (with Colab): [Examples & Tutorials](https://zea.readthedocs.io/en/latest/examples.html)
106
+ - ⚙️ Installation guide: [Installation](https://zea.readthedocs.io/en/latest/installation.html)
100
107
 
101
108
  `zea` is a Python library that offers ultrasound signal processing, image reconstruction, and deep learning. Currently, `zea` offers:
102
109
 
@@ -110,6 +117,5 @@ Welcome to the documentation for the `zea` package: *A Toolbox for Cognitive Ult
110
117
  > This package is highly experimental and under active development. It is mainly used to support [our research](https://www.tue.nl/en/research/research-groups/signal-processing-systems/biomedical-diagnostics-lab) and as a basis for our publications. That being said, we are happy to share it with the ultrasound community and hope it will be useful for your research as well.
111
118
 
112
119
  > [!NOTE]
113
- > 📖 If you use `zea` in your research, please cite our work.
114
- > You can find the citation information by clicking the **"Cite this repository"** button on the top right of this page.
120
+ > 📖 Please cite `zea` in your publications if it helps your research. You can find citation info [here](https://zea.readthedocs.io/en/latest/getting-started.html#citation).
115
121
 
@@ -6,8 +6,14 @@
6
6
  [![Documentation Status](https://readthedocs.org/projects/zea/badge/?version=latest)](https://zea.readthedocs.io/en/latest/?badge=latest)
7
7
  [![License](https://img.shields.io/github/license/tue-bmd/zea)](https://github.com/tue-bmd/zea/blob/main/LICENSE)
8
8
  [![codecov](https://codecov.io/gh/tue-bmd/zea/branch/main/graph/badge.svg)](https://codecov.io/gh/tue-bmd/zea)
9
+ [![status](https://joss.theoj.org/papers/fa923917ca41761fe0623ca6c350017d/status.svg)](https://joss.theoj.org/papers/fa923917ca41761fe0623ca6c350017d)
10
+ [![GitHub stars](https://img.shields.io/github/stars/tue-bmd/zea?style=social)](https://github.com/tue-bmd/zea/stargazers)
9
11
 
10
- Welcome to the documentation for the `zea` package: *A Toolbox for Cognitive Ultrasound Imaging.*
12
+ Welcome to the `zea` package: *A Toolbox for Cognitive Ultrasound Imaging.*
13
+
14
+ - 📚 Full documentation: [zea.readthedocs.io](https://zea.readthedocs.io)
15
+ - 🔬 Try hands-on examples (with Colab): [Examples & Tutorials](https://zea.readthedocs.io/en/latest/examples.html)
16
+ - ⚙️ Installation guide: [Installation](https://zea.readthedocs.io/en/latest/installation.html)
11
17
 
12
18
  `zea` is a Python library that offers ultrasound signal processing, image reconstruction, and deep learning. Currently, `zea` offers:
13
19
 
@@ -21,5 +27,4 @@ Welcome to the documentation for the `zea` package: *A Toolbox for Cognitive Ult
21
27
  > This package is highly experimental and under active development. It is mainly used to support [our research](https://www.tue.nl/en/research/research-groups/signal-processing-systems/biomedical-diagnostics-lab) and as a basis for our publications. That being said, we are happy to share it with the ultrasound community and hope it will be useful for your research as well.
22
28
 
23
29
  > [!NOTE]
24
- > 📖 If you use `zea` in your research, please cite our work.
25
- > You can find the citation information by clicking the **"Cite this repository"** button on the top right of this page.
30
+ > 📖 Please cite `zea` in your publications if it helps your research. You can find citation info [here](https://zea.readthedocs.io/en/latest/getting-started.html#citation).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zea"
3
- version = "0.0.2"
3
+ version = "0.0.4"
4
4
  description = "A Toolbox for Cognitive Ultrasound Imaging. Provides a set of tools for processing of ultrasound data, all built in your favorite machine learning framework."
5
5
  authors = [
6
6
  { name = "Tristan Stevens", email = "t.s.w.stevens@tue.nl" },
@@ -43,7 +43,6 @@ dependencies = [
43
43
  "wandb >=0.18",
44
44
  "wget >=3.2",
45
45
  # can we make these optional or remove?
46
- "pydicom >=2.4",
47
46
  "scikit-image >=0.23",
48
47
  "scikit-learn >=1.4",
49
48
  ]
@@ -70,6 +69,7 @@ dev = [
70
69
  "nbsphinx",
71
70
  "furo",
72
71
  "PyStemmer",
72
+ "IPython",
73
73
  # display
74
74
  "opencv-python-headless>=4",
75
75
  ]
@@ -96,6 +96,7 @@ docs = [
96
96
  "nbsphinx",
97
97
  "furo",
98
98
  "PyStemmer",
99
+ "IPython",
99
100
  ]
100
101
  jax = [
101
102
  "jax[cuda12_pip]>=0.4.26"
@@ -112,8 +113,8 @@ display-headless = [
112
113
  backends = ["jax", "tensorflow", "torch"]
113
114
 
114
115
  [project.urls]
115
- Homepage = "https://github.com/tue-bmd/ultrasound-toolbox/"
116
- Repository = "https://github.com/tue-bmd/ultrasound-toolbox/"
116
+ Homepage = "https://github.com/tue-bmd/zea/"
117
+ Repository = "https://github.com/tue-bmd/zea/"
117
118
 
118
119
  [project.scripts]
119
120
  zea = "zea.__main__:main"
@@ -7,7 +7,7 @@ from . import log
7
7
 
8
8
  # dynamically add __version__ attribute (see pyproject.toml)
9
9
  # __version__ = __import__("importlib.metadata").metadata.version(__package__)
10
- __version__ = "0.0.2"
10
+ __version__ = "0.0.4"
11
11
 
12
12
 
13
13
  def setup():
@@ -92,6 +92,7 @@ class GreedyEntropy(LinesActionModel):
92
92
  mean: float = 0,
93
93
  std_dev: float = 1,
94
94
  num_lines_to_update: int = 5,
95
+ entropy_sigma: float = 1.0,
95
96
  ):
96
97
  """Initialize the GreedyEntropy action selection model.
97
98
 
@@ -104,6 +105,8 @@ class GreedyEntropy(LinesActionModel):
104
105
  std_dev (float, optional): The standard deviation of the RBF. Defaults to 1.
105
106
  num_lines_to_update (int, optional): The number of lines around the selected line
106
107
  to update. Must be odd.
108
+ entropy_sigma (float, optional): The standard deviation of the Gaussian
109
+ Mixture components used to approximate the posterior.
107
110
  """
108
111
  super().__init__(n_actions, n_possible_actions, img_width, img_height)
109
112
 
@@ -124,7 +127,7 @@ class GreedyEntropy(LinesActionModel):
124
127
  self.num_lines_to_update,
125
128
  )
126
129
  self.upside_down_gaussian = upside_down_gaussian(points_to_evaluate)
127
- self.entropy_sigma = 1
130
+ self.entropy_sigma = entropy_sigma
128
131
 
129
132
  @staticmethod
130
133
  def compute_pairwise_pixel_gaussian_error(
@@ -152,51 +155,58 @@ class GreedyEntropy(LinesActionModel):
152
155
  # TODO: I think we only need to compute the lower triangular
153
156
  # of this matrix, since it's symmetric
154
157
  squared_l2_error_matrices = (particles[:, :, None, ...] - particles[:, None, :, ...]) ** 2
155
- gaussian_error_per_pixel_i_j = ops.exp((squared_l2_error_matrices) / (2 * entropy_sigma**2))
158
+ gaussian_error_per_pixel_i_j = ops.exp(
159
+ -(squared_l2_error_matrices) / (2 * entropy_sigma**2)
160
+ )
156
161
  # Vertically stack all columns corresponding with the same line
157
162
  # This way we can just sum across the height axis and get the entropy
158
163
  # for each pixel in a given line
159
164
  batch_size, n_particles, _, height, _ = gaussian_error_per_pixel_i_j.shape
160
- gaussian_error_per_pixel_stacked = ops.reshape(
161
- gaussian_error_per_pixel_i_j,
162
- [
163
- batch_size,
164
- n_particles,
165
- n_particles,
166
- height * stack_n_cols,
167
- n_possible_actions,
168
- ],
165
+ gaussian_error_per_pixel_stacked = ops.transpose(
166
+ ops.reshape(
167
+ ops.transpose(gaussian_error_per_pixel_i_j, (0, 1, 2, 4, 3)),
168
+ [
169
+ batch_size,
170
+ n_particles,
171
+ n_particles,
172
+ n_possible_actions,
173
+ height * stack_n_cols,
174
+ ],
175
+ ),
176
+ (0, 1, 2, 4, 3),
169
177
  )
170
178
  # [n_particles, n_particles, batch, height, width]
171
179
  return gaussian_error_per_pixel_stacked
172
180
 
173
- def compute_gmm_entropy_per_line(self, particles):
174
- """Compute the entropy for each line using a Gaussian Mixture Model.
175
-
181
+ def compute_pixelwise_entropy(self, particles):
182
+ """
176
183
  This function computes the entropy for each line using a Gaussian Mixture Model
177
184
  approximation of the posterior distribution.
178
- For more details see Section 4 here: https://arxiv.org/abs/2406.14388
185
+ For more details see Section VI. B here: https://arxiv.org/pdf/2410.13310
179
186
 
180
187
  Args:
181
188
  particles (Tensor): Particles of shape (batch_size, n_particles, height, width)
182
189
 
183
190
  Returns:
184
- Tensor: batch of entropies per line, of shape (batch, n_possible_actions)
191
+ Tensor: batch of entropies per pixel, of shape (batch, height, width)
185
192
  """
186
- gaussian_error_per_pixel_stacked = GreedyEntropy.compute_pairwise_pixel_gaussian_error(
193
+ n_particles = ops.shape(particles)[1]
194
+ gaussian_error_per_pixel_stacked = self.compute_pairwise_pixel_gaussian_error(
187
195
  particles,
188
196
  self.stack_n_cols,
189
197
  self.n_possible_actions,
190
198
  self.entropy_sigma,
191
199
  )
192
- gaussian_error_per_line = ops.sum(gaussian_error_per_pixel_stacked, axis=3)
193
200
  # sum out first dimension of (n_particles x n_particles) error matrix
194
- # [n_particles, batch, n_possible_actions]
195
- entropy_per_line_i = ops.sum(gaussian_error_per_line, axis=1)
201
+ # [n_particles, batch, height, width]
202
+ pixelwise_entropy_sum_j = ops.sum(
203
+ (1 / n_particles) * gaussian_error_per_pixel_stacked, axis=1
204
+ )
205
+ log_pixelwise_entropy_sum_j = ops.log(pixelwise_entropy_sum_j)
196
206
  # sum out second dimension of (n_particles x n_particles) error matrix
197
- # [batch, n_possible_actions]
198
- entropy_per_line = ops.sum(entropy_per_line_i, axis=1)
199
- return entropy_per_line
207
+ # [batch, height, width]
208
+ pixelwise_entropy = -ops.sum((1 / n_particles) * log_pixelwise_entropy_sum_j, axis=1)
209
+ return pixelwise_entropy
200
210
 
201
211
  def select_line_and_reweight_entropy(self, entropy_per_line):
202
212
  """Select the line with maximum entropy and reweight the entropies.
@@ -254,17 +264,19 @@ class GreedyEntropy(LinesActionModel):
254
264
  particles (Tensor): Particles of shape (batch_size, n_particles, height, width)
255
265
 
256
266
  Returns:
257
- Tuple[Tensor, Tensor]:
267
+ Tuple[Tensor, Tensor]:
258
268
  - Newly selected lines as k-hot vectors, shaped (batch_size, n_possible_actions)
259
- - Masks of shape (batch_size, img_height, img_width)
269
+ - Masks of shape (batch_size, img_height, img_width)
260
270
  """
261
- entropy_per_line = self.compute_gmm_entropy_per_line(particles)
271
+
272
+ pixelwise_entropy = self.compute_pixelwise_entropy(particles)
273
+ linewise_entropy = ops.sum(pixelwise_entropy, axis=1)
262
274
 
263
275
  # Greedily select best line, reweight entropies, and repeat
264
276
  all_selected_lines = []
265
277
  for _ in range(self.n_actions):
266
- max_entropy_line, entropy_per_line = ops.vectorized_map(
267
- self.select_line_and_reweight_entropy, entropy_per_line
278
+ max_entropy_line, linewise_entropy = ops.vectorized_map(
279
+ self.select_line_and_reweight_entropy, linewise_entropy
268
280
  )
269
281
  all_selected_lines.append(max_entropy_line)
270
282
 
@@ -428,10 +440,15 @@ class CovarianceSamplingLines(LinesActionModel):
428
440
  generation. Defaults to None.
429
441
 
430
442
  Returns:
431
- Tensor: The mask of shape (batch_size, img_size, img_size)
443
+ Tuple[Tensor, Tensor]:
444
+ - Newly selected lines as k-hot vectors, shaped (batch_size, n_possible_actions)
445
+ - Masks of shape (batch_size, img_height, img_width)
432
446
  """
433
447
  batch_size, n_particles, rows, _ = ops.shape(particles)
434
448
 
449
+ # [batch_size, rows, cols, n_particles]
450
+ particles = ops.transpose(particles, (0, 2, 3, 1))
451
+
435
452
  # [batch_size, rows * stack_n_cols, n_possible_actions, n_particles]
436
453
  shape = [
437
454
  batch_size,
@@ -441,7 +458,7 @@ class CovarianceSamplingLines(LinesActionModel):
441
458
  ]
442
459
  particles = ops.reshape(particles, shape)
443
460
 
444
- # [batch_size, rows, n_possible_actions, n_possible_actions]
461
+ # [batch_size, rows * stack_n_cols, n_possible_actions, n_possible_actions]
445
462
  cov_matrix = tensor_ops.batch_cov(particles)
446
463
 
447
464
  # Sum over the row dimension [batch_size, n_possible_actions, n_possible_actions]
@@ -1,4 +1,4 @@
1
- """Backend subpackage for ``zea``.
1
+ """Backend-specific utilities.
2
2
 
3
3
  This subpackage provides backend-specific utilities for the ``zea`` library. Most backend logic is handled by Keras 3, but a few features require custom wrappers to ensure compatibility and performance across JAX, TensorFlow, and PyTorch.
4
4
 
@@ -9,7 +9,7 @@ Key Features
9
9
  ------------
10
10
 
11
11
  - **JIT Compilation** (:func:`zea.backend.jit`):
12
- Provides a unified interface for just-in-time (JIT) compilation of functions, dispatching to the appropriate backend (JAX or TensorFlow) as needed. This enables accelerated execution of computationally intensive routines.
12
+ Provides a unified interface for just-in-time (JIT) compilation of functions, dispatching to the appropriate backend (JAX or TensorFlow) as needed. This enables accelerated execution of computationally intensive routines. Note that jit compilation is not yet supported when using the `torch` backend.
13
13
 
14
14
  - **Automatic Differentiation** (:class:`zea.backend.AutoGrad`):
15
15
  Offers a backend-agnostic wrapper for automatic differentiation, allowing gradient computation regardless of the underlying ML library.
@@ -108,7 +108,9 @@ def _jit_compile(func, jax=True, tensorflow=True, **kwargs):
108
108
  return func
109
109
  else:
110
110
  log.warning(
111
- f"Unsupported backend: {backend}. Supported backends are 'tensorflow' and 'jax'."
111
+ f"JIT compilation not currently supported for backend {backend}. "
112
+ "Supported backends are 'tensorflow' and 'jax'."
112
113
  )
114
+ log.warning("Initialize zea.Pipeline with jit_options=None to suppress this warning.")
113
115
  log.warning("Falling back to non-compiled mode.")
114
116
  return func
@@ -17,4 +17,4 @@ see the pipeline example notebook: :doc:`../notebooks/pipeline/zea_pipeline_exam
17
17
 
18
18
  """
19
19
 
20
- from . import beamformer, delays, lens_correction, pfield, pixelgrid
20
+ from . import beamformer, delays, lens_correction, pfield, phantoms, pixelgrid
@@ -1,5 +1,6 @@
1
1
  """Main beamforming functions for ultrasound imaging."""
2
2
 
3
+ import keras
3
4
  import numpy as np
4
5
  from keras import ops
5
6
 
@@ -58,7 +59,7 @@ def tof_correction(
58
59
  demodulation_frequency,
59
60
  fnum,
60
61
  angles,
61
- vfocus,
62
+ focus_distances,
62
63
  apply_phase_rotation=False,
63
64
  apply_lens_correction=False,
64
65
  lens_thickness=1e-3,
@@ -84,7 +85,7 @@ def tof_correction(
84
85
  fnum (int, optional): Focus number. Defaults to 1.
85
86
  angles (ops.Tensor): The angles of the plane waves in radians of shape
86
87
  `(n_tx,)`
87
- vfocus (ops.Tensor): The focus distance of shape `(n_tx,)`
88
+ focus_distances (ops.Tensor): The focus distance of shape `(n_tx,)`
88
89
  apply_phase_rotation (bool, optional): Whether to apply phase rotation to
89
90
  time-of-flights. Defaults to False.
90
91
  apply_lens_correction (bool, optional): Whether to apply lens correction to
@@ -133,7 +134,7 @@ def tof_correction(
133
134
  sound_speed,
134
135
  n_tx,
135
136
  n_el,
136
- vfocus,
137
+ focus_distances,
137
138
  angles,
138
139
  lens_thickness=lens_thickness,
139
140
  lens_sound_speed=lens_sound_speed,
@@ -487,7 +488,7 @@ def fnumber_mask(flatgrid, probe_geometry, f_number, fnum_window_fn):
487
488
  # The f-number is fnum = z/aperture = 1/(2 * tan(alpha))
488
489
  # Rearranging gives us alpha = arctan(1/(2 * fnum))
489
490
  # We can use this to compute the maximum angle alpha that is allowed
490
- max_alpha = ops.arctan(1 / (2 * f_number))
491
+ max_alpha = ops.arctan(1 / (2 * f_number + keras.backend.epsilon()))
491
492
 
492
493
  normalized_angle = alpha / max_alpha
493
494
  mask = fnum_window_fn(normalized_angle)
@@ -60,7 +60,8 @@ def compute_pfield(
60
60
  n_el (int): Number of elements in the probe.
61
61
  probe_geometry (array): Geometry of the probe elements.
62
62
  tx_apodizations (array): Transmit apodization values.
63
- grid (array): Grid points where the pressure field is computed of shape (Nz, Nx, 3).
63
+ grid (array): Grid points where the pressure field is computed
64
+ of shape (grid_size_z, grid_size_x, 3).
64
65
  t0_delays (array): Transmit delays for each transmit event.
65
66
  frequency_step (int, optional): Frequency step. Default is 4.
66
67
  Higher is faster but less accurate.
@@ -78,7 +79,8 @@ def compute_pfield(
78
79
  verbose (bool, optional): Whether to print progress.
79
80
 
80
81
  Returns:
81
- ops.array: The (normalized) pressure field (across tx events) of shape (n_tx, Nz, Nx).
82
+ ops.array: The (normalized) pressure field (across tx events)
83
+ of shape (n_tx, grid_size_z, grid_size_x).
82
84
  """
83
85
  # medium params
84
86
  alpha_db = 0 # currently we ignore attenuation in the compounding
@@ -293,7 +295,8 @@ def normalize_pressure_field(pfield, alpha: float = 1.0, percentile: float = 10.
293
295
  Normalize the input array of intensities by zeroing out values below a given percentile.
294
296
 
295
297
  Args:
296
- pfield (array): The unnormalized pressure field array of shape (n_tx, Nz, Nx).
298
+ pfield (array): The unnormalized pressure field array
299
+ of shape (n_tx, grid_size_z, grid_size_x).
297
300
  alpha (float, optional): Exponent to 'sharpen or smooth' the weighting.
298
301
  Higher values result in sharper weighting. Default is 1.0.
299
302
  percentile (int, optional): minimum percentile threshold to keep in the weighting.
@@ -16,52 +16,52 @@ def check_for_aliasing(scan):
16
16
  depth = scan.zlims[1] - scan.zlims[0]
17
17
  wvln = scan.wavelength
18
18
 
19
- if width / scan.Nx > wvln / 2:
19
+ if width / scan.grid_size_x > wvln / 2:
20
20
  log.warning(
21
- f"width/Nx = {width / scan.Nx:.7f} < wavelength/2 = {wvln / 2}. "
22
- f"Consider either increasing scan.Nx to {int(np.ceil(width / (wvln / 2)))} or more, or "
23
- "increasing scan.pixels_per_wavelength to 2 or more."
21
+ f"width/grid_size_x = {width / scan.grid_size_x:.7f} < wavelength/2 = {wvln / 2}. "
22
+ f"Consider either increasing scan.grid_size_x to {int(np.ceil(width / (wvln / 2)))} "
23
+ "or more, or increasing scan.pixels_per_wavelength to 2 or more."
24
24
  )
25
- if depth / scan.Nz > wvln / 2:
25
+ if depth / scan.grid_size_z > wvln / 2:
26
26
  log.warning(
27
- f"depth/Nz = {depth / scan.Nz:.7f} < wavelength/2 = {wvln / 2:.7f}. "
28
- f"Consider either increasing scan.Nz to {int(np.ceil(depth / (wvln / 2)))} or more, or "
29
- "increasing scan.pixels_per_wavelength to 2 or more."
27
+ f"depth/grid_size_z = {depth / scan.grid_size_z:.7f} < wavelength/2 = {wvln / 2:.7f}. "
28
+ f"Consider either increasing scan.grid_size_z to {int(np.ceil(depth / (wvln / 2)))} "
29
+ "or more, or increasing scan.pixels_per_wavelength to 2 or more."
30
30
  )
31
31
 
32
32
 
33
- def cartesian_pixel_grid(xlims, zlims, Nx=None, Nz=None, dx=None, dz=None):
33
+ def cartesian_pixel_grid(xlims, zlims, grid_size_x=None, grid_size_z=None, dx=None, dz=None):
34
34
  """Generate a Cartesian pixel grid based on input parameters.
35
35
 
36
36
  Args:
37
37
  xlims (tuple): Azimuthal limits of pixel grid ([xmin, xmax])
38
38
  zlims (tuple): Depth limits of pixel grid ([zmin, zmax])
39
- Nx (int): Number of azimuthal pixels, overrides dx and dz parameters
40
- Nz (int): Number of depth pixels, overrides dx and dz parameters
39
+ grid_size_x (int): Number of azimuthal pixels, overrides dx and dz parameters
40
+ grid_size_z (int): Number of depth pixels, overrides dx and dz parameters
41
41
  dx (float): Pixel spacing in azimuth
42
42
  dz (float): Pixel spacing in depth
43
43
 
44
44
  Raises:
45
- ValueError: Either Nx and Nz or dx and dz must be defined.
45
+ ValueError: Either grid_size_x and grid_size_z or dx and dz must be defined.
46
46
 
47
47
  Returns:
48
- grid (np.ndarray): Pixel grid of size (nz, nx, 3) in
48
+ grid (np.ndarray): Pixel grid of size (grid_size_z, nx, 3) in
49
49
  Cartesian coordinates (x, y, z)
50
50
  """
51
- assert (bool(Nx) and bool(Nz)) ^ (bool(dx) and bool(dz)), (
52
- "Either Nx and Nz or dx and dz must be defined."
51
+ assert (bool(grid_size_x) and bool(grid_size_z)) ^ (bool(dx) and bool(dz)), (
52
+ "Either grid_size_x and grid_size_z or dx and dz must be defined."
53
53
  )
54
54
 
55
55
  # Determine the grid spacing
56
- if Nx is not None and Nz is not None:
57
- x = np.linspace(xlims[0], xlims[1] + eps, Nx)
58
- z = np.linspace(zlims[0], zlims[1] + eps, Nz)
56
+ if grid_size_x is not None and grid_size_z is not None:
57
+ x = np.linspace(xlims[0], xlims[1] + eps, grid_size_x)
58
+ z = np.linspace(zlims[0], zlims[1] + eps, grid_size_z)
59
59
  elif dx is not None and dz is not None:
60
60
  sign = np.sign(xlims[1] - xlims[0])
61
61
  x = np.arange(xlims[0], xlims[1] + eps, sign * dx)
62
62
  z = np.arange(zlims[0], zlims[1] + eps, sign * dz)
63
63
  else:
64
- raise ValueError("Either Nx and Nz or dx and dz must be defined.")
64
+ raise ValueError("Either grid_size_x and grid_size_z or dx and dz must be defined.")
65
65
 
66
66
  # Create the pixel grid
67
67
  z_grid, x_grid = np.meshgrid(z, x, indexing="ij")
@@ -102,29 +102,30 @@ def radial_pixel_grid(rlims, dr, oris, dirs):
102
102
  return grid
103
103
 
104
104
 
105
- def polar_pixel_grid(polar_limits, zlims, Nz: int, Nr: int):
105
+ def polar_pixel_grid(polar_limits, zlims, num_radial_pixels: int, num_polar_pixels: int):
106
106
  """Generate a polar grid.
107
107
 
108
108
  Uses radial_pixel_grid but based on parameters that are present in the scan class.
109
109
 
110
110
  Args:
111
- polar_limits (tuple): Azimuthal limits of pixel grid ([azimuth_min, azimuth_max])
111
+ polar_limits (tuple): Polar limits of pixel grid ([polar_min, polar_max])
112
112
  zlims (tuple): Depth limits of pixel grid ([zmin, zmax])
113
- Nz (int, optional): Number of depth pixels.
114
- Nr (int, optional): Number of azimuthal pixels.
113
+ num_radial_pixels (int, optional): Number of depth pixels.
114
+ num_polar_pixels (int, optional): Number of polar pixels.
115
115
 
116
116
  Returns:
117
- grid (np.ndarray): Pixel grid of size (Nz, Nr, 3) in Cartesian coordinates (x, y, z)
117
+ grid (np.ndarray): Pixel grid of size (num_radial_pixels, num_polar_pixels, 3)
118
+ in Cartesian coordinates (x, y, z)
118
119
  """
119
120
  assert len(polar_limits) == 2, "polar_limits must be a tuple of length 2."
120
121
  assert len(zlims) == 2, "zlims must be a tuple of length 2."
121
122
 
122
- dr = (zlims[1] - zlims[0]) / Nz
123
+ dr = (zlims[1] - zlims[0]) / num_radial_pixels
123
124
 
124
125
  oris = np.array([0, 0, 0])
125
- oris = np.tile(oris, (Nr, 1))
126
- dirs_az = np.linspace(*polar_limits, Nr)
126
+ oris = np.tile(oris, (num_polar_pixels, 1))
127
+ dirs_az = np.linspace(*polar_limits, num_polar_pixels)
127
128
 
128
- dirs_el = np.zeros(Nr)
129
+ dirs_el = np.zeros(num_polar_pixels)
129
130
  dirs = np.vstack((dirs_az, dirs_el)).T
130
131
  return radial_pixel_grid(zlims, dr, oris, dirs).transpose(1, 0, 2)
@@ -47,8 +47,9 @@ import yaml
47
47
  from huggingface_hub import hf_hub_download
48
48
 
49
49
  from zea import log
50
+ from zea.data.preset_utils import HF_PREFIX, _hf_resolve_path
50
51
  from zea.internal.config.validation import config_schema
51
- from zea.internal.core import object_to_tensor
52
+ from zea.internal.core import dict_to_tensor
52
53
 
53
54
 
54
55
  class Config(dict):
@@ -430,8 +431,22 @@ class Config(dict):
430
431
  v._recursive_setattr(set_key, set_value)
431
432
 
432
433
  @classmethod
433
- def from_yaml(cls, path, **kwargs):
434
- """Load config object from yaml file"""
434
+ def from_path(cls, path, **kwargs):
435
+ """Load config object from a file path.
436
+
437
+ Args:
438
+ path (str or Path): The path to the config file.
439
+ Can be a string or a Path object. Additionally can be a string with
440
+ the prefix 'hf://', in which case it will be resolved to a
441
+ huggingface path.
442
+
443
+ Returns:
444
+ Config: config object.
445
+ """
446
+ if str(path).startswith(HF_PREFIX):
447
+ path = _hf_resolve_path(str(path))
448
+ if isinstance(path, str):
449
+ path = Path(path)
435
450
  return _load_config_from_yaml(path, config_class=cls, **kwargs)
436
451
 
437
452
  @classmethod
@@ -460,9 +475,14 @@ class Config(dict):
460
475
  local_path = hf_hub_download(repo_id, path, **kwargs)
461
476
  return _load_config_from_yaml(local_path, config_class=cls)
462
477
 
463
- def to_tensor(self):
478
+ @classmethod
479
+ def from_yaml(cls, path, **kwargs):
480
+ """Load config object from yaml file."""
481
+ return cls.from_path(path, **kwargs)
482
+
483
+ def to_tensor(self, keep_as_is=None):
464
484
  """Convert the attributes in the object to keras tensors"""
465
- return object_to_tensor(self)
485
+ return dict_to_tensor(self.serialize(), keep_as_is=keep_as_is)
466
486
 
467
487
 
468
488
  def check_config(config: Union[dict, Config], verbose: bool = False):