From f8b2948d7d0de61f3ed32698d61a4b078d365f19 Mon Sep 17 00:00:00 2001 From: Kanishk <36276423+kanishk16@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:27:39 +0530 Subject: [PATCH 01/18] chore: migrate imageio from v2 to v3 --- ivadomed/inference.py | 4 +++- ivadomed/loader/segmentation_pair.py | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ivadomed/inference.py b/ivadomed/inference.py index e5528d9cc..00da3f4c5 100644 --- a/ivadomed/inference.py +++ b/ivadomed/inference.py @@ -225,7 +225,9 @@ def pred_to_png(pred_list: list, target_list: list, subj_path: str, suffix: str for pred, target in zip(pred_list, target_list): filename = subj_path + target + suffix data = pred.get_fdata() - imageio.imwrite(filename, (data*255/max_value).astype(np.uint8), format='png') + _img = (data*255/max_value).astype(np.uint8) + img = np.dstack((_img, _img, _img)) + imageio.v3.imwrite(filename, img, extension='.png') def process_transformations(context: dict, fname_roi: str, fname_prior: str, metadata: dict, slice_axis: int, diff --git a/ivadomed/loader/segmentation_pair.py b/ivadomed/loader/segmentation_pair.py index 23281c8e0..e65ec76d2 100644 --- a/ivadomed/loader/segmentation_pair.py +++ b/ivadomed/loader/segmentation_pair.py @@ -315,12 +315,12 @@ def convert_file_to_nifti(self, filename: str, extension: str, is_gt: bool = Fal """ # For '.png', '.tif', '.tiff', '.jpg' and 'jpeg' extentions # Read image as 8 bit grayscale in numpy array (behavior TBD in ivadomed for RGB, RBGA or higher bit depth) - if "tif" in extension: - img = np.expand_dims(imageio.v2.imread(filename, format='tiff-pil'), axis=-1).astype(np.uint8) - if len(img.shape) > 3: - img = np.expand_dims(imageio.v2.imread(filename, format='tiff-pil', as_gray=True), axis=-1).astype(np.uint8) - else: - img = np.expand_dims(imageio.v2.imread(filename, as_gray=True), axis=-1).astype(np.uint8) + _img = imageio.v3.imread(filename) + + if len(_img.shape) < 3: + _img = np.expand_dims(_img, axis=-1) + + img = imageio.core.image_as_uint(_img, bitdepth=8) # Binarize ground-truth values (0-255) to 0 and 1 in uint8 with threshold 0.5 if is_gt: From e34c92a759b93e12886691b918dbb4355337b7ce Mon Sep 17 00:00:00 2001 From: Kanishk <36276423+kanishk16@users.noreply.github.com> Date: Tue, 27 Jun 2023 00:40:08 +0530 Subject: [PATCH 02/18] fix: tensorboard test --- ivadomed/loader/segmentation_pair.py | 4 ++-- testing/unit_tests/test_tensorboard_save.py | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ivadomed/loader/segmentation_pair.py b/ivadomed/loader/segmentation_pair.py index e65ec76d2..ea3b52c3e 100644 --- a/ivadomed/loader/segmentation_pair.py +++ b/ivadomed/loader/segmentation_pair.py @@ -316,10 +316,10 @@ def convert_file_to_nifti(self, filename: str, extension: str, is_gt: bool = Fal # For '.png', '.tif', '.tiff', '.jpg' and 'jpeg' extentions # Read image as 8 bit grayscale in numpy array (behavior TBD in ivadomed for RGB, RBGA or higher bit depth) _img = imageio.v3.imread(filename) - + if len(_img.shape) < 3: _img = np.expand_dims(_img, axis=-1) - + img = imageio.core.image_as_uint(_img, bitdepth=8) # Binarize ground-truth values (0-255) to 0 and 1 in uint8 with threshold 0.5 diff --git a/testing/unit_tests/test_tensorboard_save.py b/testing/unit_tests/test_tensorboard_save.py index 2d1a0742e..f282bf265 100644 --- a/testing/unit_tests/test_tensorboard_save.py +++ b/testing/unit_tests/test_tensorboard_save.py @@ -28,9 +28,12 @@ def test_tensorboard_save(): summary_iterators = [EventAccumulator(str(dname)).Reload() for dname in dpath.iterdir()] for i in range(len(summary_iterators)): if summary_iterators[i].Tags()['images'] == ['Training/Input', 'Training/Predictions', 'Training/Ground Truth']: - input_retrieve = np.array(Image.open(io.BytesIO(summary_iterators[i].Images('Training/Input')[0][2]))) - pred_retrieve = np.array(Image.open(io.BytesIO(summary_iterators[i].Images('Training/Predictions')[0][2]))) - gt_retrieve = np.array(Image.open(io.BytesIO(summary_iterators[i].Images('Training/Ground Truth')[0][2]))) + input_retrieve = np.array(Image.open(io.BytesIO( + summary_iterators[i].Images('Training/Input')[0].encoded_image_string))) + pred_retrieve = np.array(Image.open(io.BytesIO( + summary_iterators[i].Images('Training/Predictions')[0].encoded_image_string))) + gt_retrieve = np.array(Image.open(io.BytesIO( + summary_iterators[i].Images('Training/Ground Truth')[0].encoded_image_string))) assert np.allclose(imed_math.rescale_values_array(input_retrieve[:, :, 0], 0, 1), inp[0, 0, :, :]) assert np.allclose(imed_math.rescale_values_array(pred_retrieve[:, :, 0], 0, 1), pred[0, 0, :, :]) From d6769d2fda4cf7f38a1aa2219a803fd71e31b803 Mon Sep 17 00:00:00 2001 From: Kanishk Kalra <36276423+kanishk16@users.noreply.github.com> Date: Wed, 28 Jun 2023 22:42:45 +0530 Subject: [PATCH 03/18] chore: remove ubuntu-18.04 and python 3.7 from `run_tests` workflow (#1298) GHA stopped support for Ubuntu-18.04 LTS quite some time back. Since it is part of the requisite matrix test to merge a PR, it blocks #1296 and #1297. Moreover, removing python 3.7 as it reached EOL on 27 June 2023 (https://endoflife.date/python) and primarily to reduce GHA workflow quota for future runs. Partly unblocks #1296 and #1297 --- .github/workflows/run_tests.yml | 4 ++-- .github/workflows/run_tests_dummy.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index d53021528..31451bfcc 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -65,8 +65,8 @@ jobs: fail-fast: false matrix: - os: [ "macos-latest", "windows-latest", "ubuntu-20.04", "ubuntu-18.04" ] - python-version: [ '3.7', '3.8', '3.9', '3.10' ] + os: [ "macos-latest", "windows-latest", "ubuntu-20.04" ] + python-version: [ '3.8', '3.9', '3.10' ] test-name: - integration-test diff --git a/.github/workflows/run_tests_dummy.yml b/.github/workflows/run_tests_dummy.yml index bcc3f620d..4b7e44c79 100644 --- a/.github/workflows/run_tests_dummy.yml +++ b/.github/workflows/run_tests_dummy.yml @@ -28,7 +28,7 @@ jobs: strategy: matrix: # This list must be kept **in sync** with the Required Statuses in https://github.com/ivadomed/ivadomed/settings/branch_protection_rules/5051948 - os: [ "macos-latest", "windows-latest", "ubuntu-20.04", "ubuntu-18.04" ] + os: [ "macos-latest", "windows-latest", "ubuntu-20.04" ] python-version: [ 3.8 ] test-name: - integration-test From 109c37cca472da8077c7efc595bc50ecd9c6272a Mon Sep 17 00:00:00 2001 From: Kanishk <36276423+kanishk16@users.noreply.github.com> Date: Thu, 29 Jun 2023 23:20:20 +0530 Subject: [PATCH 04/18] include suggestions from code review --- .github/workflows/run_tests_dummy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests_dummy.yml b/.github/workflows/run_tests_dummy.yml index 4b7e44c79..c8af33b2d 100644 --- a/.github/workflows/run_tests_dummy.yml +++ b/.github/workflows/run_tests_dummy.yml @@ -28,7 +28,7 @@ jobs: strategy: matrix: # This list must be kept **in sync** with the Required Statuses in https://github.com/ivadomed/ivadomed/settings/branch_protection_rules/5051948 - os: [ "macos-latest", "windows-latest", "ubuntu-20.04" ] + os: [ "macos-latest", "ubuntu-20.04" ] python-version: [ 3.8 ] test-name: - integration-test From 5672e73b11c9212790ebfd99ebae753cfe7e0056 Mon Sep 17 00:00:00 2001 From: "Mathieu Boudreau, PhD" Date: Wed, 5 Jul 2023 13:15:26 -0300 Subject: [PATCH 05/18] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 1e4beb4d2..ef0095a6c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,7 @@ matplotlib>=3.3.0 nibabel~=3.2 onnxruntime~=1.7 pandas>=1.1,<1.5.0 +Pillow<10.0.0 pybids>=0.14.0 scikit-learn>=0.20.3 scikit-image~=0.17 From 5e25927f429d9fbd8c3f3cf73c10bcded1b754d7 Mon Sep 17 00:00:00 2001 From: "Mathieu Boudreau, PhD" Date: Wed, 5 Jul 2023 15:34:12 -0300 Subject: [PATCH 06/18] Set upper limit to pybids version Resolves windows bug, see https://github.com/ivadomed/ivadomed/pull/1299 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ef0095a6c..5c7d54c13 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ nibabel~=3.2 onnxruntime~=1.7 pandas>=1.1,<1.5.0 Pillow<10.0.0 -pybids>=0.14.0 +pybids>=0.14.0,<0.15.6 scikit-learn>=0.20.3 scikit-image~=0.17 seaborn~=0.11 From e6fff5c25764965a860565051687bb8cd2ddc0e0 Mon Sep 17 00:00:00 2001 From: "Mathieu Boudreau, PhD" Date: Wed, 5 Jul 2023 16:35:08 -0300 Subject: [PATCH 07/18] Revert requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5c7d54c13..ef0095a6c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ nibabel~=3.2 onnxruntime~=1.7 pandas>=1.1,<1.5.0 Pillow<10.0.0 -pybids>=0.14.0,<0.15.6 +pybids>=0.14.0 scikit-learn>=0.20.3 scikit-image~=0.17 seaborn~=0.11 From a17d8625f79454a38c63e93876dfe3c9f1f63d33 Mon Sep 17 00:00:00 2001 From: Armand Collin Date: Tue, 18 Jul 2023 15:07:12 -0400 Subject: [PATCH 08/18] Accomodate all combinations of 8-bit/16-bit, PNG/TIFF, grayscale/rgb/rgba --- ivadomed/inference.py | 5 ++--- ivadomed/loader/segmentation_pair.py | 8 +++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ivadomed/inference.py b/ivadomed/inference.py index 00da3f4c5..c3fb2c461 100644 --- a/ivadomed/inference.py +++ b/ivadomed/inference.py @@ -225,9 +225,8 @@ def pred_to_png(pred_list: list, target_list: list, subj_path: str, suffix: str for pred, target in zip(pred_list, target_list): filename = subj_path + target + suffix data = pred.get_fdata() - _img = (data*255/max_value).astype(np.uint8) - img = np.dstack((_img, _img, _img)) - imageio.v3.imwrite(filename, img, extension='.png') + _img = (data*255/max_value).astype(np.uint8).squeeze() + imageio.v3.imwrite(filename, _img, extension='.png') def process_transformations(context: dict, fname_roi: str, fname_prior: str, metadata: dict, slice_axis: int, diff --git a/ivadomed/loader/segmentation_pair.py b/ivadomed/loader/segmentation_pair.py index ea3b52c3e..7bfcfbc34 100644 --- a/ivadomed/loader/segmentation_pair.py +++ b/ivadomed/loader/segmentation_pair.py @@ -315,7 +315,13 @@ def convert_file_to_nifti(self, filename: str, extension: str, is_gt: bool = Fal """ # For '.png', '.tif', '.tiff', '.jpg' and 'jpeg' extentions # Read image as 8 bit grayscale in numpy array (behavior TBD in ivadomed for RGB, RBGA or higher bit depth) - _img = imageio.v3.imread(filename) + if 'tif' in extension: + _img = imageio.v3.imread(filename, plugin='tifffile') + if len(_img.shape) > 2: + # convert multichannel TIFF to grayscale using ITU-R 601-2 luma transform + _img = np.dot(_img[..., :3], [0.299, 0.587, 0.114]) + else: + _img = imageio.v3.imread(filename, plugin="pillow", mode="F") if len(_img.shape) < 3: _img = np.expand_dims(_img, axis=-1) From a3dc62d0c46004014e2556bed860cabb94c81ded Mon Sep 17 00:00:00 2001 From: Armand Collin Date: Wed, 19 Jul 2023 12:01:52 -0400 Subject: [PATCH 09/18] Separate image loading and processing (colorspace conversion/bit truncation) steps --- ivadomed/loader/segmentation_pair.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ivadomed/loader/segmentation_pair.py b/ivadomed/loader/segmentation_pair.py index 7bfcfbc34..ede5b3fa6 100644 --- a/ivadomed/loader/segmentation_pair.py +++ b/ivadomed/loader/segmentation_pair.py @@ -315,14 +315,24 @@ def convert_file_to_nifti(self, filename: str, extension: str, is_gt: bool = Fal """ # For '.png', '.tif', '.tiff', '.jpg' and 'jpeg' extentions # Read image as 8 bit grayscale in numpy array (behavior TBD in ivadomed for RGB, RBGA or higher bit depth) - if 'tif' in extension: - _img = imageio.v3.imread(filename, plugin='tifffile') - if len(_img.shape) > 2: - # convert multichannel TIFF to grayscale using ITU-R 601-2 luma transform - _img = np.dot(_img[..., :3], [0.299, 0.587, 0.114]) - else: - _img = imageio.v3.imread(filename, plugin="pillow", mode="F") - + props = imageio.v3.improps(filename) # new in v3 - standardized metadata + _img = imageio.v3.imread(filename) + + # TIFF is a "wild" format. A few assumptions greatly simplify the code below: + # 1. the image is interleaved/channel-last (not planar) + # 2. the colorspace is one of: binary, gray, RGB, RGBA (not aliasing ones like YUV or CMYK) + # 3. the image is flat (not a volume or time-series) + # Note: All of these are trivially true for JPEG and PNG due to limitations of these formats. + + # make grayscale (treats binary as 1-bit grayscale) + colorspace_idx = 2 + int(props.is_batch) + if _img.ndim <= colorspace_idx: # binary or gray + pass # nothing to do + elif _img.shape[colorspace_idx] == 3: # RGB + _img = np.sum(_img * (.299, .587, .114), axis=-1) + else: # RGBA + # discards alpha + _img = np.sum(_img * (.299, .587, .114, 0), axis=-1) if len(_img.shape) < 3: _img = np.expand_dims(_img, axis=-1) From 3519a0b36a9059a85840b808358f840e314943e0 Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Wed, 27 Sep 2023 12:19:24 -0400 Subject: [PATCH 10/18] `requirements.txt`: Try `torch==2.0.0` This version will be necessary for compatibility with MONAI/nnUNet, so I'm testing it here. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ef0095a6c..c8f673cd0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,6 +22,6 @@ tensorboard>=1.15.0 tqdm>=4.30 scipy torchio>=0.18.68 -torch>=1.8.1,<=1.11.0 +torch==2.0.0 torchvision>=0.9.1,<=0.12.0 wandb>=0.12.11 From 2d37b9f337e9941f078fc59c0da2972d34e872fd Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Wed, 27 Sep 2023 12:35:23 -0400 Subject: [PATCH 11/18] `requirements.txt`: Remove upper bound for torchvision --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c8f673cd0..a89834450 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,5 +23,5 @@ tqdm>=4.30 scipy torchio>=0.18.68 torch==2.0.0 -torchvision>=0.9.1,<=0.12.0 +torchvision>=0.9.1 wandb>=0.12.11 From 3f93ec66fc90c5fc9a3d6376c82fefe2c6b3cc2e Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Wed, 27 Sep 2023 12:46:45 -0400 Subject: [PATCH 12/18] Replace `torch._six.string_classes` with `str` `torch._six` was removed, and we should be accessing an internal API anyway. --- ivadomed/loader/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ivadomed/loader/utils.py b/ivadomed/loader/utils.py index 59e2a55b8..956dceb65 100644 --- a/ivadomed/loader/utils.py +++ b/ivadomed/loader/utils.py @@ -13,7 +13,6 @@ import torch from loguru import logger from sklearn.model_selection import train_test_split -from torch._six import string_classes from ivadomed import utils as imed_utils from ivadomed.keywords import SplitDatasetKW, LoaderParamsKW, ROIParamsKW, ContrastParamsKW import nibabel as nib @@ -270,7 +269,7 @@ def imed_collate(batch: dict) -> dict | list | str | torch.Tensor: return torch.LongTensor(batch) elif isinstance(batch[0], float): return torch.DoubleTensor(batch) - elif isinstance(batch[0], string_classes): + elif isinstance(batch[0], str): return batch elif isinstance(batch[0], collections.abc.Mapping): return {key: imed_collate([d[key] for d in batch]) for key in batch[0]} From fbc65da2ea7eb75c131489b8dc0b4254f359a5e1 Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Wed, 27 Sep 2023 14:14:02 -0400 Subject: [PATCH 13/18] `requirements.txt`: Set upper bound for `pybids` --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a89834450..dfcd31323 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ nibabel~=3.2 onnxruntime~=1.7 pandas>=1.1,<1.5.0 Pillow<10.0.0 -pybids>=0.14.0 +pybids>=0.14.0,<0.15.6 scikit-learn>=0.20.3 scikit-image~=0.17 seaborn~=0.11 From 0a67ae9b9e882b8e92121581f3bd0324a72a7d6f Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Wed, 27 Sep 2023 15:20:12 -0400 Subject: [PATCH 14/18] `requirements.txt`: Add `onnx` as a dependency --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index dfcd31323..65f6dd1fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,6 +11,7 @@ imageio~=2.19 joblib~=1.0 matplotlib>=3.3.0 nibabel~=3.2 +onnx onnxruntime~=1.7 pandas>=1.1,<1.5.0 Pillow<10.0.0 From 7339ddbc06efd9b4cf44a968d4d16ec6d46607d2 Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Wed, 27 Sep 2023 15:32:43 -0400 Subject: [PATCH 15/18] `requirements.txt`: Set upperbound for `onnxruntime` to `<1.16.0` --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 65f6dd1fd..6764f7680 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ joblib~=1.0 matplotlib>=3.3.0 nibabel~=3.2 onnx -onnxruntime~=1.7 +onnxruntime>=1.7.0,<1.16.0 pandas>=1.1,<1.5.0 Pillow<10.0.0 pybids>=0.14.0,<0.15.6 From 295ca08316693e0e341508addeb87d2eea00a331 Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Fri, 1 Dec 2023 13:16:47 -0500 Subject: [PATCH 16/18] `.readthedocs.yml`: Migrate from Python 3.7 -> 3.10 --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 1127680e3..4743d82f3 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -10,7 +10,7 @@ sphinx: configuration: docs/source/conf.py python: - version: 3.7 + version: 3.10 install: # Install IvadoMed package via setup.py content - method: pip From 0ac0fd647f62339803955279c232352b341c6bda Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Fri, 1 Dec 2023 13:21:15 -0500 Subject: [PATCH 17/18] `.readthedocs.yml`: Test RTD config (version 2.0) --- .readthedocs.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 4743d82f3..a0333d376 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,16 +1,23 @@ -# .readthedocs.yml +# .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.10" + # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/source/conf.py +# We recommend specifying your dependencies to enable reproducible builds: +# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: - version: 3.10 install: # Install IvadoMed package via setup.py content - method: pip From ab00a2a8f3cd97cf8fe1d69d54e766fcb09ef967 Mon Sep 17 00:00:00 2001 From: Joshua Newton Date: Fri, 1 Dec 2023 13:58:48 -0500 Subject: [PATCH 18/18] `run_tests_dummy.yml`: Re-add "windows-latest" --- .github/workflows/run_tests_dummy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests_dummy.yml b/.github/workflows/run_tests_dummy.yml index c8af33b2d..4b7e44c79 100644 --- a/.github/workflows/run_tests_dummy.yml +++ b/.github/workflows/run_tests_dummy.yml @@ -28,7 +28,7 @@ jobs: strategy: matrix: # This list must be kept **in sync** with the Required Statuses in https://github.com/ivadomed/ivadomed/settings/branch_protection_rules/5051948 - os: [ "macos-latest", "ubuntu-20.04" ] + os: [ "macos-latest", "windows-latest", "ubuntu-20.04" ] python-version: [ 3.8 ] test-name: - integration-test