Repository: Project-MONAI/MONAI

Issue:
Add `dtype` arg to `ScaleIntensityRange` transform for output
**Is your feature request related to a problem? Please describe.**
Need to add a `dtype` arg to `ScaleIntensityRange` to control the output datatype, same as other intensity transforms.




Discussion:

Patch:
diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py
--- a/monai/transforms/intensity/array.py
+++ b/monai/transforms/intensity/array.py
@@ -290,7 +290,7 @@ class StdShiftIntensity(Transform):
         nonzero: whether only count non-zero values.
         channel_wise: if True, calculate on each channel separately. Please ensure
             that the first dimension represents the channel of the image if True.
-        dtype: output data type, defaults to float32.
+        dtype: output data type, if None, same as input image. defaults to float32.
     """
 
     backend = [TransformBackends.TORCH, TransformBackends.NUMPY]
@@ -323,7 +323,8 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
         """
         Apply the transform to `img`.
         """
-        img, *_ = convert_data_type(img, dtype=self.dtype)
+        if self.dtype is not None:
+            img, *_ = convert_data_type(img, dtype=self.dtype)
         if self.channel_wise:
             for i, d in enumerate(img):
                 img[i] = self._stdshift(d)  # type: ignore
@@ -355,7 +356,7 @@ def __init__(
             prob: probability of std shift.
             nonzero: whether only count non-zero values.
             channel_wise: if True, calculate on each channel separately.
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
 
         """
         RandomizableTransform.__init__(self, prob)
@@ -416,7 +417,7 @@ def __init__(
                 this parameter, please set `minv` and `maxv` into None.
             channel_wise: if True, scale on each channel separately. Please ensure
                 that the first dimension represents the channel of the image if True.
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
         """
         self.minv = minv
         self.maxv = maxv
@@ -439,7 +440,8 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
             return rescale_array(img, self.minv, self.maxv, dtype=self.dtype)
         if self.factor is not None:
             ret = img * (1 + self.factor)
-            ret, *_ = convert_data_type(ret, dtype=self.dtype)
+            if self.dtype is not None:
+                ret, *_ = convert_data_type(ret, dtype=self.dtype or img.dtype)
             return ret
         raise ValueError("Incompatible values: minv=None or maxv=None and factor=None.")
 
@@ -460,7 +462,7 @@ def __init__(
             factors: factor range to randomly scale by ``v = v * (1 + factor)``.
                 if single number, factor value is picked from (-factors, factors).
             prob: probability of scale.
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
 
         """
         RandomizableTransform.__init__(self, prob)
@@ -507,7 +509,7 @@ class RandBiasField(RandomizableTransform):
         degree: degree of freedom of the polynomials. The value should be no less than 1.
             Defaults to 3.
         coeff_range: range of the random coefficients. Defaults to (0.0, 0.1).
-        dtype: output data type, defaults to float32.
+        dtype: output data type, if None, same as input image. defaults to float32.
         prob: probability to do random bias field.
 
     """
@@ -580,7 +582,7 @@ def __call__(self, img: NdarrayOrTensor, randomize: bool = True) -> NdarrayOrTen
         )
         img_np, *_ = convert_data_type(img, np.ndarray)
         out = img_np * np.exp(_bias_fields)
-        out, *_ = convert_to_dst_type(src=out, dst=img, dtype=self.dtype)
+        out, *_ = convert_to_dst_type(src=out, dst=img, dtype=self.dtype or img.dtype)
         return out
 
 
@@ -598,7 +600,7 @@ class NormalizeIntensity(Transform):
         nonzero: whether only normalize non-zero values.
         channel_wise: if using calculated mean and std, calculate on each channel separately
             or calculate on the entire image directly.
-        dtype: output data type, defaults to float32.
+        dtype: output data type, if None, same as input image. defaults to float32.
     """
 
     backend = [TransformBackends.TORCH, TransformBackends.NUMPY]
@@ -665,6 +667,7 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
         """
         Apply the transform to `img`, assuming `img` is a channel-first array if `self.channel_wise` is True,
         """
+        dtype = self.dtype or img.dtype
         if self.channel_wise:
             if self.subtrahend is not None and len(self.subtrahend) != len(img):
                 raise ValueError(f"img has {len(img)} channels, but subtrahend has {len(self.subtrahend)} components.")
@@ -680,7 +683,7 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
         else:
             img = self._normalize(img, self.subtrahend, self.divisor)
 
-        out, *_ = convert_data_type(img, dtype=self.dtype)
+        out, *_ = convert_data_type(img, dtype=dtype)
         return out
 
 
@@ -725,21 +728,26 @@ class ScaleIntensityRange(Transform):
         b_min: intensity target range min.
         b_max: intensity target range max.
         clip: whether to perform clip after scaling.
+        dtype: output data type, if None, same as input image. defaults to float32.
     """
 
     backend = [TransformBackends.TORCH, TransformBackends.NUMPY]
 
-    def __init__(self, a_min: float, a_max: float, b_min: float, b_max: float, clip: bool = False) -> None:
+    def __init__(
+        self, a_min: float, a_max: float, b_min: float, b_max: float, clip: bool = False, dtype: DtypeLike = np.float32
+    ) -> None:
         self.a_min = a_min
         self.a_max = a_max
         self.b_min = b_min
         self.b_max = b_max
         self.clip = clip
+        self.dtype = dtype
 
     def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
         """
         Apply the transform to `img`.
         """
+        dtype = self.dtype or img.dtype
         if self.a_max - self.a_min == 0.0:
             warn("Divide by zero (a_min == a_max)", Warning)
             return img - self.a_min + self.b_min
@@ -748,7 +756,9 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
         img = img * (self.b_max - self.b_min) + self.b_min
         if self.clip:
             img = clip(img, self.b_min, self.b_max)
-        return img
+        ret, *_ = convert_data_type(img, dtype=dtype)
+
+        return ret
 
 
 class AdjustContrast(Transform):
@@ -883,12 +893,20 @@ class ScaleIntensityRangePercentiles(Transform):
         b_max: intensity target range max.
         clip: whether to perform clip after scaling.
         relative: whether to scale to the corresponding percentiles of [b_min, b_max].
+        dtype: output data type, if None, same as input image. defaults to float32.
     """
 
     backend = ScaleIntensityRange.backend
 
     def __init__(
-        self, lower: float, upper: float, b_min: float, b_max: float, clip: bool = False, relative: bool = False
+        self,
+        lower: float,
+        upper: float,
+        b_min: float,
+        b_max: float,
+        clip: bool = False,
+        relative: bool = False,
+        dtype: DtypeLike = np.float32,
     ) -> None:
         if lower < 0.0 or lower > 100.0:
             raise ValueError("Percentiles must be in the range [0, 100]")
@@ -900,6 +918,7 @@ def __init__(
         self.b_max = b_max
         self.clip = clip
         self.relative = relative
+        self.dtype = dtype
 
     def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
         """
@@ -914,7 +933,7 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor:
             b_min = ((self.b_max - self.b_min) * (self.lower / 100.0)) + self.b_min
             b_max = ((self.b_max - self.b_min) * (self.upper / 100.0)) + self.b_min
 
-        scalar = ScaleIntensityRange(a_min=a_min, a_max=a_max, b_min=b_min, b_max=b_max, clip=False)
+        scalar = ScaleIntensityRange(a_min=a_min, a_max=a_max, b_min=b_min, b_max=b_max, clip=False, dtype=self.dtype)
         img = scalar(img)
 
         if self.clip:
@@ -1968,7 +1987,7 @@ class HistogramNormalize(Transform):
         mask: if provided, must be ndarray of bools or 0s and 1s, and same shape as `image`.
             only points at which `mask==True` are used for the equalization.
             can also provide the mask along with img at runtime.
-        dtype: data type of the output, default to `float32`.
+        dtype: data type of the output, if None, same as input image. default to `float32`.
 
     """
 
@@ -1988,12 +2007,15 @@ def __init__(
         self.mask = mask
         self.dtype = dtype
 
-    def __call__(self, img: NdarrayOrTensor, mask: Optional[NdarrayOrTensor] = None) -> np.ndarray:
-        return equalize_hist(
-            img=img,
-            mask=mask if mask is not None else self.mask,
-            num_bins=self.num_bins,
-            min=self.min,
-            max=self.max,
-            dtype=self.dtype,
-        )
+    def __call__(self, img: NdarrayOrTensor, mask: Optional[NdarrayOrTensor] = None) -> NdarrayOrTensor:
+        img_np: np.ndarray
+        img_np, *_ = convert_data_type(img, np.ndarray)  # type: ignore
+        mask = mask if mask is not None else self.mask
+        mask_np: Optional[np.ndarray] = None
+        if mask is not None:
+            mask_np, *_ = convert_data_type(mask, np.ndarray)  # type: ignore
+
+        ret = equalize_hist(img=img_np, mask=mask_np, num_bins=self.num_bins, min=self.min, max=self.max)
+        out, *_ = convert_to_dst_type(src=ret, dst=img, dtype=self.dtype or img.dtype)
+
+        return out
diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py
--- a/monai/transforms/intensity/dictionary.py
+++ b/monai/transforms/intensity/dictionary.py
@@ -412,7 +412,7 @@ def __init__(
             nonzero: whether only count non-zero values.
             channel_wise: if True, calculate on each channel separately. Please ensure
                 that the first dimension represents the channel of the image if True.
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
             allow_missing_keys: don't raise exception if key is missing.
         """
         super().__init__(keys, allow_missing_keys)
@@ -451,7 +451,7 @@ def __init__(
             prob: probability of std shift.
             nonzero: whether only count non-zero values.
             channel_wise: if True, calculate on each channel separately.
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
             allow_missing_keys: don't raise exception if key is missing.
         """
         MapTransform.__init__(self, keys, allow_missing_keys)
@@ -509,7 +509,7 @@ def __init__(
                 this parameter, please set `minv` and `maxv` into None.
             channel_wise: if True, scale on each channel separately. Please ensure
                 that the first dimension represents the channel of the image if True.
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
             allow_missing_keys: don't raise exception if key is missing.
 
         """
@@ -546,7 +546,7 @@ def __init__(
                 if single number, factor value is picked from (-factors, factors).
             prob: probability of rotating.
                 (Default 0.1, with 10% probability it returns a rotated array.)
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
             allow_missing_keys: don't raise exception if key is missing.
 
         """
@@ -597,7 +597,7 @@ def __init__(
             degree: degree of freedom of the polynomials. The value should be no less than 1.
                 Defaults to 3.
             coeff_range: range of the random coefficients. Defaults to (0.0, 0.1).
-            dtype: output data type, defaults to float32.
+            dtype: output data type, if None, same as input image. defaults to float32.
             prob: probability to do random bias field.
             allow_missing_keys: don't raise exception if key is missing.
 
@@ -641,7 +641,7 @@ class NormalizeIntensityd(MapTransform):
         nonzero: whether only normalize non-zero values.
         channel_wise: if using calculated mean and std, calculate on each channel separately
             or calculate on the entire image directly.
-        dtype: output data type, defaults to float32.
+        dtype: output data type, if None, same as input image. defaults to float32.
         allow_missing_keys: don't raise exception if key is missing.
     """
 
@@ -712,6 +712,7 @@ class ScaleIntensityRanged(MapTransform):
         b_min: intensity target range min.
         b_max: intensity target range max.
         clip: whether to perform clip after scaling.
+        dtype: output data type, if None, same as input image. defaults to float32.
         allow_missing_keys: don't raise exception if key is missing.
     """
 
@@ -725,10 +726,11 @@ def __init__(
         b_min: float,
         b_max: float,
         clip: bool = False,
+        dtype: DtypeLike = np.float32,
         allow_missing_keys: bool = False,
     ) -> None:
         super().__init__(keys, allow_missing_keys)
-        self.scaler = ScaleIntensityRange(a_min, a_max, b_min, b_max, clip)
+        self.scaler = ScaleIntensityRange(a_min, a_max, b_min, b_max, clip, dtype)
 
     def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]:
         d = dict(data)
@@ -826,6 +828,7 @@ class ScaleIntensityRangePercentilesd(MapTransform):
         b_max: intensity target range max.
         clip: whether to perform clip after scaling.
         relative: whether to scale to the corresponding percentiles of [b_min, b_max]
+        dtype: output data type, if None, same as input image. defaults to float32.
         allow_missing_keys: don't raise exception if key is missing.
     """
 
@@ -840,10 +843,11 @@ def __init__(
         b_max: float,
         clip: bool = False,
         relative: bool = False,
+        dtype: DtypeLike = np.float32,
         allow_missing_keys: bool = False,
     ) -> None:
         super().__init__(keys, allow_missing_keys)
-        self.scaler = ScaleIntensityRangePercentiles(lower, upper, b_min, b_max, clip, relative)
+        self.scaler = ScaleIntensityRangePercentiles(lower, upper, b_min, b_max, clip, relative, dtype)
 
     def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]:
         d = dict(data)
@@ -1549,7 +1553,7 @@ class HistogramNormalized(MapTransform):
             only points at which `mask==True` are used for the equalization.
             can also provide the mask by `mask_key` at runtime.
         mask_key: if mask is None, will try to get the mask with `mask_key`.
-        dtype: data type of the output, default to `float32`.
+        dtype: output data type, if None, same as input image. defaults to float32.
         allow_missing_keys: do not raise exception if key is missing.
 
     """
diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py
--- a/monai/transforms/utility/array.py
+++ b/monai/transforms/utility/array.py
@@ -403,7 +403,7 @@ class ToNumpy(Transform):
 
     backend = [TransformBackends.TORCH, TransformBackends.NUMPY]
 
-    def __init__(self, dtype: Optional[DtypeLike] = None) -> None:
+    def __init__(self, dtype: DtypeLike = None) -> None:
         super().__init__()
         self.dtype = dtype
 
diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py
--- a/monai/transforms/utility/dictionary.py
+++ b/monai/transforms/utility/dictionary.py
@@ -552,9 +552,7 @@ class ToNumpyd(MapTransform):
 
     backend = ToNumpy.backend
 
-    def __init__(
-        self, keys: KeysCollection, dtype: Optional[DtypeLike] = None, allow_missing_keys: bool = False
-    ) -> None:
+    def __init__(self, keys: KeysCollection, dtype: DtypeLike = None, allow_missing_keys: bool = False) -> None:
         """
         Args:
             keys: keys of the corresponding items to be transformed.
diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py
--- a/monai/transforms/utils.py
+++ b/monai/transforms/utils.py
@@ -149,14 +149,15 @@ def zero_margins(img: np.ndarray, margin: int) -> bool:
 
 
 def rescale_array(
-    arr: NdarrayOrTensor, minv: float = 0.0, maxv: float = 1.0, dtype: Union[DtypeLike, torch.dtype] = np.float32
+    arr: NdarrayOrTensor,
+    minv: float = 0.0,
+    maxv: float = 1.0,
+    dtype: Optional[Union[DtypeLike, torch.dtype]] = np.float32,
 ) -> NdarrayOrTensor:
     """
     Rescale the values of numpy array `arr` to be from `minv` to `maxv`.
     """
-    if dtype is not None:
-        arr, *_ = convert_data_type(arr, dtype=dtype)
-
+    dtype_ = dtype or arr.dtype
     mina = arr.min()
     maxa = arr.max()
 
@@ -164,7 +165,10 @@ def rescale_array(
         return arr * minv
 
     norm = (arr - mina) / (maxa - mina)  # normalize the array first
-    return (norm * (maxv - minv)) + minv  # rescale by minv and maxv, which is the normalized array by default
+    arr = (norm * (maxv - minv)) + minv  # rescale by minv and maxv, which is the normalized array by default
+
+    ret, *_ = convert_data_type(arr, dtype=dtype_)
+    return ret
 
 
 def rescale_instance_array(
@@ -173,7 +177,7 @@ def rescale_instance_array(
     """
     Rescale each array slice along the first dimension of `arr` independently.
     """
-    out: np.ndarray = np.zeros(arr.shape, dtype)
+    out: np.ndarray = np.zeros(arr.shape, dtype or arr.dtype)
     for i in range(arr.shape[0]):
         out[i] = rescale_array(arr[i], minv, maxv, dtype)
 
@@ -184,8 +188,8 @@ def rescale_array_int_max(arr: np.ndarray, dtype: DtypeLike = np.uint16) -> np.n
     """
     Rescale the array `arr` to be between the minimum and maximum values of the type `dtype`.
     """
-    info: np.iinfo = np.iinfo(dtype)
-    return np.asarray(rescale_array(arr, info.min, info.max), dtype=dtype)
+    info: np.iinfo = np.iinfo(dtype or arr.dtype)
+    return np.asarray(rescale_array(arr, info.min, info.max), dtype=dtype or arr.dtype)
 
 
 def copypaste_arrays(
@@ -1234,12 +1238,7 @@ def compute_divisible_spatial_size(spatial_shape: Sequence[int], k: Union[Sequen
 
 
 def equalize_hist(
-    img: NdarrayOrTensor,
-    mask: Optional[NdarrayOrTensor] = None,
-    num_bins: int = 256,
-    min: int = 0,
-    max: int = 255,
-    dtype: DtypeLike = np.float32,
+    img: np.ndarray, mask: Optional[np.ndarray] = None, num_bins: int = 256, min: int = 0, max: int = 255
 ) -> np.ndarray:
     """
     Utility to equalize input image based on the histogram.
@@ -1254,17 +1253,11 @@ def equalize_hist(
             https://numpy.org/doc/stable/reference/generated/numpy.histogram.html.
         min: the min value to normalize input image, default to `0`.
         max: the max value to normalize input image, default to `255`.
-        dtype: data type of the output, default to `float32`.
 
     """
-    img_np: np.ndarray
-    img_np, *_ = convert_data_type(img, np.ndarray)  # type: ignore
-    mask_np: Optional[np.ndarray] = None
-    if mask is not None:
-        mask_np, *_ = convert_data_type(mask, np.ndarray)  # type: ignore
 
-    orig_shape = img_np.shape
-    hist_img = img_np[np.array(mask_np, dtype=bool)] if mask_np is not None else img_np
+    orig_shape = img.shape
+    hist_img = img[np.array(mask, dtype=bool)] if mask is not None else img
     if has_skimage:
         hist, bins = exposure.histogram(hist_img.flatten(), num_bins)
     else:
@@ -1276,9 +1269,8 @@ def equalize_hist(
     cum = rescale_array(arr=cum, minv=min, maxv=max)
 
     # apply linear interpolation
-    img_np = np.interp(img_np.flatten(), bins, cum)
-
-    return img_np.reshape(orig_shape).astype(dtype)
+    img = np.interp(img.flatten(), bins, cum)
+    return img.reshape(orig_shape)
 
 
 class Fourier:
diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py
--- a/monai/utils/type_conversion.py
+++ b/monai/utils/type_conversion.py
@@ -130,7 +130,7 @@ def convert_to_tensor(
     return data
 
 
-def convert_to_numpy(data, dtype: Optional[DtypeLike] = None, wrap_sequence: bool = False):
+def convert_to_numpy(data, dtype: DtypeLike = None, wrap_sequence: bool = False):
     """
     Utility to convert the input data to a numpy array. If passing a dictionary, list or tuple,
     recursively check every item and convert it to numpy array.


Test patch:
diff --git a/tests/test_histogram_normalize.py b/tests/test_histogram_normalize.py
--- a/tests/test_histogram_normalize.py
+++ b/tests/test_histogram_normalize.py
@@ -15,7 +15,8 @@
 from parameterized import parameterized
 
 from monai.transforms import HistogramNormalize
-from tests.utils import TEST_NDARRAYS
+from monai.utils import get_equivalent_dtype
+from tests.utils import TEST_NDARRAYS, assert_allclose
 
 TESTS = []
 for p in TEST_NDARRAYS:
@@ -23,7 +24,7 @@
         [
             {"num_bins": 4, "min": 1, "max": 5, "mask": np.array([1, 1, 1, 1, 1, 0])},
             p(np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])),
-            np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0]),
+            p(np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0])),
         ]
     )
 
@@ -31,7 +32,7 @@
         [
             {"num_bins": 4, "max": 4, "dtype": np.uint8},
             p(np.array([0.0, 1.0, 2.0, 3.0, 4.0])),
-            np.array([0, 0, 1, 3, 4]),
+            p(np.array([0, 0, 1, 3, 4])),
         ]
     )
 
@@ -39,7 +40,7 @@
         [
             {"num_bins": 256, "max": 255, "dtype": np.uint8},
             p(np.array([[[100.0, 200.0], [150.0, 250.0]]])),
-            np.array([[[0, 170], [70, 255]]]),
+            p(np.array([[[0, 170], [70, 255]]])),
         ]
     )
 
@@ -48,8 +49,8 @@ class TestHistogramNormalize(unittest.TestCase):
     @parameterized.expand(TESTS)
     def test_value(self, argments, image, expected_data):
         result = HistogramNormalize(**argments)(image)
-        np.testing.assert_allclose(result, expected_data)
-        self.assertEqual(result.dtype, argments.get("dtype", np.float32))
+        assert_allclose(result, expected_data)
+        self.assertEqual(get_equivalent_dtype(result.dtype, data_type=np.ndarray), argments.get("dtype", np.float32))
 
 
 if __name__ == "__main__":
diff --git a/tests/test_histogram_normalized.py b/tests/test_histogram_normalized.py
--- a/tests/test_histogram_normalized.py
+++ b/tests/test_histogram_normalized.py
@@ -15,7 +15,8 @@
 from parameterized import parameterized
 
 from monai.transforms import HistogramNormalized
-from tests.utils import TEST_NDARRAYS
+from monai.utils import get_equivalent_dtype
+from tests.utils import TEST_NDARRAYS, assert_allclose
 
 TESTS = []
 for p in TEST_NDARRAYS:
@@ -23,7 +24,7 @@
         [
             {"keys": "img", "num_bins": 4, "min": 1, "max": 5, "mask_key": "mask"},
             {"img": p(np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])), "mask": p(np.array([1, 1, 1, 1, 1, 0]))},
-            np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0]),
+            p(np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0])),
         ]
     )
 
@@ -31,7 +32,7 @@
         [
             {"keys": "img", "num_bins": 4, "max": 4, "dtype": np.uint8},
             {"img": p(np.array([0.0, 1.0, 2.0, 3.0, 4.0]))},
-            np.array([0, 0, 1, 3, 4]),
+            p(np.array([0, 0, 1, 3, 4])),
         ]
     )
 
@@ -39,7 +40,7 @@
         [
             {"keys": "img", "num_bins": 256, "max": 255, "dtype": np.uint8},
             {"img": p(np.array([[[100.0, 200.0], [150.0, 250.0]]]))},
-            np.array([[[0, 170], [70, 255]]]),
+            p(np.array([[[0, 170], [70, 255]]])),
         ]
     )
 
@@ -48,8 +49,8 @@ class TestHistogramNormalized(unittest.TestCase):
     @parameterized.expand(TESTS)
     def test_value(self, argments, image, expected_data):
         result = HistogramNormalized(**argments)(image)["img"]
-        np.testing.assert_allclose(result, expected_data)
-        self.assertEqual(result.dtype, argments.get("dtype", np.float32))
+        assert_allclose(result, expected_data)
+        self.assertEqual(get_equivalent_dtype(result.dtype, data_type=np.ndarray), argments.get("dtype", np.float32))
 
 
 if __name__ == "__main__":
diff --git a/tests/test_scale_intensity_range.py b/tests/test_scale_intensity_range.py
--- a/tests/test_scale_intensity_range.py
+++ b/tests/test_scale_intensity_range.py
@@ -11,17 +11,19 @@
 
 import unittest
 
+import numpy as np
+
 from monai.transforms import ScaleIntensityRange
 from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose
 
 
 class IntensityScaleIntensityRange(NumpyImageTestCase2D):
     def test_image_scale_intensity_range(self):
-        scaler = ScaleIntensityRange(a_min=20, a_max=108, b_min=50, b_max=80)
+        scaler = ScaleIntensityRange(a_min=20, a_max=108, b_min=50, b_max=80, dtype=np.uint8)
         for p in TEST_NDARRAYS:
             scaled = scaler(p(self.imt))
-            expected = (self.imt - 20) / 88
-            expected = expected * 30 + 50
+            self.assertTrue(scaled.dtype, np.uint8)
+            expected = (((self.imt - 20) / 88) * 30 + 50).astype(np.uint8)
             assert_allclose(scaled, p(expected))
 
 
diff --git a/tests/test_scale_intensity_range_percentiles.py b/tests/test_scale_intensity_range_percentiles.py
--- a/tests/test_scale_intensity_range_percentiles.py
+++ b/tests/test_scale_intensity_range_percentiles.py
@@ -27,9 +27,8 @@ def test_scaling(self):
 
         a_min = np.percentile(img, lower)
         a_max = np.percentile(img, upper)
-        expected = (img - a_min) / (a_max - a_min)
-        expected = (expected * (b_max - b_min)) + b_min
-        scaler = ScaleIntensityRangePercentiles(lower=lower, upper=upper, b_min=b_min, b_max=b_max)
+        expected = (((img - a_min) / (a_max - a_min)) * (b_max - b_min) + b_min).astype(np.uint8)
+        scaler = ScaleIntensityRangePercentiles(lower=lower, upper=upper, b_min=b_min, b_max=b_max, dtype=np.uint8)
         for p in TEST_NDARRAYS:
             result = scaler(p(img))
             assert_allclose(result, p(expected), rtol=1e-4)