2626from monai .networks .layers import AffineTransform , GaussianFilter , grid_pull
2727from monai .networks .utils import meshgrid_ij , normalize_transform
2828from monai .transforms .croppad .array import CenterSpatialCrop , Pad
29+ from monai .transforms .intensity .array import GaussianSmooth
2930from monai .transforms .transform import Randomizable , RandomizableTransform , ThreadUnsafe , Transform
3031from monai .transforms .utils import (
3132 create_control_grid ,
@@ -622,6 +623,15 @@ class Resize(Transform):
622623 align_corners: This only has an effect when mode is
623624 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: None.
624625 See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.interpolate.html
626+ anti_aliasing: bool
627+ Whether to apply a Gaussian filter to smooth the image prior
628+ to downsampling. It is crucial to filter when downsampling
629+ the image to avoid aliasing artifacts. See also ``skimage.transform.resize``
630+ anti_aliasing_sigma: {float, tuple of floats}, optional
631+ Standard deviation for Gaussian filtering used when anti-aliasing.
632+ By default, this value is chosen as (s - 1) / 2 where s is the
633+ downsampling factor, where s > 1. For the up-size case, s < 1, no
634+ anti-aliasing is performed prior to rescaling.
625635 """
626636
627637 backend = [TransformBackends .TORCH ]
@@ -632,17 +642,23 @@ def __init__(
632642 size_mode : str = "all" ,
633643 mode : Union [InterpolateMode , str ] = InterpolateMode .AREA ,
634644 align_corners : Optional [bool ] = None ,
645+ anti_aliasing : bool = False ,
646+ anti_aliasing_sigma : Union [Sequence [float ], float , None ] = None ,
635647 ) -> None :
636648 self .size_mode = look_up_option (size_mode , ["all" , "longest" ])
637649 self .spatial_size = spatial_size
638650 self .mode : InterpolateMode = look_up_option (mode , InterpolateMode )
639651 self .align_corners = align_corners
652+ self .anti_aliasing = anti_aliasing
653+ self .anti_aliasing_sigma = anti_aliasing_sigma
640654
641655 def __call__ (
642656 self ,
643657 img : NdarrayOrTensor ,
644658 mode : Optional [Union [InterpolateMode , str ]] = None ,
645659 align_corners : Optional [bool ] = None ,
660+ anti_aliasing : Optional [bool ] = None ,
661+ anti_aliasing_sigma : Union [Sequence [float ], float , None ] = None ,
646662 ) -> NdarrayOrTensor :
647663 """
648664 Args:
@@ -653,11 +669,23 @@ def __call__(
653669 align_corners: This only has an effect when mode is
654670 'linear', 'bilinear', 'bicubic' or 'trilinear'. Defaults to ``self.align_corners``.
655671 See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.interpolate.html
672+ anti_aliasing: bool, optional
673+ Whether to apply a Gaussian filter to smooth the image prior
674+ to downsampling. It is crucial to filter when downsampling
675+ the image to avoid aliasing artifacts. See also ``skimage.transform.resize``
676+ anti_aliasing_sigma: {float, tuple of floats}, optional
677+ Standard deviation for Gaussian filtering used when anti-aliasing.
678+ By default, this value is chosen as (s - 1) / 2 where s is the
679+ downsampling factor, where s > 1. For the up-size case, s < 1, no
680+ anti-aliasing is performed prior to rescaling.
656681
657682 Raises:
658683 ValueError: When ``self.spatial_size`` length is less than ``img`` spatial dimensions.
659684
660685 """
686+ anti_aliasing = self .anti_aliasing if anti_aliasing is None else anti_aliasing
687+ anti_aliasing_sigma = self .anti_aliasing_sigma if anti_aliasing_sigma is None else anti_aliasing_sigma
688+
661689 img_ , * _ = convert_data_type (img , torch .Tensor , dtype = torch .float )
662690 if self .size_mode == "all" :
663691 input_ndim = img_ .ndim - 1 # spatial ndim
@@ -677,6 +705,20 @@ def __call__(
677705 raise ValueError ("spatial_size must be an int number if size_mode is 'longest'." )
678706 scale = self .spatial_size / max (img_size )
679707 spatial_size_ = tuple (int (round (s * scale )) for s in img_size )
708+
709+ if anti_aliasing and any (x < y for x , y in zip (spatial_size_ , img_ .shape [1 :])):
710+ factors = torch .div (torch .Tensor (list (img_ .shape [1 :])), torch .Tensor (spatial_size_ ))
711+ if anti_aliasing_sigma is None :
712+ # if sigma is not given, use the default sigma in skimage.transform.resize
713+ anti_aliasing_sigma = torch .maximum (torch .zeros (factors .shape ), (factors - 1 ) / 2 ).tolist ()
714+ else :
715+ # if sigma is given, use the given value for downsampling axis
716+ anti_aliasing_sigma = list (ensure_tuple_rep (anti_aliasing_sigma , len (spatial_size_ )))
717+ for axis in range (len (spatial_size_ )):
718+ anti_aliasing_sigma [axis ] = anti_aliasing_sigma [axis ] * int (factors [axis ] > 1 )
719+ anti_aliasing_filter = GaussianSmooth (sigma = anti_aliasing_sigma )
720+ img_ = anti_aliasing_filter (img_ )
721+
680722 resized = torch .nn .functional .interpolate (
681723 input = img_ .unsqueeze (0 ),
682724 size = spatial_size_ ,
0 commit comments