From 49f2bf0cae47fe2173e668a4b0f56d7c7390e6d9 Mon Sep 17 00:00:00 2001 From: YunLiu <55491388+KumoLiu@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:24:44 +0800 Subject: [PATCH 1/6] fix #7317 Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> --- monai/transforms/io/array.py | 8 ++++++-- tests/test_save_image.py | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/monai/transforms/io/array.py b/monai/transforms/io/array.py index cd7e4ef090..cfbb3d97a4 100644 --- a/monai/transforms/io/array.py +++ b/monai/transforms/io/array.py @@ -458,7 +458,7 @@ def set_options(self, init_kwargs=None, data_kwargs=None, meta_kwargs=None, writ self.write_kwargs.update(write_kwargs) return self - def __call__(self, img: torch.Tensor | np.ndarray, meta_data: dict | None = None): + def __call__(self, img: torch.Tensor | np.ndarray, meta_data: dict | None = None, filename: str | None = None): """ Args: img: target data content that save into file. The image should be channel-first, shape: `[C,H,W,[D]]`. @@ -466,7 +466,11 @@ def __call__(self, img: torch.Tensor | np.ndarray, meta_data: dict | None = None """ meta_data = img.meta if isinstance(img, MetaTensor) else meta_data kw = self.fname_formatter(meta_data, self) - filename = self.folder_layout.filename(**kw) + if filename is not None: + filename += f".{self.output_ext}" if self.output_ext and not self.output_ext.startswith(".") else f"{self.output_ext}" + else: + filename = self.folder_layout.filename(**kw) + if meta_data: meta_spatial_shape = ensure_tuple(meta_data.get("spatial_shape", ())) if len(meta_spatial_shape) >= len(img.shape): diff --git a/tests/test_save_image.py b/tests/test_save_image.py index ba94ab5087..a3a52b687a 100644 --- a/tests/test_save_image.py +++ b/tests/test_save_image.py @@ -37,6 +37,12 @@ False, ] +TEST_CASE_5 = [ + torch.randint(0, 255, (3, 2, 4, 5), dtype=torch.uint8), + ".dcm", + False, +] + @unittest.skipUnless(has_itk, "itk not installed") class TestSaveImage(unittest.TestCase): @@ -58,6 +64,20 @@ def test_saved_content(self, test_data, meta_data, output_ext, resample): filepath = "testfile0" if meta_data is not None else "0" self.assertTrue(os.path.exists(os.path.join(tempdir, filepath + "_trans" + output_ext))) + @parameterized.expand([TEST_CASE_5]) + def test_saved_content_with_filename(self, test_data, output_ext, resample): + with tempfile.TemporaryDirectory() as tempdir: + trans = SaveImage( + output_dir=tempdir, + output_ext=output_ext, + resample=resample, + separate_folder=False, # test saving into the same folder + ) + filename = str(os.path.join(tempdir, "test")) + trans(test_data, filename=filename) + + self.assertTrue(os.path.exists(filename + output_ext)) + if __name__ == "__main__": unittest.main() From 434ddc88304779907955e7f2b68bbee644c12803 Mon Sep 17 00:00:00 2001 From: YunLiu <55491388+KumoLiu@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:27:08 +0800 Subject: [PATCH 2/6] fix flake8 Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> --- monai/transforms/io/array.py | 6 +++++- tests/test_save_image.py | 6 +----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/monai/transforms/io/array.py b/monai/transforms/io/array.py index cfbb3d97a4..bae9665b56 100644 --- a/monai/transforms/io/array.py +++ b/monai/transforms/io/array.py @@ -467,7 +467,11 @@ def __call__(self, img: torch.Tensor | np.ndarray, meta_data: dict | None = None meta_data = img.meta if isinstance(img, MetaTensor) else meta_data kw = self.fname_formatter(meta_data, self) if filename is not None: - filename += f".{self.output_ext}" if self.output_ext and not self.output_ext.startswith(".") else f"{self.output_ext}" + filename += ( + f".{self.output_ext}" + if self.output_ext and not self.output_ext.startswith(".") + else f"{self.output_ext}" + ) else: filename = self.folder_layout.filename(**kw) diff --git a/tests/test_save_image.py b/tests/test_save_image.py index a3a52b687a..d88db201ce 100644 --- a/tests/test_save_image.py +++ b/tests/test_save_image.py @@ -37,11 +37,7 @@ False, ] -TEST_CASE_5 = [ - torch.randint(0, 255, (3, 2, 4, 5), dtype=torch.uint8), - ".dcm", - False, -] +TEST_CASE_5 = [torch.randint(0, 255, (3, 2, 4, 5), dtype=torch.uint8), ".dcm", False] @unittest.skipUnless(has_itk, "itk not installed") From 942e6f37d74c75f54fe6b5042fca5baccebcb85d Mon Sep 17 00:00:00 2001 From: YunLiu <55491388+KumoLiu@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:09:13 +0800 Subject: [PATCH 3/6] add docstring Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> --- monai/transforms/io/array.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/monai/transforms/io/array.py b/monai/transforms/io/array.py index bae9665b56..44ce0d7f15 100644 --- a/monai/transforms/io/array.py +++ b/monai/transforms/io/array.py @@ -458,14 +458,17 @@ def set_options(self, init_kwargs=None, data_kwargs=None, meta_kwargs=None, writ self.write_kwargs.update(write_kwargs) return self - def __call__(self, img: torch.Tensor | np.ndarray, meta_data: dict | None = None, filename: str | None = None): + def __call__( + self, img: torch.Tensor | np.ndarray, meta_data: dict | None = None, filename: str | PathLike | None = None + ): """ Args: img: target data content that save into file. The image should be channel-first, shape: `[C,H,W,[D]]`. meta_data: key-value pairs of metadata corresponding to the data. + filename: str or file-like object which to save img. + If specified, will ignore `self.output_name_formatter` and `self.folder_layout`. """ meta_data = img.meta if isinstance(img, MetaTensor) else meta_data - kw = self.fname_formatter(meta_data, self) if filename is not None: filename += ( f".{self.output_ext}" @@ -473,6 +476,7 @@ def __call__(self, img: torch.Tensor | np.ndarray, meta_data: dict | None = None else f"{self.output_ext}" ) else: + kw = self.fname_formatter(meta_data, self) filename = self.folder_layout.filename(**kw) if meta_data: From 7901c3eae5762c4395327ad6d58d6f419d1cb13c Mon Sep 17 00:00:00 2001 From: YunLiu <55491388+KumoLiu@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:11:59 +0800 Subject: [PATCH 4/6] fix mypy Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> --- monai/transforms/io/array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monai/transforms/io/array.py b/monai/transforms/io/array.py index 44ce0d7f15..4747b94803 100644 --- a/monai/transforms/io/array.py +++ b/monai/transforms/io/array.py @@ -470,7 +470,7 @@ def __call__( """ meta_data = img.meta if isinstance(img, MetaTensor) else meta_data if filename is not None: - filename += ( + filename = str(filename) + ( f".{self.output_ext}" if self.output_ext and not self.output_ext.startswith(".") else f"{self.output_ext}" From 8cc36b71e9dc29ccae8027d7a608b1561155c6b9 Mon Sep 17 00:00:00 2001 From: YunLiu <55491388+KumoLiu@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:33:20 +0800 Subject: [PATCH 5/6] address comments Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> --- monai/transforms/io/array.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/monai/transforms/io/array.py b/monai/transforms/io/array.py index 4747b94803..644239eea4 100644 --- a/monai/transforms/io/array.py +++ b/monai/transforms/io/array.py @@ -414,6 +414,7 @@ def __init__( self.fname_formatter = output_name_formatter self.output_ext = output_ext.lower() or output_format.lower() + self.output_ext = f".{self.output_ext}" if self.output_ext and not self.output_ext.startswith(".") else self.output_ext if isinstance(writer, str): writer_, has_built_in = optional_import("monai.data", name=f"{writer}") # search built-in if not has_built_in: @@ -470,11 +471,7 @@ def __call__( """ meta_data = img.meta if isinstance(img, MetaTensor) else meta_data if filename is not None: - filename = str(filename) + ( - f".{self.output_ext}" - if self.output_ext and not self.output_ext.startswith(".") - else f"{self.output_ext}" - ) + filename = f"{filename}{self.output_ext}" else: kw = self.fname_formatter(meta_data, self) filename = self.folder_layout.filename(**kw) From 1685fd8a683a5b7daca3a57f0f4ad7baa83ddc7b Mon Sep 17 00:00:00 2001 From: YunLiu <55491388+KumoLiu@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:33:51 +0800 Subject: [PATCH 6/6] fix flake8 Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> --- monai/transforms/io/array.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/monai/transforms/io/array.py b/monai/transforms/io/array.py index 644239eea4..7222a26fc3 100644 --- a/monai/transforms/io/array.py +++ b/monai/transforms/io/array.py @@ -414,7 +414,9 @@ def __init__( self.fname_formatter = output_name_formatter self.output_ext = output_ext.lower() or output_format.lower() - self.output_ext = f".{self.output_ext}" if self.output_ext and not self.output_ext.startswith(".") else self.output_ext + self.output_ext = ( + f".{self.output_ext}" if self.output_ext and not self.output_ext.startswith(".") else self.output_ext + ) if isinstance(writer, str): writer_, has_built_in = optional_import("monai.data", name=f"{writer}") # search built-in if not has_built_in: