zea 0.0.6__py3-none-any.whl → 0.0.7__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 (61) hide show
  1. zea/__init__.py +54 -19
  2. zea/agent/__init__.py +12 -12
  3. zea/agent/masks.py +2 -1
  4. zea/backend/tensorflow/dataloader.py +2 -1
  5. zea/beamform/beamformer.py +100 -50
  6. zea/beamform/lens_correction.py +9 -2
  7. zea/beamform/pfield.py +9 -2
  8. zea/config.py +34 -25
  9. zea/data/__init__.py +22 -16
  10. zea/data/convert/camus.py +2 -1
  11. zea/data/convert/echonet.py +4 -4
  12. zea/data/convert/echonetlvh/convert_raw_to_usbmd.py +1 -1
  13. zea/data/convert/matlab.py +11 -4
  14. zea/data/data_format.py +31 -30
  15. zea/data/datasets.py +7 -5
  16. zea/data/file.py +104 -2
  17. zea/data/layers.py +3 -3
  18. zea/datapaths.py +16 -4
  19. zea/display.py +7 -5
  20. zea/interface.py +14 -16
  21. zea/internal/_generate_keras_ops.py +6 -7
  22. zea/internal/cache.py +2 -49
  23. zea/internal/config/validation.py +1 -2
  24. zea/internal/core.py +69 -6
  25. zea/internal/device.py +6 -2
  26. zea/internal/dummy_scan.py +330 -0
  27. zea/internal/operators.py +114 -2
  28. zea/internal/parameters.py +101 -70
  29. zea/internal/setup_zea.py +5 -6
  30. zea/internal/utils.py +282 -0
  31. zea/io_lib.py +247 -19
  32. zea/keras_ops.py +74 -4
  33. zea/log.py +9 -7
  34. zea/metrics.py +15 -7
  35. zea/models/__init__.py +30 -20
  36. zea/models/base.py +30 -14
  37. zea/models/carotid_segmenter.py +19 -4
  38. zea/models/diffusion.py +173 -12
  39. zea/models/echonet.py +22 -8
  40. zea/models/echonetlvh.py +31 -7
  41. zea/models/lpips.py +19 -2
  42. zea/models/lv_segmentation.py +28 -11
  43. zea/models/preset_utils.py +5 -5
  44. zea/models/regional_quality.py +30 -10
  45. zea/models/taesd.py +21 -5
  46. zea/models/unet.py +15 -1
  47. zea/ops.py +390 -196
  48. zea/probes.py +6 -6
  49. zea/scan.py +109 -49
  50. zea/simulator.py +24 -21
  51. zea/tensor_ops.py +406 -302
  52. zea/tools/hf.py +1 -1
  53. zea/tools/selection_tool.py +47 -86
  54. zea/utils.py +92 -480
  55. zea/visualize.py +177 -39
  56. {zea-0.0.6.dist-info → zea-0.0.7.dist-info}/METADATA +4 -2
  57. zea-0.0.7.dist-info/RECORD +114 -0
  58. zea-0.0.6.dist-info/RECORD +0 -112
  59. {zea-0.0.6.dist-info → zea-0.0.7.dist-info}/WHEEL +0 -0
  60. {zea-0.0.6.dist-info → zea-0.0.7.dist-info}/entry_points.txt +0 -0
  61. {zea-0.0.6.dist-info → zea-0.0.7.dist-info}/licenses/LICENSE +0 -0
zea/tools/hf.py CHANGED
@@ -41,7 +41,7 @@ def load_model_from_hf(repo_id, revision="main", verbose=True):
41
41
  if verbose:
42
42
  log.info(
43
43
  log.yellow(
44
- f"Succesfully loaded model {commit_message} from "
44
+ f"Successfully loaded model {commit_message} from "
45
45
  f"'https://huggingface.co/{repo_id}'. Last updated on {commit_time}."
46
46
  )
47
47
  )
@@ -17,19 +17,20 @@ Key Features
17
17
 
18
18
  Example
19
19
  -------
20
- .. code-block:: python
21
20
 
22
- import matplotlib.pyplot as plt
23
- from zea.tools.selection_tool import interactive_selector
21
+ .. doctest::
24
22
 
25
- image = ... # Load your 2D image array
26
- fig, ax = plt.subplots()
27
- ax.imshow(image, cmap="gray")
28
- patches, masks = interactive_selector(image, ax, selector="rectangle")
23
+ >>> import matplotlib.pyplot as plt
24
+ >>> import numpy as np
25
+ >>> from zea.tools.selection_tool import interactive_selector
26
+
27
+ >>> image = np.zeros((100, 100)) # Load your 2D image array
28
+ >>> fig, ax = plt.subplots()
29
+ >>> _ = ax.imshow(image, cmap="gray")
30
+ >>> patches, masks = interactive_selector(image, ax, selector="rectangle") # doctest: +SKIP
29
31
 
30
32
  """
31
33
 
32
- import tkinter as tk
33
34
  from collections.abc import Iterable
34
35
  from pathlib import Path
35
36
  from typing import Union
@@ -43,7 +44,6 @@ from matplotlib.path import Path as pltPath
43
44
  from matplotlib.widgets import LassoSelector, RectangleSelector
44
45
  from PIL import Image, ImageDraw
45
46
  from scipy.interpolate import interp1d
46
- from skimage import measure
47
47
  from skimage.measure import approximate_polygon, find_contours
48
48
  from sklearn.metrics import pairwise_distances
49
49
 
@@ -55,7 +55,8 @@ from zea.internal.viewer import (
55
55
  )
56
56
  from zea.io_lib import _SUPPORTED_VID_TYPES, load_image, load_video
57
57
  from zea.metrics import get_metric
58
- from zea.utils import translate
58
+ from zea.tensor_ops import translate
59
+ from zea.visualize import plot_rectangle_from_mask, plot_shape_from_mask
59
60
 
60
61
 
61
62
  def crop_array(array, value=None):
@@ -180,16 +181,30 @@ def interactive_selector(
180
181
  for mask in masks:
181
182
  patches.append(crop_array(data * mask, value=0))
182
183
 
183
- like_selection = not bool(confirm_selection)
184
+ # Early return if no confirmation is required
185
+ if not confirm_selection:
186
+ return patches, masks
187
+
188
+ try:
189
+ from tkinter import Tk, messagebox
190
+ except ImportError as e:
191
+ raise ImportError(
192
+ log.error("Failed to import tkinter. Please install it with 'apt install python3-tk'.")
193
+ ) from e
194
+
195
+ # Create root window once for messagebox dialogs
196
+ root = Tk()
197
+ root.withdraw()
184
198
 
199
+ like_selection = False
185
200
  while not like_selection:
186
201
  print(f"You have made {len(patches)} selection(s).")
187
202
  # draw masks on top of data
188
- for mask in masks:
189
- add_shape_from_mask(ax, mask, alpha=0.5)
203
+ for current_mask in masks:
204
+ plot_shape_from_mask(ax, current_mask, alpha=0.5)
190
205
  plt.draw()
191
- # tkinter yes / no dialog
192
- like_selection = tk.messagebox.askyesno("Like Selection", "Do you like your selection?")
206
+
207
+ like_selection = messagebox.askyesno("Like Selection", "Do you like your selection?")
193
208
 
194
209
  if not like_selection:
195
210
  remove_masks_from_axs(ax)
@@ -199,68 +214,12 @@ def interactive_selector(
199
214
  _execute_selector()
200
215
 
201
216
  patches = []
202
- for mask in masks:
203
- patches.append(crop_array(data * mask, value=0))
204
-
205
- return patches, masks
206
-
207
-
208
- def add_rectangle_from_mask(ax, mask, **kwargs):
209
- """add a rectangle box to axis from mask array.
210
-
211
- Args:
212
- ax (plt.ax): matplotlib axis
213
- mask (ndarray): numpy array with rectangle non-zero
214
- box defining the region of interest.
215
- Kwargs:
216
- edgecolor (str): color of the shape's edge
217
- facecolor (str): color of the shape's face
218
- linewidth (int): width of the shape's edge
217
+ for current_mask in masks:
218
+ patches.append(crop_array(data * current_mask, value=0))
219
219
 
220
- Returns:
221
- plt.ax: matplotlib axis with rectangle added
222
- """
223
- # Create a Rectangle patch
224
- y1, y2 = np.where(np.diff(mask, axis=0).sum(axis=1))[0]
225
- x1, x2 = np.where(np.diff(mask, axis=1).sum(axis=0))[0]
226
- rect = Rectangle(
227
- (x1, y1),
228
- (x2 - x1),
229
- (y2 - y1),
230
- **kwargs,
231
- )
232
-
233
- # Add the patch to the Axes
234
- rect_obj = ax.add_patch(rect)
235
- return rect_obj
220
+ root.destroy()
236
221
 
237
-
238
- def add_shape_from_mask(ax, mask, **kwargs):
239
- """add a shape to axis from mask array.
240
-
241
- Args:
242
- ax (plt.ax): matplotlib axis
243
- mask (ndarray): numpy array with non-zero
244
- shape defining the region of interest.
245
- Kwargs:
246
- edgecolor (str): color of the shape's edge
247
- facecolor (str): color of the shape's face
248
- linewidth (int): width of the shape's edge
249
-
250
- Returns:
251
- plt.ax: matplotlib axis with shape added
252
- """
253
- # Pad mask to ensure edge contours are found
254
- padded_mask = np.pad(mask, pad_width=1, mode="constant", constant_values=0)
255
- contours = measure.find_contours(padded_mask, 0.5)
256
- patches = []
257
- for contour in contours:
258
- # Remove padding offset
259
- contour -= 1
260
- path = pltPath(contour[:, ::-1])
261
- patch = PathPatch(path, **kwargs)
262
- patches.append(ax.add_patch(patch))
263
- return patches
222
+ return patches, masks
264
223
 
265
224
 
266
225
  def interactive_selector_with_plot_and_metric(
@@ -334,9 +293,9 @@ def interactive_selector_with_plot_and_metric(
334
293
  _ax.set_title(title + "\n" + f"{metric}: {score:.3f}")
335
294
  for mask in masks:
336
295
  if selector == "rectangle":
337
- add_rectangle_from_mask(_ax, mask, alpha=0.5)
296
+ plot_rectangle_from_mask(_ax, mask, alpha=0.5)
338
297
  else:
339
- add_shape_from_mask(_ax, mask, alpha=0.5)
298
+ plot_shape_from_mask(_ax, mask, alpha=0.5)
340
299
  plt.tight_layout()
341
300
 
342
301
  # plot patches and masks
@@ -350,7 +309,7 @@ def interactive_selector_with_plot_and_metric(
350
309
  ax_new[2].imshow(mask, aspect="auto")
351
310
 
352
311
  if selector == "rectangle":
353
- add_rectangle_from_mask(ax_base, mask)
312
+ plot_rectangle_from_mask(ax_base, mask)
354
313
 
355
314
  for _ax in ax_new:
356
315
  _ax.axis("off")
@@ -723,9 +682,9 @@ def update_imshow_with_mask(
723
682
  imshow_obj.set_array(images[frame_no])
724
683
  remove_masks_from_axs(axs)
725
684
  if selector == "rectangle":
726
- mask_obj = add_rectangle_from_mask(axs, masks[frame_no])
685
+ mask_obj = plot_rectangle_from_mask(axs, masks[frame_no])
727
686
  else:
728
- mask_obj = add_shape_from_mask(axs, masks[frame_no], alpha=0.5)
687
+ mask_obj = plot_shape_from_mask(axs, masks[frame_no], alpha=0.5)
729
688
  return imshow_obj, mask_obj
730
689
 
731
690
 
@@ -821,9 +780,9 @@ def main():
821
780
  pos, size = get_matplotlib_figure_props(fig)
822
781
 
823
782
  if selector == "rectangle":
824
- add_rectangle_from_mask(axs, mask[0], alpha=0.5)
783
+ plot_rectangle_from_mask(axs, mask[0], alpha=0.5)
825
784
  else:
826
- add_shape_from_mask(axs, mask[0], alpha=0.5)
785
+ plot_shape_from_mask(axs, mask[0], alpha=0.5)
827
786
  plt.close()
828
787
  selection_masks.append(mask[0])
829
788
 
@@ -840,13 +799,15 @@ def main():
840
799
  imshow_obj = axs.imshow(images[0], cmap="gray")
841
800
 
842
801
  if selector == "rectangle":
843
- add_rectangle_from_mask(axs, interpolated_masks[0])
802
+ plot_rectangle_from_mask(axs, interpolated_masks[0])
844
803
  else:
845
- add_shape_from_mask(axs, interpolated_masks[0], alpha=0.5)
804
+ plot_shape_from_mask(axs, interpolated_masks[0], alpha=0.5)
846
805
 
847
806
  filestem = Path(file.parent / f"{file.stem}_{title}_annotations.gif")
848
807
  np.save(filestem.with_suffix(".npy"), interpolated_masks)
849
- print(f"Succesfully saved interpolated masks to {log.yellow(filestem.with_suffix('.npy'))}")
808
+ print(
809
+ f"Successfully saved interpolated masks to {log.yellow(filestem.with_suffix('.npy'))}"
810
+ )
850
811
 
851
812
  fps = ask_save_animation_with_fps()
852
813
 
@@ -859,7 +820,7 @@ def main():
859
820
  )
860
821
  filename = filestem.with_suffix(".gif")
861
822
  ani.save(filename, writer="pillow")
862
- print(f"Succesfully saved animation as {log.yellow(filename)}")
823
+ print(f"Successfully saved animation as {log.yellow(filename)}")
863
824
 
864
825
 
865
826
  if __name__ == "__main__":