monai-weekly 1.4.dev2425__py3-none-any.whl → 1.4.dev2427__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 (29) hide show
  1. monai/__init__.py +1 -1
  2. monai/_version.py +3 -3
  3. monai/apps/deepedit/transforms.py +1 -1
  4. monai/apps/deepgrow/transforms.py +1 -1
  5. monai/apps/generation/__init__.py +10 -0
  6. monai/apps/generation/maisi/__init__.py +10 -0
  7. monai/apps/generation/maisi/networks/__init__.py +10 -0
  8. monai/apps/generation/maisi/networks/autoencoderkl_maisi.py +975 -0
  9. monai/apps/generation/maisi/networks/controlnet_maisi.py +178 -0
  10. monai/apps/generation/maisi/networks/diffusion_model_unet_maisi.py +410 -0
  11. monai/apps/generation/maisi/utils/__init__.py +10 -0
  12. monai/apps/generation/maisi/utils/morphological_ops.py +170 -0
  13. monai/apps/nuclick/transforms.py +1 -1
  14. monai/apps/pathology/transforms/post/array.py +1 -1
  15. monai/apps/pathology/utils.py +2 -2
  16. monai/data/torchscript_utils.py +1 -1
  17. monai/data/ultrasound_confidence_map.py +41 -10
  18. monai/losses/dice.py +10 -3
  19. monai/metrics/utils.py +3 -3
  20. monai/optimizers/lr_finder.py +1 -1
  21. monai/transforms/intensity/array.py +25 -2
  22. monai/transforms/signal/array.py +1 -1
  23. monai/utils/misc.py +20 -2
  24. monai/utils/module.py +6 -3
  25. {monai_weekly-1.4.dev2425.dist-info → monai_weekly-1.4.dev2427.dist-info}/METADATA +6 -3
  26. {monai_weekly-1.4.dev2425.dist-info → monai_weekly-1.4.dev2427.dist-info}/RECORD +29 -21
  27. {monai_weekly-1.4.dev2425.dist-info → monai_weekly-1.4.dev2427.dist-info}/WHEEL +1 -1
  28. {monai_weekly-1.4.dev2425.dist-info → monai_weekly-1.4.dev2427.dist-info}/LICENSE +0 -0
  29. {monai_weekly-1.4.dev2425.dist-info → monai_weekly-1.4.dev2427.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,170 @@
1
+ # Copyright (c) MONAI Consortium
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software
7
+ # distributed under the License is distributed on an "AS IS" BASIS,
8
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ # See the License for the specific language governing permissions and
10
+ # limitations under the License.
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Sequence
15
+
16
+ import torch
17
+ import torch.nn.functional as F
18
+ from torch import Tensor
19
+
20
+ from monai.config import NdarrayOrTensor
21
+ from monai.utils import convert_data_type, convert_to_dst_type, ensure_tuple_rep
22
+
23
+
24
+ def erode(mask: NdarrayOrTensor, filter_size: int | Sequence[int] = 3, pad_value: float = 1.0) -> NdarrayOrTensor:
25
+ """
26
+ Erode 2D/3D binary mask.
27
+
28
+ Args:
29
+ mask: input 2D/3D binary mask, [N,C,M,N] or [N,C,M,N,P] torch tensor or ndarray.
30
+ filter_size: erosion filter size, has to be odd numbers, default to be 3.
31
+ pad_value: the filled value for padding. We need to pad the input before filtering
32
+ to keep the output with the same size as input. Usually use default value
33
+ and not changed.
34
+
35
+ Return:
36
+ eroded mask, same shape and data type as input.
37
+
38
+ Example:
39
+
40
+ .. code-block:: python
41
+
42
+ # define a naive mask
43
+ mask = torch.zeros(3,2,3,3,3)
44
+ mask[:,:,1,1,1] = 1.0
45
+ filter_size = 3
46
+ erode_result = erode(mask, filter_size) # expect torch.zeros(3,2,3,3,3)
47
+ dilate_result = dilate(mask, filter_size) # expect torch.ones(3,2,3,3,3)
48
+ """
49
+ mask_t, *_ = convert_data_type(mask, torch.Tensor)
50
+ res_mask_t = erode_t(mask_t, filter_size=filter_size, pad_value=pad_value)
51
+ res_mask: NdarrayOrTensor
52
+ res_mask, *_ = convert_to_dst_type(src=res_mask_t, dst=mask)
53
+ return res_mask
54
+
55
+
56
+ def dilate(mask: NdarrayOrTensor, filter_size: int | Sequence[int] = 3, pad_value: float = 0.0) -> NdarrayOrTensor:
57
+ """
58
+ Dilate 2D/3D binary mask.
59
+
60
+ Args:
61
+ mask: input 2D/3D binary mask, [N,C,M,N] or [N,C,M,N,P] torch tensor or ndarray.
62
+ filter_size: dilation filter size, has to be odd numbers, default to be 3.
63
+ pad_value: the filled value for padding. We need to pad the input before filtering
64
+ to keep the output with the same size as input. Usually use default value
65
+ and not changed.
66
+
67
+ Return:
68
+ dilated mask, same shape and data type as input.
69
+
70
+ Example:
71
+
72
+ .. code-block:: python
73
+
74
+ # define a naive mask
75
+ mask = torch.zeros(3,2,3,3,3)
76
+ mask[:,:,1,1,1] = 1.0
77
+ filter_size = 3
78
+ erode_result = erode(mask,filter_size) # expect torch.zeros(3,2,3,3,3)
79
+ dilate_result = dilate(mask,filter_size) # expect torch.ones(3,2,3,3,3)
80
+ """
81
+ mask_t, *_ = convert_data_type(mask, torch.Tensor)
82
+ res_mask_t = dilate_t(mask_t, filter_size=filter_size, pad_value=pad_value)
83
+ res_mask: NdarrayOrTensor
84
+ res_mask, *_ = convert_to_dst_type(src=res_mask_t, dst=mask)
85
+ return res_mask
86
+
87
+
88
+ def get_morphological_filter_result_t(mask_t: Tensor, filter_size: int | Sequence[int], pad_value: float) -> Tensor:
89
+ """
90
+ Apply a morphological filter to a 2D/3D binary mask tensor.
91
+
92
+ Args:
93
+ mask_t: input 2D/3D binary mask, [N,C,M,N] or [N,C,M,N,P] torch tensor.
94
+ filter_size: morphological filter size, has to be odd numbers.
95
+ pad_value: the filled value for padding. We need to pad the input before filtering
96
+ to keep the output with the same size as input.
97
+
98
+ Return:
99
+ Tensor: Morphological filter result mask, same shape as input.
100
+ """
101
+ spatial_dims = len(mask_t.shape) - 2
102
+ if spatial_dims not in [2, 3]:
103
+ raise ValueError(
104
+ f"spatial_dims must be either 2 or 3, "
105
+ f"got spatial_dims={spatial_dims} for mask tensor with shape of {mask_t.shape}."
106
+ )
107
+
108
+ # Define the structuring element
109
+ filter_size = ensure_tuple_rep(filter_size, spatial_dims)
110
+ if any(size % 2 == 0 for size in filter_size):
111
+ raise ValueError(f"All dimensions in filter_size must be odd numbers, got {filter_size}.")
112
+
113
+ structuring_element = torch.ones((mask_t.shape[1], mask_t.shape[1]) + filter_size).to(mask_t.device)
114
+
115
+ # Pad the input tensor to handle border pixels
116
+ # Calculate padding size
117
+ pad_size = [size // 2 for size in filter_size for _ in range(2)]
118
+
119
+ input_padded = F.pad(mask_t.float(), pad_size, mode="constant", value=pad_value)
120
+
121
+ # Apply filter operation
122
+ conv_fn = F.conv2d if spatial_dims == 2 else F.conv3d
123
+ output = conv_fn(input_padded, structuring_element, padding=0) / torch.sum(structuring_element[0, ...])
124
+
125
+ return output
126
+
127
+
128
+ def erode_t(mask_t: Tensor, filter_size: int | Sequence[int] = 3, pad_value: float = 1.0) -> Tensor:
129
+ """
130
+ Erode 2D/3D binary mask with data type as torch tensor.
131
+
132
+ Args:
133
+ mask_t: input 2D/3D binary mask, [N,C,M,N] or [N,C,M,N,P] torch tensor.
134
+ filter_size: erosion filter size, has to be odd numbers, default to be 3.
135
+ pad_value: the filled value for padding. We need to pad the input before filtering
136
+ to keep the output with the same size as input. Usually use default value
137
+ and not changed.
138
+
139
+ Return:
140
+ Tensor: eroded mask, same shape as input.
141
+ """
142
+
143
+ output = get_morphological_filter_result_t(mask_t, filter_size, pad_value)
144
+
145
+ # Set output values based on the minimum value within the structuring element
146
+ output = torch.where(torch.abs(output - 1.0) < 1e-7, 1.0, 0.0)
147
+
148
+ return output
149
+
150
+
151
+ def dilate_t(mask_t: Tensor, filter_size: int | Sequence[int] = 3, pad_value: float = 0.0) -> Tensor:
152
+ """
153
+ Dilate 2D/3D binary mask with data type as torch tensor.
154
+
155
+ Args:
156
+ mask_t: input 2D/3D binary mask, [N,C,M,N] or [N,C,M,N,P] torch tensor.
157
+ filter_size: dilation filter size, has to be odd numbers, default to be 3.
158
+ pad_value: the filled value for padding. We need to pad the input before filtering
159
+ to keep the output with the same size as input. Usually use default value
160
+ and not changed.
161
+
162
+ Return:
163
+ Tensor: dilated mask, same shape as input.
164
+ """
165
+ output = get_morphological_filter_result_t(mask_t, filter_size, pad_value)
166
+
167
+ # Set output values based on the minimum value within the structuring element
168
+ output = torch.where(output > 0, 1.0, 0.0)
169
+
170
+ return output
@@ -24,7 +24,7 @@ from monai.utils import StrEnum, convert_to_numpy, optional_import
24
24
 
25
25
  measure, _ = optional_import("skimage.measure")
26
26
  morphology, _ = optional_import("skimage.morphology")
27
- distance_transform_cdt, _ = optional_import("scipy.ndimage.morphology", name="distance_transform_cdt")
27
+ distance_transform_cdt, _ = optional_import("scipy.ndimage", name="distance_transform_cdt")
28
28
 
29
29
 
30
30
  class NuclickKeys(StrEnum):
@@ -33,7 +33,7 @@ from monai.utils import TransformBackends, convert_to_numpy, optional_import
33
33
  from monai.utils.misc import ensure_tuple_rep
34
34
  from monai.utils.type_conversion import convert_to_dst_type, convert_to_tensor
35
35
 
36
- label, _ = optional_import("scipy.ndimage.measurements", name="label")
36
+ label, _ = optional_import("scipy.ndimage", name="label")
37
37
  disk, _ = optional_import("skimage.morphology", name="disk")
38
38
  opening, _ = optional_import("skimage.morphology", name="opening")
39
39
  watershed, _ = optional_import("skimage.segmentation", name="watershed")
@@ -33,10 +33,10 @@ def compute_multi_instance_mask(mask: np.ndarray, threshold: float) -> Any:
33
33
  """
34
34
 
35
35
  neg = 255 - mask * 255
36
- distance = ndimage.morphology.distance_transform_edt(neg)
36
+ distance = ndimage.distance_transform_edt(neg)
37
37
  binary = distance < threshold
38
38
 
39
- filled_image = ndimage.morphology.binary_fill_holes(binary)
39
+ filled_image = ndimage.binary_fill_holes(binary)
40
40
  multi_instance_mask = measure.label(filled_image, connectivity=2)
41
41
 
42
42
  return multi_instance_mask
@@ -116,7 +116,7 @@ def load_net_with_metadata(
116
116
  Returns:
117
117
  Triple containing loaded object, metadata dict, and extra files dict containing other file data if present
118
118
  """
119
- extra_files = {f: "" for f in more_extra_files}
119
+ extra_files = dict.fromkeys(more_extra_files, "")
120
120
  extra_files[METADATA_FILENAME] = ""
121
121
 
122
122
  jit_obj = torch.jit.load(filename_prefix_or_stream, map_location, extra_files)
@@ -19,9 +19,11 @@ from monai.utils import min_version, optional_import
19
19
  __all__ = ["UltrasoundConfidenceMap"]
20
20
 
21
21
  cv2, _ = optional_import("cv2")
22
- csc_matrix, _ = optional_import("scipy.sparse", "1.7.1", min_version, "csc_matrix")
23
- spsolve, _ = optional_import("scipy.sparse.linalg", "1.7.1", min_version, "spsolve")
24
- hilbert, _ = optional_import("scipy.signal", "1.7.1", min_version, "hilbert")
22
+ csc_matrix, _ = optional_import("scipy.sparse", "1.12.0", min_version, "csc_matrix")
23
+ spsolve, _ = optional_import("scipy.sparse.linalg", "1.12.0", min_version, "spsolve")
24
+ cg, _ = optional_import("scipy.sparse.linalg", "1.12.0", min_version, "cg")
25
+ hilbert, _ = optional_import("scipy.signal", "1.12.0", min_version, "hilbert")
26
+ ruge_stuben_solver, _ = optional_import("pyamg", "5.0.0", min_version, "ruge_stuben_solver")
25
27
 
26
28
 
27
29
  class UltrasoundConfidenceMap:
@@ -30,6 +32,9 @@ class UltrasoundConfidenceMap:
30
32
  It generates a confidence map by setting source and sink points in the image and computing the probability
31
33
  for random walks to reach the source for each pixel.
32
34
 
35
+ The official code is available at:
36
+ https://campar.in.tum.de/Main/AthanasiosKaramalisCode
37
+
33
38
  Args:
34
39
  alpha (float, optional): Alpha parameter. Defaults to 2.0.
35
40
  beta (float, optional): Beta parameter. Defaults to 90.0.
@@ -37,15 +42,33 @@ class UltrasoundConfidenceMap:
37
42
  mode (str, optional): 'RF' or 'B' mode data. Defaults to 'B'.
38
43
  sink_mode (str, optional): Sink mode. Defaults to 'all'. If 'mask' is selected, a mask must be when calling
39
44
  the transform. Can be 'all', 'mid', 'min', or 'mask'.
45
+ use_cg (bool, optional): Use Conjugate Gradient method for solving the linear system. Defaults to False.
46
+ cg_tol (float, optional): Tolerance for the Conjugate Gradient method. Defaults to 1e-6.
47
+ Will be used only if `use_cg` is True.
48
+ cg_maxiter (int, optional): Maximum number of iterations for the Conjugate Gradient method. Defaults to 200.
49
+ Will be used only if `use_cg` is True.
40
50
  """
41
51
 
42
- def __init__(self, alpha: float = 2.0, beta: float = 90.0, gamma: float = 0.05, mode="B", sink_mode="all"):
52
+ def __init__(
53
+ self,
54
+ alpha: float = 2.0,
55
+ beta: float = 90.0,
56
+ gamma: float = 0.05,
57
+ mode="B",
58
+ sink_mode="all",
59
+ use_cg=False,
60
+ cg_tol=1e-6,
61
+ cg_maxiter=200,
62
+ ):
43
63
  # The hyperparameters for confidence map estimation
44
64
  self.alpha = alpha
45
65
  self.beta = beta
46
66
  self.gamma = gamma
47
67
  self.mode = mode
48
68
  self.sink_mode = sink_mode
69
+ self.use_cg = use_cg
70
+ self.cg_tol = cg_tol
71
+ self.cg_maxiter = cg_maxiter
49
72
 
50
73
  # The precision to use for all computations
51
74
  self.eps = np.finfo("float64").eps
@@ -228,17 +251,18 @@ class UltrasoundConfidenceMap:
228
251
  s = self.normalize(s)
229
252
 
230
253
  # Horizontal penalty
231
- s[:vertical_end] += gamma
232
- # s[vertical_end:diagonal_end] += gamma * np.sqrt(2) # --> In the paper it is sqrt(2)
233
- # since the diagonal edges are longer yet does not exist in the original code
254
+ s[vertical_end:] += gamma
255
+ # Here there is a difference between the official MATLAB code and the paper
256
+ # on the edge penalty. We directly implement what the official code does.
234
257
 
235
258
  # Normalize differences
236
259
  s = self.normalize(s)
237
260
 
238
261
  # Gaussian weighting function
239
262
  s = -(
240
- (np.exp(-beta * s, dtype="float64")) + 1.0e-6
241
- ) # --> This epsilon changes results drastically default: 1.e-6
263
+ (np.exp(-beta * s, dtype="float64")) + 1e-5
264
+ ) # --> This epsilon changes results drastically default: 10e-6
265
+ # Please notice that it is not 1e-6, it is 10e-6 which is actually different.
242
266
 
243
267
  # Create Laplacian, diagonal missing
244
268
  lap = csc_matrix((s, (i, j)))
@@ -256,7 +280,14 @@ class UltrasoundConfidenceMap:
256
280
  return lap
257
281
 
258
282
  def _solve_linear_system(self, lap, rhs):
259
- x = spsolve(lap, rhs)
283
+
284
+ if self.use_cg:
285
+ lap_sparse = lap.tocsr()
286
+ ml = ruge_stuben_solver(lap_sparse, coarse_solver="pinv")
287
+ m = ml.aspreconditioner(cycle="V")
288
+ x, _ = cg(lap, rhs, rtol=self.cg_tol, maxiter=self.cg_maxiter, M=m)
289
+ else:
290
+ x = spsolve(lap, rhs)
260
291
 
261
292
  return x
262
293
 
monai/losses/dice.py CHANGED
@@ -811,7 +811,7 @@ class DiceFocalLoss(_Loss):
811
811
  The details of Focal Loss is shown in ``monai.losses.FocalLoss``.
812
812
 
813
813
  ``gamma`` and ``lambda_focal`` are only used for the focal loss.
814
- ``include_background``, ``weight`` and ``reduction`` are used for both losses
814
+ ``include_background``, ``weight``, ``reduction``, and ``alpha`` are used for both losses,
815
815
  and other parameters are only used for dice loss.
816
816
 
817
817
  """
@@ -837,6 +837,7 @@ class DiceFocalLoss(_Loss):
837
837
  weight: Sequence[float] | float | int | torch.Tensor | None = None,
838
838
  lambda_dice: float = 1.0,
839
839
  lambda_focal: float = 1.0,
840
+ alpha: float | None = None,
840
841
  ) -> None:
841
842
  """
842
843
  Args:
@@ -871,7 +872,8 @@ class DiceFocalLoss(_Loss):
871
872
  Defaults to 1.0.
872
873
  lambda_focal: the trade-off weight value for focal loss. The value should be no less than 0.0.
873
874
  Defaults to 1.0.
874
-
875
+ alpha: value of the alpha in the definition of the alpha-balanced Focal loss. The value should be in
876
+ [0, 1]. Defaults to None.
875
877
  """
876
878
  super().__init__()
877
879
  weight = focal_weight if focal_weight is not None else weight
@@ -890,7 +892,12 @@ class DiceFocalLoss(_Loss):
890
892
  weight=weight,
891
893
  )
892
894
  self.focal = FocalLoss(
893
- include_background=include_background, to_onehot_y=False, gamma=gamma, weight=weight, reduction=reduction
895
+ include_background=include_background,
896
+ to_onehot_y=False,
897
+ gamma=gamma,
898
+ weight=weight,
899
+ alpha=alpha,
900
+ reduction=reduction,
894
901
  )
895
902
  if lambda_dice < 0.0:
896
903
  raise ValueError("lambda_dice should be no less than 0.0.")
monai/metrics/utils.py CHANGED
@@ -35,9 +35,9 @@ from monai.utils import (
35
35
  optional_import,
36
36
  )
37
37
 
38
- binary_erosion, _ = optional_import("scipy.ndimage.morphology", name="binary_erosion")
39
- distance_transform_edt, _ = optional_import("scipy.ndimage.morphology", name="distance_transform_edt")
40
- distance_transform_cdt, _ = optional_import("scipy.ndimage.morphology", name="distance_transform_cdt")
38
+ binary_erosion, _ = optional_import("scipy.ndimage", name="binary_erosion")
39
+ distance_transform_edt, _ = optional_import("scipy.ndimage", name="distance_transform_edt")
40
+ distance_transform_cdt, _ = optional_import("scipy.ndimage", name="distance_transform_cdt")
41
41
 
42
42
  __all__ = [
43
43
  "ignore_background",
@@ -524,7 +524,7 @@ class LearningRateFinder:
524
524
  # Plot the LR with steepest gradient
525
525
  if steepest_lr:
526
526
  lr_at_steepest_grad, loss_at_steepest_grad = self.get_steepest_gradient(skip_start, skip_end)
527
- if lr_at_steepest_grad is not None:
527
+ if lr_at_steepest_grad is not None and loss_at_steepest_grad is not None:
528
528
  ax.scatter(
529
529
  lr_at_steepest_grad,
530
530
  loss_at_steepest_grad,
@@ -2789,6 +2789,9 @@ class UltrasoundConfidenceMapTransform(Transform):
2789
2789
  It generates a confidence map by setting source and sink points in the image and computing the probability
2790
2790
  for random walks to reach the source for each pixel.
2791
2791
 
2792
+ The official code is available at:
2793
+ https://campar.in.tum.de/Main/AthanasiosKaramalisCode
2794
+
2792
2795
  Args:
2793
2796
  alpha (float, optional): Alpha parameter. Defaults to 2.0.
2794
2797
  beta (float, optional): Beta parameter. Defaults to 90.0.
@@ -2796,14 +2799,32 @@ class UltrasoundConfidenceMapTransform(Transform):
2796
2799
  mode (str, optional): 'RF' or 'B' mode data. Defaults to 'B'.
2797
2800
  sink_mode (str, optional): Sink mode. Defaults to 'all'. If 'mask' is selected, a mask must be when
2798
2801
  calling the transform. Can be one of 'all', 'mid', 'min', 'mask'.
2802
+ use_cg (bool, optional): Use Conjugate Gradient method for solving the linear system. Defaults to False.
2803
+ cg_tol (float, optional): Tolerance for the Conjugate Gradient method. Defaults to 1e-6.
2804
+ Will be used only if `use_cg` is True.
2805
+ cg_maxiter (int, optional): Maximum number of iterations for the Conjugate Gradient method. Defaults to 200.
2806
+ Will be used only if `use_cg` is True.
2799
2807
  """
2800
2808
 
2801
- def __init__(self, alpha: float = 2.0, beta: float = 90.0, gamma: float = 0.05, mode="B", sink_mode="all") -> None:
2809
+ def __init__(
2810
+ self,
2811
+ alpha: float = 2.0,
2812
+ beta: float = 90.0,
2813
+ gamma: float = 0.05,
2814
+ mode="B",
2815
+ sink_mode="all",
2816
+ use_cg=False,
2817
+ cg_tol: float = 1.0e-6,
2818
+ cg_maxiter: int = 200,
2819
+ ):
2802
2820
  self.alpha = alpha
2803
2821
  self.beta = beta
2804
2822
  self.gamma = gamma
2805
2823
  self.mode = mode
2806
2824
  self.sink_mode = sink_mode
2825
+ self.use_cg = use_cg
2826
+ self.cg_tol = cg_tol
2827
+ self.cg_maxiter = cg_maxiter
2807
2828
 
2808
2829
  if self.mode not in ["B", "RF"]:
2809
2830
  raise ValueError(f"Unknown mode: {self.mode}. Supported modes are 'B' and 'RF'.")
@@ -2813,7 +2834,9 @@ class UltrasoundConfidenceMapTransform(Transform):
2813
2834
  f"Unknown sink mode: {self.sink_mode}. Supported modes are 'all', 'mid', 'min' and 'mask'."
2814
2835
  )
2815
2836
 
2816
- self._compute_conf_map = UltrasoundConfidenceMap(self.alpha, self.beta, self.gamma, self.mode, self.sink_mode)
2837
+ self._compute_conf_map = UltrasoundConfidenceMap(
2838
+ self.alpha, self.beta, self.gamma, self.mode, self.sink_mode, self.use_cg, self.cg_tol, self.cg_maxiter
2839
+ )
2817
2840
 
2818
2841
  def __call__(self, img: NdarrayOrTensor, mask: NdarrayOrTensor | None = None) -> NdarrayOrTensor:
2819
2842
  """Compute confidence map from an ultrasound image.
@@ -28,7 +28,7 @@ from monai.utils import optional_import
28
28
  from monai.utils.enums import TransformBackends
29
29
  from monai.utils.type_conversion import convert_data_type, convert_to_tensor
30
30
 
31
- shift, has_shift = optional_import("scipy.ndimage.interpolation", name="shift")
31
+ shift, has_shift = optional_import("scipy.ndimage", name="shift")
32
32
  iirnotch, has_iirnotch = optional_import("scipy.signal", name="iirnotch")
33
33
  with warnings.catch_warnings():
34
34
  warnings.simplefilter("ignore", UserWarning) # project-monai/monai#5204
monai/utils/misc.py CHANGED
@@ -24,7 +24,6 @@ import types
24
24
  import warnings
25
25
  from ast import literal_eval
26
26
  from collections.abc import Callable, Iterable, Sequence
27
- from distutils.util import strtobool
28
27
  from math import log10
29
28
  from pathlib import Path
30
29
  from typing import TYPE_CHECKING, Any, TypeVar, cast, overload
@@ -78,6 +77,25 @@ __all__ = [
78
77
  "run_cmd",
79
78
  ]
80
79
 
80
+
81
+ def _strtobool(val: str) -> bool:
82
+ """
83
+ Replaces deprecated (pre python 3.12)
84
+ distutils strtobool function.
85
+
86
+ True values are y, yes, t, true, on and 1;
87
+ False values are n, no, f, false, off and 0.
88
+ Raises ValueError if val is anything else.
89
+ """
90
+ val = val.lower()
91
+ if val in ("y", "yes", "t", "true", "on", "1"):
92
+ return True
93
+ elif val in ("n", "no", "f", "false", "off", "0"):
94
+ return False
95
+ else:
96
+ raise ValueError(f"invalid truth value {val}")
97
+
98
+
81
99
  _seed = None
82
100
  _flag_deterministic = torch.backends.cudnn.deterministic
83
101
  _flag_cudnn_benchmark = torch.backends.cudnn.benchmark
@@ -400,7 +418,7 @@ def list_to_dict(items):
400
418
  d[key] = literal_eval(value)
401
419
  except ValueError:
402
420
  try:
403
- d[key] = bool(strtobool(str(value)))
421
+ d[key] = bool(_strtobool(str(value)))
404
422
  except ValueError:
405
423
  d[key] = value
406
424
  return d
monai/utils/module.py CHANGED
@@ -13,6 +13,7 @@ from __future__ import annotations
13
13
 
14
14
  import enum
15
15
  import functools
16
+ import importlib.util
16
17
  import os
17
18
  import pdb
18
19
  import re
@@ -208,9 +209,11 @@ def load_submodules(
208
209
  ):
209
210
  if (is_pkg or load_all) and name not in sys.modules and match(exclude_pattern, name) is None:
210
211
  try:
211
- mod = import_module(name)
212
- importer.find_spec(name).loader.load_module(name) # type: ignore
213
- submodules.append(mod)
212
+ mod_spec = importer.find_spec(name) # type: ignore
213
+ if mod_spec and mod_spec.loader:
214
+ mod = importlib.util.module_from_spec(mod_spec)
215
+ mod_spec.loader.exec_module(mod)
216
+ submodules.append(mod)
214
217
  except OptionalImportError:
215
218
  pass # could not import the optional deps., they are ignored
216
219
  except ImportError as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: monai-weekly
3
- Version: 1.4.dev2425
3
+ Version: 1.4.dev2427
4
4
  Summary: AI Toolkit for Healthcare Imaging
5
5
  Home-page: https://monai.io/
6
6
  Author: MONAI Consortium
@@ -35,7 +35,6 @@ Provides-Extra: all
35
35
  Requires-Dist: nibabel ; extra == 'all'
36
36
  Requires-Dist: ninja ; extra == 'all'
37
37
  Requires-Dist: scikit-image >=0.14.2 ; extra == 'all'
38
- Requires-Dist: scipy >=1.7.1 ; extra == 'all'
39
38
  Requires-Dist: pillow ; extra == 'all'
40
39
  Requires-Dist: tensorboard ; extra == 'all'
41
40
  Requires-Dist: gdown >=4.7.3 ; extra == 'all'
@@ -67,8 +66,10 @@ Requires-Dist: zarr ; extra == 'all'
67
66
  Requires-Dist: lpips ==0.1.4 ; extra == 'all'
68
67
  Requires-Dist: nvidia-ml-py ; extra == 'all'
69
68
  Requires-Dist: huggingface-hub ; extra == 'all'
69
+ Requires-Dist: pyamg >=5.0.0 ; extra == 'all'
70
70
  Requires-Dist: transformers <4.41.0,>=4.36.0 ; (python_version <= "3.10") and extra == 'all'
71
71
  Requires-Dist: onnxruntime ; (python_version <= "3.10") and extra == 'all'
72
+ Requires-Dist: scipy >=1.12.0 ; (python_version >= "3.9") and extra == 'all'
72
73
  Requires-Dist: cucim-cu12 ; (python_version >= "3.9" and python_version <= "3.10") and extra == 'all'
73
74
  Provides-Extra: clearml
74
75
  Requires-Dist: clearml ; extra == 'clearml'
@@ -119,6 +120,8 @@ Provides-Extra: pillow
119
120
  Requires-Dist: pillow !=8.3.0 ; extra == 'pillow'
120
121
  Provides-Extra: psutil
121
122
  Requires-Dist: psutil ; extra == 'psutil'
123
+ Provides-Extra: pyamg
124
+ Requires-Dist: pyamg >=5.0.0 ; extra == 'pyamg'
122
125
  Provides-Extra: pydicom
123
126
  Requires-Dist: pydicom ; extra == 'pydicom'
124
127
  Provides-Extra: pynrrd
@@ -128,7 +131,7 @@ Requires-Dist: nvidia-ml-py ; extra == 'pynvml'
128
131
  Provides-Extra: pyyaml
129
132
  Requires-Dist: pyyaml ; extra == 'pyyaml'
130
133
  Provides-Extra: scipy
131
- Requires-Dist: scipy >=1.7.1 ; extra == 'scipy'
134
+ Requires-Dist: scipy >=1.12.0 ; (python_version >= "3.9") and extra == 'scipy'
132
135
  Provides-Extra: skimage
133
136
  Requires-Dist: scikit-image >=0.14.2 ; extra == 'skimage'
134
137
  Provides-Extra: tensorboard