diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6552327 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.mha filter=lfs diff=lfs merge=lfs -text +*.nii.gz filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index be9a959..7e20756 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,6 +14,8 @@ jobs: steps: - uses: actions/checkout@v2 + with: + lfs: 'true' - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: diff --git a/setup.py b/setup.py index e9a9b3a..65db365 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ long_description = fh.read() setuptools.setup( - version='1.1.6', + version='1.2', author_email='Joeran.Bosma@radboudumc.nl', long_description=long_description, long_description_content_type="text/markdown", @@ -14,5 +14,7 @@ "Bug Tracker": "https://github.com/DIAGNijmegen/picai_prep/issues" }, license='Apache License, Version 2.0', - packages=['picai_prep', 'picai_prep.resources', 'picai_prep.examples.dcm2mha', 'picai_prep.examples.mha2nnunet'], + package_dir={"": "src"}, # our packages live under src, but src is not a package itself + packages=setuptools.find_packages('src', exclude=['tests']), + exclude_package_data={'': ['tests']}, ) diff --git a/src/picai_prep/examples/mha2nnunet/picai_archive.py b/src/picai_prep/examples/mha2nnunet/picai_archive.py index 3120d5a..8c571ec 100644 --- a/src/picai_prep/examples/mha2nnunet/picai_archive.py +++ b/src/picai_prep/examples/mha2nnunet/picai_archive.py @@ -109,16 +109,17 @@ def generate_mha2nnunet_settings( } }, "preprocessing": { - "matrix_size": [ - 20, - 320, - 320 - ], - "spacing": [ - 3.0, - 0.5, - 0.5 - ] + # optionally, resample and perform centre crop: + # "matrix_size": [ + # 20, + # 320, + # 320 + # ], + # "spacing": [ + # 3.0, + # 0.5, + # 0.5 + # ], }, "archive": archive_list } diff --git a/src/picai_prep/examples/mha2nnunet/picai_archive_inference.py b/src/picai_prep/examples/mha2nnunet/picai_archive_inference.py index 4e5f315..5d34b06 100644 --- a/src/picai_prep/examples/mha2nnunet/picai_archive_inference.py +++ b/src/picai_prep/examples/mha2nnunet/picai_archive_inference.py @@ -97,16 +97,17 @@ def generate_mha2nnunet_settings( } }, "preprocessing": { - "matrix_size": [ - 20, - 160, - 160 - ], - "spacing": [ - 3.6, - 0.5, - 0.5 - ] + # optionally, resample and perform centre crop: + # "matrix_size": [ + # 20, + # 160, + # 160 + # ], + # "spacing": [ + # 3.6, + # 0.5, + # 0.5 + # ] }, "archive": archive_list } diff --git a/src/picai_prep/preprocessing.py b/src/picai_prep/preprocessing.py index 758344c..8a5e544 100755 --- a/src/picai_prep/preprocessing.py +++ b/src/picai_prep/preprocessing.py @@ -15,10 +15,11 @@ import SimpleITK as sitk import numpy as np +from numpy.testing import assert_allclose from dataclasses import dataclass from scipy import ndimage -from typing import List, Tuple, Callable, Optional, Union, Any, Iterable, cast +from typing import List, Callable, Optional, Union, Any, Iterable try: import numpy.typing as npt except ImportError: # pragma: no cover @@ -32,21 +33,15 @@ class PreprocessingSettings(): - matrix_size: number of voxels output volume (z, y, x) - spacing: output voxel spacing in mm (z, y, x) - physical_size: size in mm/voxel of the target volume (z, y, x) - - align_physical_space: whether to align sequences to eachother, based on metadata - - crop_to_first_physical_centre: whether to crop to physical centre of first sequence, - or to the new centre after aligning sequences - align_segmentation: whether to align the scans using the centroid of the provided segmentation """ - matrix_size: Iterable[int] = (20, 160, 160) + matrix_size: Optional[Iterable[int]] = None spacing: Optional[Iterable[float]] = None physical_size: Optional[Iterable[float]] = None - align_physical_space: bool = False - crop_to_first_physical_centre: bool = False align_segmentation: Optional[sitk.Image] = None def __post_init__(self): - if self.physical_size is None: - assert self.spacing, "Need either physical_size or spacing" + if self.physical_size is None and self.spacing is not None and self.matrix_size is not None: # calculate physical size self.physical_size = [ voxel_spacing * num_voxels @@ -56,8 +51,7 @@ def __post_init__(self): ) ] - if self.spacing is None: - assert self.physical_size, "Need either physical_size or spacing" + if self.spacing is None and self.physical_size is not None and self.matrix_size is not None: # calculate spacing self.spacing = [ size / num_voxels @@ -67,13 +61,8 @@ def __post_init__(self): ) ] - @property - def _spacing(self) -> Iterable[float]: - return cast(Iterable[float], self.spacing) - - @property - def _physical_size(self) -> Iterable[float]: - return cast(Iterable[float], self.physical_size) + if self.align_segmentation is not None: + raise NotImplementedError("Alignment of scans based on segmentation is not implemented yet.") def resample_img( @@ -170,83 +159,6 @@ def crop_or_pad( return np.pad(image[tuple(slicer)], padding) -def get_overlap_start_indices(img_main: sitk.Image, img_secondary: sitk.Image): - # convert start index from main image to secondary image - point_secondary = img_secondary.TransformIndexToPhysicalPoint((0, 0, 0)) - index_main = img_main.TransformPhysicalPointToContinuousIndex(point_secondary) - - # clip index - index_main = np.clip(index_main, a_min=0, a_max=None) - - # convert main index back to secondary image - point_main = img_main.TransformContinuousIndexToPhysicalPoint(index_main) - index_secondary = img_secondary.TransformPhysicalPointToContinuousIndex(point_main) - - # round secondary index up (round to 5 decimals for e.g. 18.999999999999996) - index_secondary = np.ceil(np.round(index_secondary, decimals=5)) - - # convert secondary index once again to main image - point_secondary = img_secondary.TransformContinuousIndexToPhysicalPoint(index_secondary) - index_main = img_main.TransformPhysicalPointToIndex(point_secondary) - - # convert and return result - return np.array(index_secondary).astype(int), np.array(index_main).astype(int) - - -def get_overlap_end_indices(img_main: sitk.Image, img_secondary: sitk.Image): - # convert end index from secondary image to primary image - point_secondary = img_secondary.TransformIndexToPhysicalPoint(img_secondary.GetSize()) - index_main = img_main.TransformPhysicalPointToContinuousIndex(point_secondary) - - # clip index - index_main = [min(sz, i) for (i, sz) in zip(index_main, img_main.GetSize())] - - # convert primary index back to secondary image - point_main = img_main.TransformContinuousIndexToPhysicalPoint(index_main) - index_secondary = img_secondary.TransformPhysicalPointToContinuousIndex(point_main) - - # round secondary index down (round to 5 decimals for e.g. 18.999999999999996) - index_secondary = np.floor(np.round(index_secondary, decimals=5)) - - # convert secondary index once again to primary image - point_secondary = img_secondary.TransformContinuousIndexToPhysicalPoint(index_secondary) - index_main = img_main.TransformPhysicalPointToIndex(point_secondary) - - # convert and return result - return np.array(index_secondary).astype(int), np.array(index_main).astype(int) - - -def crop_to_common_physical_space( - img_main: sitk.Image, - img_sec: sitk.Image -) -> Tuple[sitk.Image, sitk.Image]: - """ - Crop SimpleITK images to the largest shared physical volume - """ - # determine crop indices - idx_start_sec, idx_start_main = get_overlap_start_indices(img_main, img_sec) - idx_end_sec, idx_end_main = get_overlap_end_indices(img_main, img_sec) - - # check extracted indices - assert ((idx_end_sec - idx_start_sec) > np.array(img_sec.GetSize()) / 2).all(), \ - "Found unrealistically little overlap when aligning scans, aborting." - assert ((idx_end_main - idx_start_main) > np.array(img_main.GetSize()) / 2).all(), \ - "Found unrealistically little overlap when aligning scans, aborting." - - # apply crop - slices = [slice(idx_start, idx_end) for (idx_start, idx_end) in zip(idx_start_main, idx_end_main)] - img_main = img_main[slices] - - slices = [slice(idx_start, idx_end) for (idx_start, idx_end) in zip(idx_start_sec, idx_end_sec)] - img_sec = img_sec[slices] - - return img_main, img_sec - - -def get_physical_centre(image: sitk.Image): - return image.TransformContinuousIndexToPhysicalPoint(np.array(image.GetSize()) / 2.0) - - @dataclass class Sample: scans: List[sitk.Image] @@ -260,53 +172,42 @@ class Sample: num_gt_lesions: Optional[int] = None def __post_init__(self): - # determine main centre - self.main_centre = get_physical_centre(self.scans[0]) - if self.lbl is not None: # keep track of connected components lbl = sitk.GetArrayFromImage(self.lbl) _, num_gt_lesions = ndimage.label(lbl, structure=np.ones((3, 3, 3))) self.num_gt_lesions = num_gt_lesions - def crop_to_common_physical_space(self): - """ - Align physical centre of the first scan (e.g., T2W) with subsequent scans (e.g., ADC, high b-value) - """ - main_centre = get_physical_centre(self.scans[0]) - - should_align_scans = False - for scan in self.scans[1:]: - secondary_centre = get_physical_centre(scan) - - # calculate distance from center of first scan (e.g., T2W) to center of secondary scan (e.g., ADC, high b-value) - distance = np.sqrt(np.sum((np.array(main_centre) - np.array(secondary_centre))**2)) - - # if difference in center coordinates is more than 2mm, align the scans - if distance > 2: - print(f"Aligning scans with distance of {distance:.1f} mm between centers for {self.name}.") - should_align_scans = True - - if should_align_scans: - for i, main_scan in enumerate(self.scans): - for j, secondary_scan in enumerate(self.scans): - if i == j: - continue - - # align scans - img_main, img_sec = crop_to_common_physical_space(main_scan, secondary_scan) - self.scans[i] = img_main - self.scans[j] = img_sec - - def resample(self): - """Resample scans and label""" + def resample_to_first_scan(self): + """Resample scans and label to the first scan""" + # set up resampler to resolution, field of view, etc. of first scan + resampler = sitk.ResampleImageFilter() # default linear + resampler.SetReferenceImage(self.scans[0]) + resampler.SetInterpolator(sitk.sitkBSpline) + + # resample other images + self.scans[1:] = [resampler.Execute(scan) for scan in self.scans[1:]] + + # resample annotation + resampler.SetInterpolator(sitk.sitkNearestNeighbor) + if self.lbl is not None: + self.lbl = resampler.Execute(self.lbl) + + def resample_spacing(self, spacing: Optional[Iterable[float]] = None): + """Resample scans and label to the target spacing""" + if spacing is None: + assert self.settings.spacing is not None + spacing = self.settings.spacing + + # resample scans to target resolution self.scans = [ - resample_img(scan, out_spacing=self.settings._spacing, is_label=False) + resample_img(scan, out_spacing=spacing, is_label=False) for scan in self.scans ] + # resample annotation to target resolution if self.lbl is not None: - self.lbl = resample_img(self.lbl, out_spacing=self.settings._spacing, is_label=True) + self.lbl = resample_img(self.lbl, out_spacing=spacing, is_label=True) def centre_crop(self): """Centre crop scans and label""" @@ -318,7 +219,7 @@ def centre_crop(self): if self.lbl is not None: self.lbl = crop_or_pad(self.lbl, size=self.settings.matrix_size) - def copy_physical_metadata(self): + def align_physical_metadata(self, check_almost_equal=True): """Align the origin and direction of each scan, and label""" case_origin, case_direction, case_spacing = None, None, None for img in self.scans: @@ -328,6 +229,13 @@ def copy_physical_metadata(self): case_direction = img.GetDirection() case_spacing = img.GetSpacing() else: + if check_almost_equal: + # check if current scan's metadata is almost equal to the first scan + assert_allclose(img.GetOrigin(), case_origin) + assert_allclose(img.GetDirection(), case_direction) + assert_allclose(img.GetSpacing(), case_spacing) + + # copy over first scan's metadata to current scan img.SetOrigin(case_origin) img.SetDirection(case_direction) img.SetSpacing(case_spacing) @@ -348,18 +256,19 @@ def preprocess(self): # apply scan transformation self.scans = [self.scan_preprocess_func(scan) for scan in self.scans] - if self.settings.align_physical_space: - # align sequences based on metadata - self.crop_to_common_physical_space() + if self.settings.spacing is not None: + # resample scans and label to specified spacing + self.resample_spacing() - # resample scans and label - self.resample() + if self.settings.matrix_size is not None: + # perform centre crop + self.centre_crop() - # perform centre crop - self.centre_crop() + # resample scans and label to first scan's spacing, field-of-view, etc. + self.resample_to_first_scan() # copy physical metadata to align subvoxel differences between sequences - self.copy_physical_metadata() + self.align_physical_metadata() if self.lbl is not None: # check connected components of annotation diff --git a/src/picai_prep/resources/mha2nnunet_schema.py b/src/picai_prep/resources/mha2nnunet_schema.py index d0e3045..b3f79d6 100644 --- a/src/picai_prep/resources/mha2nnunet_schema.py +++ b/src/picai_prep/resources/mha2nnunet_schema.py @@ -38,24 +38,16 @@ "type": "object", "description": "Preprocessing parameters", "properties": { - "align_physical_space": { - "description": "...", - "type": "boolean" - }, - "crop_to_first_physical_centre": { - "description": "...", - "type": "boolean" - }, "physical_size": { - "description": "...", + "description": "Target field-of-view in mm (z, y, x). Automatically calculated if `matrix_size` and `spacing` are set.", "$ref": "#/$defs/3d" }, "matrix_size": { - "description": "Defaults to [20, 160, 160] if neither this or 'physical_size' is set.", + "description": "Target matrix size. Automatically calculated if `physical_size` and `spacing` are set.", "$ref": "#/$defs/3d" }, "spacing": { - "description": "...", + "description": "Target resolution in mm/voxel (z, y, x). Automatically calculated if `physical_size` and `matrix_size` are set.", "$ref": "#/$defs/3d" } }, diff --git a/tests/input/annotations/ProstateX/ProstateX-0000_07-07-2011.nii.gz b/tests/input/annotations/ProstateX/ProstateX-0000_07-07-2011.nii.gz old mode 100755 new mode 100644 index e196027..3a27e45 Binary files a/tests/input/annotations/ProstateX/ProstateX-0000_07-07-2011.nii.gz and b/tests/input/annotations/ProstateX/ProstateX-0000_07-07-2011.nii.gz differ diff --git a/tests/input/annotations/ProstateX/ProstateX-0001_07-08-2011.nii.gz b/tests/input/annotations/ProstateX/ProstateX-0001_07-08-2011.nii.gz old mode 100755 new mode 100644 index 4116e0c..2bc9131 Binary files a/tests/input/annotations/ProstateX/ProstateX-0001_07-08-2011.nii.gz and b/tests/input/annotations/ProstateX/ProstateX-0001_07-08-2011.nii.gz differ diff --git a/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10032_1000032.nii.gz b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10032_1000032.nii.gz new file mode 100644 index 0000000..13cc50c --- /dev/null +++ b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10032_1000032.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f948ae1b3b346bc6889b21fca54970c2c3fd89498cd16e74f8208db7c692469d +size 6364 diff --git a/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10059_1000059.nii.gz b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10059_1000059.nii.gz new file mode 100644 index 0000000..e749270 --- /dev/null +++ b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10059_1000059.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64e3a983c9525898438d02f0cda8c47c8d87ab8fbdd7334a75e0ce267cce388d +size 5775 diff --git a/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10699_1000715.nii.gz b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10699_1000715.nii.gz new file mode 100644 index 0000000..a3edcf0 --- /dev/null +++ b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10699_1000715.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:906bb0e14d22ca8e8fc462d2b9374bd9dc842f50cc6cf61d4cb2a5243fa859da +size 4535 diff --git a/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10730_1000746.nii.gz b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10730_1000746.nii.gz new file mode 100644 index 0000000..842d056 --- /dev/null +++ b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10730_1000746.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:598d4f6d972944e21c61a483d9660d25bbf458ddd774e241afcc705b595549ba +size 7410 diff --git a/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10868_1000884.nii.gz b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10868_1000884.nii.gz new file mode 100644 index 0000000..b9cf555 --- /dev/null +++ b/tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled/10868_1000884.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a222fba23ebd0a2a1a2e59b0251b210f153748bebba95d5e9c27c9247534bfe7 +size 6278 diff --git a/tests/input/mha/picai/10032/10032_1000032_adc.mha b/tests/input/mha/picai/10032/10032_1000032_adc.mha new file mode 100755 index 0000000..b5e1c21 --- /dev/null +++ b/tests/input/mha/picai/10032/10032_1000032_adc.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:271c0a88688131f60fbfdbbfb6fe9145790fdb1d0e5d6aa6bb1a16f0e14aeca7 +size 171012 diff --git a/tests/input/mha/picai/10032/10032_1000032_cor.mha b/tests/input/mha/picai/10032/10032_1000032_cor.mha new file mode 100755 index 0000000..59514d2 --- /dev/null +++ b/tests/input/mha/picai/10032/10032_1000032_cor.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:255e2fecaf14b9df66103483cdf2b9235e61540b1190b54b499c491dc948228b +size 2037080 diff --git a/tests/input/mha/picai/10032/10032_1000032_hbv.mha b/tests/input/mha/picai/10032/10032_1000032_hbv.mha new file mode 100755 index 0000000..425e76b --- /dev/null +++ b/tests/input/mha/picai/10032/10032_1000032_hbv.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9cb8d46c08b3cf65daa019036e6af02b7cef423be106b002bd1a3aba215305b3 +size 98453 diff --git a/tests/input/mha/picai/10032/10032_1000032_sag.mha b/tests/input/mha/picai/10032/10032_1000032_sag.mha new file mode 100755 index 0000000..96608a5 --- /dev/null +++ b/tests/input/mha/picai/10032/10032_1000032_sag.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:afa2eaef86194ebcf31db6a23289011c50edd4aed8bbd6738b27c75fa62b3df2 +size 2539874 diff --git a/tests/input/mha/picai/10032/10032_1000032_t2w.mha b/tests/input/mha/picai/10032/10032_1000032_t2w.mha new file mode 100755 index 0000000..f1a22cc --- /dev/null +++ b/tests/input/mha/picai/10032/10032_1000032_t2w.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f8a841192571618eb938825807d39b415e0f465bab07ba0b370df7a71df0e59 +size 6874433 diff --git a/tests/input/mha/picai/10059/10059_1000059_adc.mha b/tests/input/mha/picai/10059/10059_1000059_adc.mha new file mode 100755 index 0000000..dde9dad --- /dev/null +++ b/tests/input/mha/picai/10059/10059_1000059_adc.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfde4e1cbd928ebafb865087b3154133c30ebb039d7896c9b585256d6893affd +size 379619 diff --git a/tests/input/mha/picai/10059/10059_1000059_cor.mha b/tests/input/mha/picai/10059/10059_1000059_cor.mha new file mode 100755 index 0000000..eae3977 --- /dev/null +++ b/tests/input/mha/picai/10059/10059_1000059_cor.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2068ed6faa8e893911cfaec6f767f26de2d98b5db407f25438971ebd9c8638b8 +size 2401935 diff --git a/tests/input/mha/picai/10059/10059_1000059_hbv.mha b/tests/input/mha/picai/10059/10059_1000059_hbv.mha new file mode 100755 index 0000000..28097e1 --- /dev/null +++ b/tests/input/mha/picai/10059/10059_1000059_hbv.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b77df784c6995901cd1455772d14b9fcbbe57470a31262e385971f29e8775905 +size 158592 diff --git a/tests/input/mha/picai/10059/10059_1000059_sag.mha b/tests/input/mha/picai/10059/10059_1000059_sag.mha new file mode 100755 index 0000000..5bbe378 --- /dev/null +++ b/tests/input/mha/picai/10059/10059_1000059_sag.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0f4105d52ee6a8e625a4f1c77c38fe28e28f952930e2a80a96f761d1d27e686 +size 2601680 diff --git a/tests/input/mha/picai/10059/10059_1000059_t2w.mha b/tests/input/mha/picai/10059/10059_1000059_t2w.mha new file mode 100755 index 0000000..152e1ee --- /dev/null +++ b/tests/input/mha/picai/10059/10059_1000059_t2w.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa241b5db8c97506e47e38b88fbe487d20b1ec63de3fa737eb32be4ff5344b0f +size 5373554 diff --git a/tests/input/mha/picai/10699/10699_1000715_adc.mha b/tests/input/mha/picai/10699/10699_1000715_adc.mha new file mode 100755 index 0000000..f73e5e8 --- /dev/null +++ b/tests/input/mha/picai/10699/10699_1000715_adc.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ba4131e879f3bdeb1bf44558c9a3aa2f1c7f03ee86cda80665c5ecd2c054e0c0 +size 122145 diff --git a/tests/input/mha/picai/10699/10699_1000715_cor.mha b/tests/input/mha/picai/10699/10699_1000715_cor.mha new file mode 100755 index 0000000..4e69106 --- /dev/null +++ b/tests/input/mha/picai/10699/10699_1000715_cor.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ffe714852d0ddf02a9867b3bef48ed95e08b958cbc7e91dcfdeaed4e87831b9b +size 1505917 diff --git a/tests/input/mha/picai/10699/10699_1000715_hbv.mha b/tests/input/mha/picai/10699/10699_1000715_hbv.mha new file mode 100755 index 0000000..37b0c09 --- /dev/null +++ b/tests/input/mha/picai/10699/10699_1000715_hbv.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18ba4d9117b1be195f00d8447d00ad4f095349a441f16b8b57d71f3b6c081637 +size 553026 diff --git a/tests/input/mha/picai/10699/10699_1000715_sag.mha b/tests/input/mha/picai/10699/10699_1000715_sag.mha new file mode 100755 index 0000000..a1eff2e --- /dev/null +++ b/tests/input/mha/picai/10699/10699_1000715_sag.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82172b1880046edd2772dd3f9d3103fe561314c8ba738cd2b4ec9a7ab699fd02 +size 3335218 diff --git a/tests/input/mha/picai/10699/10699_1000715_t2w.mha b/tests/input/mha/picai/10699/10699_1000715_t2w.mha new file mode 100755 index 0000000..5c88627 --- /dev/null +++ b/tests/input/mha/picai/10699/10699_1000715_t2w.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:714c0be3e3003c4395c8962a9ebb1d627d252d2f0241134e622967393602e08f +size 2618828 diff --git a/tests/input/mha/picai/10730/10730_1000746_adc.mha b/tests/input/mha/picai/10730/10730_1000746_adc.mha new file mode 100755 index 0000000..ff62369 --- /dev/null +++ b/tests/input/mha/picai/10730/10730_1000746_adc.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f777f70f33790ec96b8f87efdae1682ef9b9cae93224f8ce78345112a39e6f8 +size 152038 diff --git a/tests/input/mha/picai/10730/10730_1000746_cor.mha b/tests/input/mha/picai/10730/10730_1000746_cor.mha new file mode 100755 index 0000000..e2f5bf3 --- /dev/null +++ b/tests/input/mha/picai/10730/10730_1000746_cor.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bacd4c25eaa0e288ccaced9e8f59c26b9e90edc71e98c49c9a6e55b0931cde58 +size 2275221 diff --git a/tests/input/mha/picai/10730/10730_1000746_hbv.mha b/tests/input/mha/picai/10730/10730_1000746_hbv.mha new file mode 100755 index 0000000..da36c4d --- /dev/null +++ b/tests/input/mha/picai/10730/10730_1000746_hbv.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb6ae214e23facc8d6f1ee054adb735e393589fc6244128acf524e75cab76ca2 +size 73885 diff --git a/tests/input/mha/picai/10730/10730_1000746_sag.mha b/tests/input/mha/picai/10730/10730_1000746_sag.mha new file mode 100755 index 0000000..f2635bb --- /dev/null +++ b/tests/input/mha/picai/10730/10730_1000746_sag.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e1e094c1548f16420c66f84030d2059c44239d77e9b785285608a8c6ebcb883 +size 2533020 diff --git a/tests/input/mha/picai/10730/10730_1000746_t2w.mha b/tests/input/mha/picai/10730/10730_1000746_t2w.mha new file mode 100755 index 0000000..da80866 --- /dev/null +++ b/tests/input/mha/picai/10730/10730_1000746_t2w.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8743e97bc2db2e21732d94087d2ba10610b320f2746a6983fc4498e45889221a +size 7973075 diff --git a/tests/input/mha/picai/10868/10868_1000884_adc.mha b/tests/input/mha/picai/10868/10868_1000884_adc.mha new file mode 100755 index 0000000..a5f7fb2 --- /dev/null +++ b/tests/input/mha/picai/10868/10868_1000884_adc.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ae93bd351e123ab58ac412f8c997d36a8d09b76a46ff41ad6269b897c0ad1e6 +size 264597 diff --git a/tests/input/mha/picai/10868/10868_1000884_cor.mha b/tests/input/mha/picai/10868/10868_1000884_cor.mha new file mode 100755 index 0000000..9a7bf34 --- /dev/null +++ b/tests/input/mha/picai/10868/10868_1000884_cor.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32bd290ef418a66efdb56bb83841ea8c9cfd799c8aabecce08c1aacf73386a32 +size 2062141 diff --git a/tests/input/mha/picai/10868/10868_1000884_hbv.mha b/tests/input/mha/picai/10868/10868_1000884_hbv.mha new file mode 100755 index 0000000..9f27237 --- /dev/null +++ b/tests/input/mha/picai/10868/10868_1000884_hbv.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:391465840ad5911364c0042d558ab877b312f049b99c0950374fa4b26f6a916a +size 132058 diff --git a/tests/input/mha/picai/10868/10868_1000884_sag.mha b/tests/input/mha/picai/10868/10868_1000884_sag.mha new file mode 100755 index 0000000..a77c16d --- /dev/null +++ b/tests/input/mha/picai/10868/10868_1000884_sag.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c3867e0c1be2a04aec102be0fcdc2921c1d80a59347f8aaffa71637aea62495 +size 2638021 diff --git a/tests/input/mha/picai/10868/10868_1000884_t2w.mha b/tests/input/mha/picai/10868/10868_1000884_t2w.mha new file mode 100755 index 0000000..02a47bd --- /dev/null +++ b/tests/input/mha/picai/10868/10868_1000884_t2w.mha @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b282d0648357dc15f6bcb7a90c8e9d4be0c1286fd3e7ef8b567d68f364942a00 +size 3972194 diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_adc.mha b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_adc.mha index 6cdf9f7..2d34caf 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_adc.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_adc.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_cor.mha b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_cor.mha index 8cc17b6..b0cb22a 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_cor.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_cor.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_hbv.mha b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_hbv.mha index 06efaf8..e173992 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_hbv.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_hbv.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_sag.mha b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_sag.mha index 27633d7..1ad9f0d 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_sag.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_sag.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_t2w.mha b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_t2w.mha index f73cc97..05baca5 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_t2w.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0000/ProstateX-0000_07-07-2011_t2w.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_adc.mha b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_adc.mha index 40048ff..38bc785 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_adc.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_adc.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_cor.mha b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_cor.mha index 728d885..e47ab96 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_cor.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_cor.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_hbv.mha b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_hbv.mha index f5c75f1..06b44d9 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_hbv.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_hbv.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_sag.mha b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_sag.mha index b9826fa..9f68e99 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_sag.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_sag.mha differ diff --git a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_t2w.mha b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_t2w.mha index 65daab8..cfdac0a 100755 Binary files a/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_t2w.mha and b/tests/output-expected/mha/ProstateX/ProstateX-0001/ProstateX-0001_07-08-2011_t2w.mha differ diff --git a/tests/output-expected/mha2nnunet_inference_settings_picai.json b/tests/output-expected/mha2nnunet_inference_settings_picai.json new file mode 100644 index 0000000..df65180 --- /dev/null +++ b/tests/output-expected/mha2nnunet_inference_settings_picai.json @@ -0,0 +1,72 @@ +{ + "dataset_json": { + "task": "Task2201_picai_baseline", + "description": "bpMRI scans from PI-CAI dataset to train nnUNet baseline", + "tensorImageSize": "4D", + "reference": "", + "licence": "", + "release": "1.0", + "modality": { + "0": "T2W", + "1": "CT", + "2": "HBV" + }, + "labels": { + "0": "background", + "1": "lesion" + } + }, + "preprocessing": {}, + "archive": [ + { + "patient_id": "10032", + "study_id": "1000032", + "scan_paths": [ + "10032/10032_1000032_t2w.mha", + "10032/10032_1000032_adc.mha", + "10032/10032_1000032_hbv.mha" + ], + "annotation_path": "10032_1000032.nii.gz" + }, + { + "patient_id": "10059", + "study_id": "1000059", + "scan_paths": [ + "10059/10059_1000059_t2w.mha", + "10059/10059_1000059_adc.mha", + "10059/10059_1000059_hbv.mha" + ], + "annotation_path": "10059_1000059.nii.gz" + }, + { + "patient_id": "10699", + "study_id": "1000715", + "scan_paths": [ + "10699/10699_1000715_t2w.mha", + "10699/10699_1000715_adc.mha", + "10699/10699_1000715_hbv.mha" + ], + "annotation_path": "10699_1000715.nii.gz" + }, + { + "patient_id": "10730", + "study_id": "1000746", + "scan_paths": [ + "10730/10730_1000746_t2w.mha", + "10730/10730_1000746_adc.mha", + "10730/10730_1000746_hbv.mha" + ], + "annotation_path": "10730_1000746.nii.gz" + }, + { + "patient_id": "10868", + "study_id": "1000884", + "scan_paths": [ + "10868/10868_1000884_t2w.mha", + "10868/10868_1000884_adc.mha", + "10868/10868_1000884_hbv.mha" + ], + "annotation_path": "10868_1000884.nii.gz" + } + ] +} \ No newline at end of file diff --git a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.json b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.json index af4c081..485ea8e 100644 --- a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.json +++ b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.json @@ -1 +1 @@ -{"instances": {"1": 0}} \ No newline at end of file +{"instances": {"1": 2}} \ No newline at end of file diff --git a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.nii.gz b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.nii.gz index 253a477..ae8dd9f 100644 Binary files a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.nii.gz and b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0000_07-07-2011.nii.gz differ diff --git a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.json b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.json index c148a5a..af4c081 100644 --- a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.json +++ b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.json @@ -1 +1 @@ -{"instances": {}} \ No newline at end of file +{"instances": {"1": 0}} \ No newline at end of file diff --git a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.nii.gz b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.nii.gz index d26b291..32765b2 100644 Binary files a/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.nii.gz and b/tests/output-expected/nnDet_raw_data/Task100_test/raw_splitted/labelsTr/ProstateX-0001_07-08-2011.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0000.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0000.nii.gz index 0b11ce2..260bd53 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0000.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0000.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0001.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0001.nii.gz index 2fd4689..68cedad 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0001.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0001.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0002.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0002.nii.gz index 0c34582..5866a43 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0002.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0000_07-07-2011_0002.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0000.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0000.nii.gz index 5eaf11e..8917d9e 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0000.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0000.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0001.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0001.nii.gz index ff3e323..c01e82b 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0001.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0001.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0002.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0002.nii.gz index 5bcf70a..dd6b7af 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0002.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr/ProstateX-0001_07-08-2011_0002.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0000_07-07-2011.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0000_07-07-2011.nii.gz index e66e719..2423f1f 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0000_07-07-2011.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0000_07-07-2011.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0001_07-08-2011.nii.gz b/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0001_07-08-2011.nii.gz index 70c2297..8ee931a 100644 Binary files a/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0001_07-08-2011.nii.gz and b/tests/output-expected/nnUNet_raw_data/Task100_test/labelsTr/ProstateX-0001_07-08-2011.nii.gz differ diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/dataset.json b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/dataset.json new file mode 100644 index 0000000..9f895db --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/dataset.json @@ -0,0 +1,43 @@ +{ + "task": "Task2201_picai_baseline", + "description": "bpMRI scans from PI-CAI dataset to train nnUNet baseline", + "tensorImageSize": "4D", + "reference": "", + "licence": "", + "release": "1.0", + "modality": { + "0": "T2W", + "1": "CT", + "2": "HBV" + }, + "labels": { + "0": "background", + "1": "lesion" + }, + "name": "picai_baseline", + "numTraining": 5, + "numTest": 0, + "training": [ + { + "image": "./imagesTr/10032_1000032.nii.gz", + "label": "./labelsTr/10032_1000032.nii.gz" + }, + { + "image": "./imagesTr/10059_1000059.nii.gz", + "label": "./labelsTr/10059_1000059.nii.gz" + }, + { + "image": "./imagesTr/10699_1000715.nii.gz", + "label": "./labelsTr/10699_1000715.nii.gz" + }, + { + "image": "./imagesTr/10730_1000746.nii.gz", + "label": "./labelsTr/10730_1000746.nii.gz" + }, + { + "image": "./imagesTr/10868_1000884.nii.gz", + "label": "./labelsTr/10868_1000884.nii.gz" + } + ], + "test": [] +} \ No newline at end of file diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0000.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0000.nii.gz new file mode 100644 index 0000000..9a0bc30 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0000.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da4b54311ec0bdd5ce79e1b12c6391af2224ce4d701bf70549ce4b2bd58a03b3 +size 6819490 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0001.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0001.nii.gz new file mode 100644 index 0000000..4427cdc --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0001.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a78a094589567d344c605fd0860463bdd68563d818d089308048f632fd911efc +size 2083030 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0002.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0002.nii.gz new file mode 100644 index 0000000..02c9b53 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10032_1000032_0002.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e27f80b15c0a5f7c4ce7a159a69d791779fd9699fb69e47fdbe4a54257823261 +size 633930 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0000.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0000.nii.gz new file mode 100644 index 0000000..bbded0a --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0000.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df0787c2d8bf45f4b18f24f3064d08e4fd443b3b2f60e9cee8686edd80039e18 +size 5323633 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0001.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0001.nii.gz new file mode 100644 index 0000000..8d06679 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0001.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddfe0a0c7c24471dacd55ff969e15995eb9f259a22e6ae2ec8a5a098643a65d6 +size 3300315 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0002.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0002.nii.gz new file mode 100644 index 0000000..64ac1c8 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10059_1000059_0002.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95bb3e0ead647215d7a8951d13d7f64a86d1b308ffdb8357638dece6c28ff053 +size 703947 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0000.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0000.nii.gz new file mode 100644 index 0000000..4a68054 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0000.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a526dd15be12164b144ff4bdee3ac2f0d5430c43d4894333b208a8b57b15ead +size 2580340 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0001.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0001.nii.gz new file mode 100644 index 0000000..e29b14c --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0001.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9f60a7513a41a3305788f430a404913c1c83c029c26ffe272cc20038580d44b +size 1176349 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0002.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0002.nii.gz new file mode 100644 index 0000000..4dcb1eb --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10699_1000715_0002.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91584a4061fb29bb6d0c18bc517e8b59ed493b127c79fe89ade48519c39f825f +size 568445 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0000.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0000.nii.gz new file mode 100644 index 0000000..779fc6b --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0000.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ddab726f36d25ea36614c9ff465d195b550763031bf616ce39923c46590877f +size 7924033 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0001.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0001.nii.gz new file mode 100644 index 0000000..7f14292 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0001.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c3d90ff0fb9a8ff4b0a146d5f86abbcfb657f2166ac257b630855317d3cddf7 +size 2170690 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0002.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0002.nii.gz new file mode 100644 index 0000000..e2b378d --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10730_1000746_0002.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:decefe5a8b2199a56808573ab283c647f9c7be0030bbc9aa676bba276564231c +size 490699 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0000.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0000.nii.gz new file mode 100644 index 0000000..d40ac83 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0000.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f45763ebbaed74aaa540dc883587daa7917382610affc8661c4ca0692fc16e6d +size 3909839 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0001.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0001.nii.gz new file mode 100644 index 0000000..176ac8d --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0001.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc860d0f260aa07fcd818aa96e2dfed7a483d51942573a6d3a61d5eeda6cb111 +size 3331533 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0002.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0002.nii.gz new file mode 100644 index 0000000..949eda2 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/imagesTr/10868_1000884_0002.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09cdb531a6ca4cd36d03f234902be097e37026fc4a3dd6137641e3300b99b6bd +size 825908 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10032_1000032.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10032_1000032.nii.gz new file mode 100644 index 0000000..af4c899 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10032_1000032.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd3b201d43a8b77dd67a1eb67067d811bf8246acb53c7d5ab5a79823366c9544 +size 6368 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10059_1000059.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10059_1000059.nii.gz new file mode 100644 index 0000000..793d1d6 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10059_1000059.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e3f8f4697f7049b690697e52b4306cac43710f89df68ede67d31a449683a47d +size 5776 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10699_1000715.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10699_1000715.nii.gz new file mode 100644 index 0000000..42d164a --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10699_1000715.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:238fd47ea3694cb53d95150f1e34033c242d650289b756dac13b5308a0ea47f5 +size 4533 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10730_1000746.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10730_1000746.nii.gz new file mode 100644 index 0000000..e402d7e --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10730_1000746.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0d5ca6dec5fbd2f0c691b011d960b1a5a01ad557bed8f227d4c6684e3d0eab6 +size 7415 diff --git a/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10868_1000884.nii.gz b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10868_1000884.nii.gz new file mode 100644 index 0000000..31e2560 --- /dev/null +++ b/tests/output-expected/nnUNet_raw_data/Task2201_picai_baseline/labelsTr/10868_1000884.nii.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee31c312668545d8d14a083d0f540232ebe84b47be8fa8b7471fa793e074507f +size 6283 diff --git a/tests/test_mha2nnunet.py b/tests/test_mha2nnunet.py index 72d5416..6c00add 100644 --- a/tests/test_mha2nnunet.py +++ b/tests/test_mha2nnunet.py @@ -19,55 +19,66 @@ from pathlib import Path from numpy.testing import assert_allclose import SimpleITK as sitk +from typing import Optional, List from picai_prep.data_utils import PathLike from picai_prep.mha2nnunet import MHA2nnUNetConverter +from picai_prep.examples.mha2nnunet import picai_archive def test_mha2nnunet( input_dir: PathLike = "tests/output-expected/mha/ProstateX", annotations_dir: PathLike = "tests/input/annotations/ProstateX", output_dir: PathLike = "tests/output/nnUNet_raw_data", - output_expected_dir: PathLike = "tests/output-expected/nnUNet_raw_data/Task100_test", + output_expected_dir: PathLike = "tests/output-expected/nnUNet_raw_data", + settings_path: PathLike = "tests/output-expected/mha2nnunet_settings.json", + task_name: str = "Task100_test", + subject_list: Optional[List[str]] = None, ): """ Convert sample MHA archive to nnUNet raw data format """ + if subject_list is None: + subject_list = [ + "ProstateX-0000_07-07-2011", + "ProstateX-0001_07-08-2011", + ] + # convert input paths to Path input_dir = Path(input_dir) annotations_dir = Path(annotations_dir) output_dir = Path(output_dir) output_expected_dir = Path(output_expected_dir) + task_dir = output_dir / task_name # remove output folder (to prevent skipping the conversion) - if os.path.exists(output_dir): - shutil.rmtree(output_dir) + if os.path.exists(task_dir): + shutil.rmtree(task_dir) # convert MHA archive to nnUNet raw data archive = MHA2nnUNetConverter( input_path=input_dir.as_posix(), annotations_path=annotations_dir.as_posix(), output_path=output_dir.as_posix(), - settings_path="tests/output-expected/mha2nnunet_settings.json" + settings_path=settings_path, ) archive.convert() # check dataset.json - path_out = output_dir / "Task100_test" / "dataset.json" - path_out_expected = output_expected_dir / "dataset.json" + path_out = task_dir / "dataset.json" + path_out_expected = output_expected_dir / task_name / "dataset.json" with open(path_out) as fp1, open(path_out_expected) as fp2: assert json.load(fp1) == json.load(fp2) # compare output - for subject_id in [ - "ProstateX-0000_07-07-2011", - "ProstateX-0001_07-08-2011", - ]: + for subject_id in subject_list: + print(f"Checking case {subject_id}...") case_origin, case_direction = None, None + for modality in ["0000", "0001", "0002"]: # construct paths to MHA images - path_out = output_dir / "Task100_test" / "imagesTr" / f"{subject_id}_{modality}.nii.gz" - path_out_expected = output_expected_dir / "imagesTr" / f"{subject_id}_{modality}.nii.gz" + path_out = task_dir / "imagesTr" / f"{subject_id}_{modality}.nii.gz" + path_out_expected = output_expected_dir / task_name / "imagesTr" / f"{subject_id}_{modality}.nii.gz" # sanity check: check if outputs exist assert path_out.exists(), f"Could not find output file at {path_out}!" @@ -92,8 +103,8 @@ def test_mha2nnunet( # check annotation # construct paths - path_out = output_dir / "Task100_test" / "labelsTr" / f"{subject_id}.nii.gz" - path_out_expected = output_expected_dir / "labelsTr" / f"{subject_id}.nii.gz" + path_out = task_dir / "labelsTr" / f"{subject_id}.nii.gz" + path_out_expected = output_expected_dir / task_name / "labelsTr" / f"{subject_id}.nii.gz" # sanity check: check if outputs exist assert path_out.exists(), f"Could not find output file at {path_out}!" @@ -110,44 +121,51 @@ def test_mha2nnunet( def test_mha2nnunet_inference( input_dir: PathLike = "tests/output-expected/mha/ProstateX", output_dir: PathLike = "tests/output/nnUNet_raw_data", - output_expected_dir: PathLike = "tests/output-expected/nnUNet_raw_data/Task100_test", + output_expected_dir: PathLike = "tests/output-expected/nnUNet_raw_data", + settings_path: PathLike = "tests/output-expected/mha2nnunet_inference_settings.json", + task_name: str = "Task100_test", + subject_list: Optional[List[str]] = None, ): """ Convert sample MHA archive to nnUNet raw data format (images only) """ + if subject_list is None: + subject_list = [ + "ProstateX-0000_07-07-2011", + "ProstateX-0001_07-08-2011", + ] + # convert input paths to Path input_dir = Path(input_dir) output_dir = Path(output_dir) output_expected_dir = Path(output_expected_dir) + task_dir = output_dir / task_name # remove output folder (to prevent skipping the conversion) - if os.path.exists(output_dir): - shutil.rmtree(output_dir) + if os.path.exists(task_dir): + shutil.rmtree(task_dir) # convert MHA archive to nnUNet raw data archive = MHA2nnUNetConverter( input_path=input_dir.as_posix(), output_path=output_dir.as_posix(), out_dir_scans="imagesTs", - settings_path="tests/output-expected/mha2nnunet_inference_settings.json" + settings_path=settings_path ) archive.convert() # check dataset.json - path_out = output_dir / "Task100_test" / "dataset.json" - path_out_expected = output_expected_dir / "dataset.json" + path_out = output_dir / task_name / "dataset.json" + path_out_expected = output_expected_dir / task_name / "dataset.json" with open(path_out) as fp1, open(path_out_expected) as fp2: assert json.load(fp1) == json.load(fp2) # compare output - for subject_id in [ - "ProstateX-0000_07-07-2011", - "ProstateX-0001_07-08-2011", - ]: + for subject_id in subject_list: for modality in ["0000", "0001", "0002"]: # construct paths to MHA images - path_out = output_dir / "Task100_test" / "imagesTs" / f"{subject_id}_{modality}.nii.gz" - path_out_expected = output_expected_dir / "imagesTr" / f"{subject_id}_{modality}.nii.gz" + path_out = output_dir / task_name / "imagesTs" / f"{subject_id}_{modality}.nii.gz" + path_out_expected = output_expected_dir / task_name / "imagesTr" / f"{subject_id}_{modality}.nii.gz" # sanity check: check if outputs exist assert path_out.exists(), f"Could not find output file at {path_out}!" @@ -161,8 +179,55 @@ def test_mha2nnunet_inference( assert_allclose(img_expected, img) # assert no annotations were converted - path_out = output_dir / "Task100_test" / "labelsTs" / f"{subject_id}_{modality}.nii.gz" + path_out = output_dir / task_name / "labelsTs" / f"{subject_id}_{modality}.nii.gz" assert not os.path.exists(path_out), "Annotation should not be converted for inference mha2nnunet" - path_out = output_dir / "Task100_test" / "labelsTr" / f"{subject_id}_{modality}.nii.gz" + path_out = output_dir / task_name / "labelsTr" / f"{subject_id}_{modality}.nii.gz" assert not os.path.exists(path_out), "Annotation should not be converted for inference mha2nnunet" + + +def test_mha2nnunet_picai( + input_dir: PathLike = "tests/input/mha/picai", + annotations_dir: PathLike = "tests/input/annotations/picai/csPCa_lesion_delineations/human_expert/resampled", + output_dir: PathLike = "tests/output/nnUNet_raw_data", + output_expected_dir: PathLike = "tests/output-expected/nnUNet_raw_data", + settings_path: PathLike = "tests/output-expected/mha2nnunet_inference_settings_picai.json", + task_name: str = "Task2201_picai_baseline", +): + """ + Test mha2nnunet preprocessing with tricky cases from the PI-CAI: Public Training and Development Dataset. + These cases are typicaly very off-centre, and contain different field-of-views between sequences. + + Notes: + - 10032_1000032 has a different field-of-view between axial T2-weighted and diffusion scans. + - 10059_1000059 has a padded T2-weighted scan, and different field-of-view between sequences. + - 10699_1000715_0002.nii.gz contains all diffusion scans, which is an accident of the released MHA scan. + - 10730_1000746 is similar to 10059_1000059, but padded on the other side. + - 10868_1000884 is pretty normal. T2-weighted has 21 slices, while diffusion has 19, which is representative. + - except for 10699_1000715_0002, all cases in output-expected are aligned between sequences. + """ + picai_archive.generate_mha2nnunet_settings( + archive_dir=input_dir, + annotations_dir=annotations_dir, + output_path=settings_path + ) + + test_mha2nnunet( + input_dir=input_dir, + annotations_dir=annotations_dir, + output_dir=output_dir, + output_expected_dir=output_expected_dir, + settings_path=settings_path, + task_name=task_name, + subject_list=[ + "10032_1000032", + "10059_1000059", + "10699_1000715", + "10730_1000746", + "10868_1000884", + ] + ) + + +if __name__ == "__main__": + test_mha2nnunet_picai() diff --git a/tests/test_preprocessing.py b/tests/test_preprocessing.py deleted file mode 100644 index 206fd08..0000000 --- a/tests/test_preprocessing.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2022 Diagnostic Image Analysis Group, Radboudumc, Nijmegen, The Netherlands -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import os -from numpy.testing import assert_allclose -from pathlib import Path -import SimpleITK as sitk -import pytest - -from picai_prep.preprocessing import Sample, PreprocessingSettings -from picai_prep.data_utils import atomic_image_write - - -@pytest.mark.parametrize("subject_id", [ - "ProstateX-0000_07-07-2011", - "ProstateX-0001_07-08-2011", -]) -def test_preprocessing_for_nnunet_inference(subject_id): - """ - Preprocess mpMRI scans (align, resample, crop, ...) - """ - # setup - input_dir = Path("tests/output/mha/ProstateX") - output_dir = Path("tests/output/nnUNet_raw_data-preprocess_mpMRI_study") - expected_output_dir = Path("tests/output-expected/nnUNet_raw_data/Task100_test/imagesTr") - spacing = (3.0, 0.5, 0.5) - matrix_size = (20, 160, 160) - physical_size = [ - voxel_spacing * size - for voxel_spacing, size in zip(spacing, matrix_size) - ] - - # pack info - patient_id = subject_id.split('_')[0] - all_scan_properties = [ - { - 'input_path': input_dir / patient_id / f"{subject_id}_t2w.mha", - 'output_path': output_dir / f"{subject_id}_0000.nii.gz", - 'type': 'T2W', - }, - { - 'input_path': input_dir / patient_id / f"{subject_id}_adc.mha", - 'output_path': output_dir / f"{subject_id}_0001.nii.gz", - 'type': 'ADC', - }, - { - 'input_path': input_dir / patient_id / f"{subject_id}_hbv.mha", - 'output_path': output_dir / f"{subject_id}_0002.nii.gz", - 'type': 'HBV', - }, - ] - - # read images - scans = [] - for scan_properties in all_scan_properties: - scans += [sitk.ReadImage(str(scan_properties['input_path']))] - - # perform preprocessing - sample = Sample( - scans=scans, - lbl=None, - settings=PreprocessingSettings( - physical_size=physical_size, - spacing=spacing, - ), - name=subject_id, - ) - sample.preprocess() - - assert sample.lbl is None, "Label was created out of thin air!" - - # write images - for scan, scan_properties in zip(sample.scans, all_scan_properties): - atomic_image_write(scan, path=scan_properties['output_path'], mkdir=True) - - # verify result - for modality in ["0000", "0001", "0002"]: - path_out = output_dir / f"{subject_id}_{modality}.nii.gz" - path_out_expected = expected_output_dir / f"{subject_id}_{modality}.nii.gz" - - # sanity check: check if outputs exist - assert os.path.exists(path_out), f"Could not find output file at {path_out}!" - assert os.path.exists(path_out_expected), f"Could not find output file at {path_out_expected}!" - - # read images - img = sitk.GetArrayFromImage(sitk.ReadImage(str(path_out))) - img_expected = sitk.GetArrayFromImage(sitk.ReadImage(str(path_out_expected))) - - # compare images - assert_allclose(img_expected, img)