def test_use_case(self): with tempfile.TemporaryDirectory() as tempdir: img_ = nib.Nifti1Image(np.random.randint(0, 2, size=(20, 20, 20)), np.eye(4)) seg_ = nib.Nifti1Image(np.random.randint(0, 2, size=(20, 20, 20)), np.eye(4)) img_name, seg_name = os.path.join(tempdir, "img.nii.gz"), os.path.join( tempdir, "seg.nii.gz") nib.save(img_, img_name) nib.save(seg_, seg_name) img_list, seg_list = [img_name], [seg_name] img_xform = _TestCompose([ EnsureChannelFirst(), Spacing(pixdim=(1.5, 1.5, 3.0)), RandAdjustContrast() ]) seg_xform = _TestCompose([ EnsureChannelFirst(), Spacing(pixdim=(1.5, 1.5, 3.0), mode="nearest") ]) img_dataset = ImageDataset( image_files=img_list, seg_files=seg_list, transform=img_xform, seg_transform=seg_xform, image_only=False, transform_with_metadata=True, ) self.assertTupleEqual(img_dataset[0][0].shape, (1, 14, 14, 7)) self.assertTupleEqual(img_dataset[0][1].shape, (1, 14, 14, 7))
def test_spacing(self, in_type, init_param, img, data_param, expected_output): _img = in_type(img) output_data, _, new_affine = Spacing(**init_param)(_img, **data_param) if isinstance(_img, torch.Tensor): self.assertEqual(_img.device, output_data.device) output_data = output_data.cpu() np.testing.assert_allclose(output_data, expected_output, atol=1e-3, rtol=1e-3) sr = len(output_data.shape) - 1 if isinstance(init_param["pixdim"], float): init_param["pixdim"] = [init_param["pixdim"]] * sr init_pixdim = ensure_tuple(init_param["pixdim"]) init_pixdim = init_param["pixdim"][:sr] norm = np.sqrt(np.sum(np.square(new_affine), axis=0))[:sr] np.testing.assert_allclose(fall_back_tuple(init_pixdim, norm), norm)
def test_consistency(self): np.set_printoptions(suppress=True, precision=3) test_image = make_nifti_image( np.arange(64).reshape(1, 8, 8), np.diag([1.5, 1.5, 1.5, 1])) data, header = LoadImage(reader="NibabelReader", as_closest_canonical=False)(test_image) data, original_affine, new_affine = Spacing([0.8, 0.8, 0.8])(data[None], header["affine"], mode="nearest") data, _, new_affine = Orientation("ILP")(data, new_affine) if os.path.exists(test_image): os.remove(test_image) write_nifti(data[0], test_image, new_affine, original_affine, mode="nearest", padding_mode="border") saved = nib.load(test_image) saved_data = saved.get_fdata() np.testing.assert_allclose(saved_data, np.arange(64).reshape(1, 8, 8), atol=1e-7) if os.path.exists(test_image): os.remove(test_image) write_nifti( data[0], test_image, new_affine, original_affine, mode="nearest", padding_mode="border", output_spatial_shape=(1, 8, 8), ) saved = nib.load(test_image) saved_data = saved.get_fdata() np.testing.assert_allclose(saved_data, np.arange(64).reshape(1, 8, 8), atol=1e-7) if os.path.exists(test_image): os.remove(test_image) # test the case that only correct orientation but don't resample write_nifti(data[0], test_image, new_affine, original_affine, resample=False) saved = nib.load(test_image) # compute expected affine start_ornt = nib.orientations.io_orientation(new_affine) target_ornt = nib.orientations.io_orientation(original_affine) ornt_transform = nib.orientations.ornt_transform( start_ornt, target_ornt) data_shape = data[0].shape expected_affine = new_affine @ nib.orientations.inv_ornt_aff( ornt_transform, data_shape) np.testing.assert_allclose(saved.affine, expected_affine) if os.path.exists(test_image): os.remove(test_image)
def test_consistency(self): np.set_printoptions(suppress=True, precision=3) test_image = make_nifti_image(np.arange(64).reshape(1, 8, 8), np.diag([1.5, 1.5, 1.5, 1])) data, header = LoadNifti(as_closest_canonical=False)(test_image) data, original_affine, new_affine = Spacing([0.8, 0.8, 0.8])( data[None], header["affine"], interp_order="nearest" ) data, _, new_affine = Orientation("ILP")(data, new_affine) if os.path.exists(test_image): os.remove(test_image) write_nifti(data[0], test_image, new_affine, original_affine, interp_order="nearest", mode="border") saved = nib.load(test_image) saved_data = saved.get_fdata() np.testing.assert_allclose(saved_data, np.arange(64).reshape(1, 8, 8), atol=1e-7) if os.path.exists(test_image): os.remove(test_image) write_nifti( data[0], test_image, new_affine, original_affine, interp_order="nearest", mode="border", output_shape=(1, 8, 8), ) saved = nib.load(test_image) saved_data = saved.get_fdata() np.testing.assert_allclose(saved_data, np.arange(64).reshape(1, 8, 8), atol=1e-7) if os.path.exists(test_image): os.remove(test_image)
def test_inverse_array(self, use_compose, dtype, device): img: MetaTensor tr = Compose([ AddChannel(), Orientation("RAS"), Flip(1), Spacing([1.0, 1.2, 0.9], align_corners=False) ]) num_invertible = len( [i for i in tr.transforms if isinstance(i, InvertibleTransform)]) # forward img = tr(self.get_image(dtype, device)) self.assertEqual(len(img.applied_operations), num_invertible) # inverse with Compose if use_compose: img = tr.inverse(img) self.assertEqual(len(img.applied_operations), 0) # inverse individually else: _tr: InvertibleTransform num_to_inverse = num_invertible for _tr in tr.transforms[::-1]: if isinstance(_tr, InvertibleTransform): img = _tr.inverse(img) num_to_inverse -= 1 self.assertEqual(len(img.applied_operations), num_to_inverse)
def __call__( self, data: Mapping[Union[Hashable, str], Dict[str, np.ndarray]] ) -> Dict[Union[Hashable, str], Union[np.ndarray, Dict[str, np.ndarray]]]: d = dict(data) for idx, key in enumerate(self.keys): meta_data = d[f"{key}_{self.meta_key_postfix}"] # set pixdim to original pixdim value where required current_pixdim = copy.deepcopy(self.pixdim) original_pixdim = meta_data["pixdim"] old_pixdim = original_pixdim[1:4] current_pixdim[self.dim_to_keep] = old_pixdim[self.dim_to_keep] # apply the transform spacing_transform = Spacing(current_pixdim, diagonal=self.diagonal) # resample array of each corresponding key # using affine fetched from d[affine_key] d[key], _, new_affine = spacing_transform( data_array=d[key], affine=meta_data["affine"], mode=self.mode[idx], padding_mode=self.padding_mode[idx], align_corners=self.align_corners[idx], dtype=self.dtype[idx], ) # store the modified affine meta_data["affine"] = new_affine return d
def test_consistency(self): np.set_printoptions(suppress=True, precision=3) test_image = make_nifti_image( np.arange(64).reshape(1, 8, 8), np.diag([1.5, 1.5, 1.5, 1])) data, header = LoadImage(reader="NibabelReader", as_closest_canonical=False)(test_image) data, original_affine, new_affine = Spacing([0.8, 0.8, 0.8])(data[None], header["affine"], mode="nearest") data, _, new_affine = Orientation("ILP")(data, new_affine) if os.path.exists(test_image): os.remove(test_image) writer_obj = NibabelWriter() writer_obj.set_data_array(data[0], channel_dim=None) writer_obj.set_metadata(meta_dict={ "affine": new_affine, "original_affine": original_affine }, mode="nearest", padding_mode="border") writer_obj.write(test_image, verbose=True) saved = nib.load(test_image) saved_data = saved.get_fdata() np.testing.assert_allclose(saved_data, np.arange(64).reshape(1, 8, 8), atol=1e-7) if os.path.exists(test_image): os.remove(test_image) writer_obj.set_data_array(data[0], channel_dim=None) writer_obj.set_metadata( meta_dict={ "affine": new_affine, "original_affine": original_affine, "spatial_shape": (1, 8, 8) }, mode="nearest", padding_mode="border", ) writer_obj.write(test_image, verbose=True) saved = nib.load(test_image) saved_data = saved.get_fdata() np.testing.assert_allclose(saved_data, np.arange(64).reshape(1, 8, 8), atol=1e-7) if os.path.exists(test_image): os.remove(test_image) # test the case no resample writer_obj.set_data_array(data[0], channel_dim=None) writer_obj.set_metadata(meta_dict={ "affine": new_affine, "original_affine": original_affine }, resample=False) writer_obj.write(test_image, verbose=True) saved = nib.load(test_image) np.testing.assert_allclose(saved.affine, new_affine) if os.path.exists(test_image): os.remove(test_image)
def test_spacing(self, init_param, img, data_param, expected_output): res = Spacing(**init_param)(img, **data_param) np.testing.assert_allclose(res[0], expected_output, atol=1e-6) sr = len(res[0].shape) - 1 if isinstance(init_param["pixdim"], float): init_param["pixdim"] = [init_param["pixdim"]] * sr init_pixdim = ensure_tuple(init_param["pixdim"]) init_pixdim = init_param["pixdim"][:sr] np.testing.assert_allclose(init_pixdim[:sr], np.sqrt(np.sum(np.square(res[2]), axis=0))[:sr])
def test_inverse(self, device): img_t = torch.rand((1, 10, 9, 8), dtype=torch.float32, device=device) affine = torch.tensor( [[0, 0, -1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=torch.float32, device="cpu") meta = {"fname": "somewhere"} img = MetaTensor(img_t, affine=affine, meta=meta) tr = Spacing(pixdim=[1.1, 1.2, 0.9]) # check that image and affine have changed img = tr(img) self.assertNotEqual(img.shape, img_t.shape) l2_norm_affine = ((affine - img.affine)**2).sum()**0.5 self.assertGreater(l2_norm_affine, 5e-2) # check that with inverse, image affine are back to how they were img = tr.inverse(img) self.assertEqual(img.applied_operations, []) self.assertEqual(img.shape, img_t.shape) l2_norm_affine = ((affine - img.affine)**2).sum()**0.5 self.assertLess(l2_norm_affine, 5e-2)
def test_spacing_torch(self, pixdim, img, track_meta: bool): set_track_meta(track_meta) tr = Spacing(pixdim=pixdim) res = tr(img) if track_meta: self.assertIsInstance(res, MetaTensor) new_spacing = affine_to_spacing(res.affine, 3) assert_allclose(new_spacing, pixdim, type_test=False) self.assertNotEqual(img.shape, res.shape) else: self.assertIsInstance(res, torch.Tensor) self.assertNotIsInstance(res, MetaTensor) self.assertNotEqual(img.shape, res.shape) set_track_meta(True)
def test_spacing(self, init_param, img, affine, data_param, expected_output, device): img = MetaTensor(img, affine=affine).to(device) res: MetaTensor = Spacing(**init_param)(img, **data_param) self.assertEqual(img.device, res.device) assert_allclose(res, expected_output, atol=1e-1, rtol=1e-1) sr = min(len(res.shape) - 1, 3) if isinstance(init_param["pixdim"], float): init_param["pixdim"] = [init_param["pixdim"]] * sr init_pixdim = ensure_tuple(init_param["pixdim"]) init_pixdim = init_param["pixdim"][:sr] norm = affine_to_spacing(res.affine, sr).cpu().numpy() assert_allclose(fall_back_tuple(init_pixdim, norm), norm, type_test=False)
def test_invert(self): set_determinism(seed=0) im_fname = make_nifti_image(create_test_image_3d(101, 100, 107, noise_max=100)[1]) # label image, discrete data = [im_fname for _ in range(12)] transform = Compose( [ LoadImage(image_only=True), EnsureChannelFirst(), Orientation("RPS"), Spacing(pixdim=(1.2, 1.01, 0.9), mode="bilinear", dtype=np.float32), RandFlip(prob=0.5, spatial_axis=[1, 2]), RandAxisFlip(prob=0.5), RandRotate90(prob=0, spatial_axes=(1, 2)), RandZoom(prob=0.5, min_zoom=0.5, max_zoom=1.1, keep_size=True), RandRotate(prob=0.5, range_x=np.pi, mode="bilinear", align_corners=True, dtype=np.float64), RandAffine(prob=0.5, rotate_range=np.pi, mode="nearest"), ResizeWithPadOrCrop(100), CastToType(dtype=torch.uint8), ] ) # num workers = 0 for mac or gpu transforms num_workers = 0 if sys.platform != "linux" or torch.cuda.is_available() else 2 dataset = Dataset(data, transform=transform) self.assertIsInstance(transform.inverse(dataset[0]), MetaTensor) loader = DataLoader(dataset, num_workers=num_workers, batch_size=1) inverter = Invert(transform=transform, nearest_interp=True, device="cpu") for d in loader: d = decollate_batch(d) for item in d: orig = deepcopy(item) i = inverter(item) self.assertTupleEqual(orig.shape[1:], (100, 100, 100)) # check the nearest interpolation mode torch.testing.assert_allclose(i.to(torch.uint8).to(torch.float), i.to(torch.float)) self.assertTupleEqual(i.shape[1:], (100, 101, 107)) # check labels match reverted = i.detach().cpu().numpy().astype(np.int32) original = LoadImage(image_only=True)(data[-1]) n_good = np.sum(np.isclose(reverted, original.numpy(), atol=1e-3)) reverted_name = i.meta["filename_or_obj"] original_name = original.meta["filename_or_obj"] self.assertEqual(reverted_name, original_name) print("invert diff", reverted.size - n_good) self.assertTrue((reverted.size - n_good) < 300000, f"diff. {reverted.size - n_good}") set_determinism(seed=None)
] class TestCompose(Compose): def __call__(self, input_): img, metadata = self.transforms[0](input_) img = self.transforms[1](img) img, _, _ = self.transforms[2](img, metadata["affine"]) return self.transforms[3](img), metadata TEST_CASE_3 = [ TestCompose([ LoadNifti(image_only=False), AddChannel(), Spacing(pixdim=(2, 2, 4)), RandAdjustContrast(prob=1.0) ]), TestCompose([ LoadNifti(image_only=False), AddChannel(), Spacing(pixdim=(2, 2, 4)), RandAdjustContrast(prob=1.0) ]), (0, 2), (1, 64, 64, 33), ] TEST_CASE_4 = [ Compose([ LoadNifti(image_only=True),
Compose([LoadNifti(image_only=True), AddChannel(), RandAdjustContrast(prob=1.0)]), (0, 1), (1, 128, 128, 128), ] class TestCompose(Compose): def __call__(self, input_): img, metadata = self.transforms[0](input_) img = self.transforms[1](img) img, _, _ = self.transforms[2](img, metadata["affine"]) return self.transforms[3](img), metadata TEST_CASE_3 = [ TestCompose([LoadNifti(image_only=False), AddChannel(), Spacing(pixdim=(2, 2, 4)), RandAdjustContrast(prob=1.0)]), TestCompose([LoadNifti(image_only=False), AddChannel(), Spacing(pixdim=(2, 2, 4)), RandAdjustContrast(prob=1.0)]), (0, 2), (1, 64, 64, 33), ] TEST_CASE_4 = [ Compose([LoadNifti(image_only=True), AddChannel(), RandGaussianNoise(prob=1.0)]), (1, 128, 128, 128), ] class TestArrayDataset(unittest.TestCase): @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) def test_shape(self, img_transform, label_transform, indexes, expected_shape): test_image = nib.Nifti1Image(np.random.randint(0, 2, size=(128, 128, 128)), np.eye(4))
from monai.utils import convert_data_type, optional_import from tests.utils import assert_allclose, download_url_or_skip_test, testing_data_config itk, has_itk = optional_import("itk") TINY_DIFF = 1e-4 keys = ("img1", "img2") key, key_1 = "ref_avg152T1_LR", "ref_avg152T1_RL" FILE_PATH = os.path.join(os.path.dirname(__file__), "testing_data", f"{key}.nii.gz") FILE_PATH_1 = os.path.join(os.path.dirname(__file__), "testing_data", f"{key_1}.nii.gz") TEST_CASES_ARRAY = [ [ Compose([Spacing(pixdim=(1.0, 1.1, 1.2)), Orientation(axcodes="RAS")]), {}, TINY_DIFF ], [ Compose([Orientation(axcodes="RAS"), Spacing(pixdim=(1.0, 1.1, 1.2))]), {}, TINY_DIFF ], ["CropForeground", { "k_divisible": 3 }, TINY_DIFF], ["BorderPad", { "spatial_border": (2, 3, 4) }, TINY_DIFF], ["CenterScaleCrop", { "roi_scale": (0.6, 0.7, 0.8) }, TINY_DIFF],
def test_ill_pixdim(self): with self.assertRaises(ValueError): Spacing(pixdim=(-1, 2.0))(np.zeros((1, 1)))