|
26 | 26 | from monai.config import USE_COMPILED, DtypeLike |
27 | 27 | from monai.config.type_definitions import NdarrayOrTensor |
28 | 28 | from monai.data.box_utils import BoxMode, StandardMode |
29 | | -from monai.data.meta_obj import get_track_meta, set_track_meta |
| 29 | +from monai.data.meta_obj import get_track_meta |
30 | 30 | from monai.data.meta_tensor import MetaTensor |
31 | 31 | from monai.data.utils import AFFINE_TOL, affine_to_spacing, compute_shape_offset, iter_patch, to_affine_nd, zoom_affine |
32 | 32 | from monai.networks.layers import AffineTransform, GaussianFilter, grid_pull |
@@ -3576,33 +3576,35 @@ def __call__(self, img: torch.Tensor, randomize: bool = True) -> torch.Tensor: |
3576 | 3576 |
|
3577 | 3577 | if self._do_transform: |
3578 | 3578 | input_shape = img.shape[1:] |
3579 | | - target_shape = tuple(np.round(np.array(input_shape) * self.zoom_factor).astype(np.int_).tolist()) |
3580 | | - |
3581 | | - resize_tfm_downsample = Resize( |
3582 | | - spatial_size=target_shape, size_mode="all", mode=self.downsample_mode, anti_aliasing=False |
3583 | | - ) |
3584 | | - |
3585 | | - resize_tfm_upsample = Resize( |
3586 | | - spatial_size=input_shape, |
3587 | | - size_mode="all", |
3588 | | - mode=self.upsample_mode, |
3589 | | - anti_aliasing=False, |
3590 | | - align_corners=self.align_corners, |
| 3579 | + # Clamp each axis to at least 1 so F.interpolate never sees a zero-sized dimension. |
| 3580 | + target_shape = tuple(max(1, int(np.round(s * self.zoom_factor))) for s in input_shape) |
| 3581 | + |
| 3582 | + # Use F.interpolate directly on a plain tensor to avoid mutating the global |
| 3583 | + # set_track_meta flag, which is not thread-safe (see GitHub issue #8409). |
| 3584 | + img_t = convert_to_tensor(img, track_meta=False) |
| 3585 | + # F.interpolate requires float input and a batch dimension; cast matches |
| 3586 | + # the default dtype=float32 that Resize uses internally. |
| 3587 | + img_float = img_t.unsqueeze(0).to(dtype=torch.float32) |
| 3588 | + |
| 3589 | + downsample_mode = str(self.downsample_mode) |
| 3590 | + upsample_mode = str(self.upsample_mode) |
| 3591 | + # align_corners is only valid for linear/bilinear/bicubic/trilinear modes |
| 3592 | + _align_corners_modes = {"linear", "bilinear", "bicubic", "trilinear"} |
| 3593 | + downsample_align_corners = self.align_corners if downsample_mode in _align_corners_modes else None |
| 3594 | + upsample_align_corners = self.align_corners if upsample_mode in _align_corners_modes else None |
| 3595 | + |
| 3596 | + img_downsampled = torch.nn.functional.interpolate( |
| 3597 | + img_float, size=target_shape, mode=downsample_mode, align_corners=downsample_align_corners |
3591 | 3598 | ) |
3592 | | - # temporarily disable metadata tracking, since we do not want to invert the two Resize functions during |
3593 | | - # post-processing |
3594 | | - original_tack_meta_value = get_track_meta() |
3595 | | - set_track_meta(False) |
3596 | | - |
3597 | | - img_downsampled = resize_tfm_downsample(img) |
3598 | | - img_upsampled = resize_tfm_upsample(img_downsampled) |
3599 | | - |
3600 | | - # reset metadata tracking to original value |
3601 | | - set_track_meta(original_tack_meta_value) |
3602 | | - |
3603 | | - # copy metadata from original image to down-and-upsampled image |
3604 | | - img_upsampled = MetaTensor(img_upsampled) |
3605 | | - img_upsampled.copy_meta_from(img) |
| 3599 | + img_upsampled_t = torch.nn.functional.interpolate( |
| 3600 | + img_downsampled, size=input_shape, mode=upsample_mode, align_corners=upsample_align_corners |
| 3601 | + ).squeeze(0) |
| 3602 | + |
| 3603 | + # copy metadata from original image to down-and-upsampled image, |
| 3604 | + # respecting the caller's get_track_meta() setting. |
| 3605 | + img_upsampled = cast(torch.Tensor, convert_to_tensor(img_upsampled_t, track_meta=get_track_meta())) |
| 3606 | + if isinstance(img_upsampled, MetaTensor): |
| 3607 | + img_upsampled.copy_meta_from(img) |
3606 | 3608 |
|
3607 | 3609 | return img_upsampled |
3608 | 3610 |
|
|
0 commit comments