def test_smooth_image(): # Test image smoothing data = np.arange(24).reshape((2, 3, 4)) aff = np.diag([-4, 5, 6, 1]) img = Nifti1Image(data, aff) # Zero smoothing is no-op out_img = smooth_image(img, 0) assert_array_equal(out_img.affine, img.affine) assert_array_equal(out_img.shape, img.shape) assert_array_equal(out_img.dataobj, data) # Isotropic smoothing sd = fwhm2sigma(np.true_divide(8, [4, 5, 6])) exp_out = spnd.gaussian_filter(data, sd, mode='nearest') assert_array_equal(smooth_image(img, 8).dataobj, exp_out) assert_array_equal(smooth_image(img, [8, 8, 8]).dataobj, exp_out) assert_raises(ValueError, smooth_image, img, [8, 8]) # Not isotropic mixed_sd = fwhm2sigma(np.true_divide([8, 7, 6], [4, 5, 6])) exp_out = spnd.gaussian_filter(data, mixed_sd, mode='nearest') assert_array_equal(smooth_image(img, [8, 7, 6]).dataobj, exp_out) # In 2D img_2d = Nifti1Image(data[0], aff) exp_out = spnd.gaussian_filter(data[0], sd[:2], mode='nearest') assert_array_equal(smooth_image(img_2d, 8).dataobj, exp_out) assert_array_equal(smooth_image(img_2d, [8, 8]).dataobj, exp_out) assert_raises(ValueError, smooth_image, img_2d, [8, 8, 8]) # Isotropic in 4D has zero for last dimension in scalar case data_4d = np.arange(24 * 5).reshape((2, 3, 4, 5)) img_4d = Nifti1Image(data_4d, aff) exp_out = spnd.gaussian_filter(data_4d, list(sd) + [0], mode='nearest') assert_array_equal(smooth_image(img_4d, 8).dataobj, exp_out) # But raises error for vector case assert_raises(ValueError, smooth_image, img_4d, [8, 8, 8]) # mode, cval exp_out = spnd.gaussian_filter(data, sd, mode='constant') assert_array_equal(smooth_image(img, 8, mode='constant').dataobj, exp_out) exp_out = spnd.gaussian_filter(data, sd, mode='constant', cval=99) assert_array_equal(smooth_image(img, 8, mode='constant', cval=99).dataobj, exp_out) # out_class img_ni1 = Nifti2Image(data, np.eye(4)) img_ni2 = Nifti2Image(data, np.eye(4)) # Default is Nifti1Image assert_equal( smooth_image(img_ni2, 0).__class__, Nifti1Image) # Can be overriden assert_equal( smooth_image(img_ni1, 0, out_class=Nifti2Image).__class__, Nifti2Image) # None specifies out_class from input assert_equal( smooth_image(img_ni2, 0, out_class=None).__class__, Nifti2Image)
def test_resample_from_to(): # Test resampling from image to image / image space data = np.arange(24).reshape((2, 3, 4)) affine = np.diag([-4, 5, 6, 1]) img = Nifti1Image(data, affine) img.header['descrip'] = 'red shirt image' out = resample_from_to(img, img) assert_almost_equal(img.dataobj, out.dataobj) assert_array_equal(img.affine, out.affine) # Check resampling reverses effect of flipping axes # This will also test translations flip_ornt = np.array([[0, 1], [1, 1], [2, 1]]) for axis in (0, 1, 2): ax_flip_ornt = flip_ornt.copy() ax_flip_ornt[axis, 1] = -1 aff_flip_i = inv_ornt_aff(ax_flip_ornt, (2, 3, 4)) flipped_img = Nifti1Image(flip_axis(data, axis), np.dot(affine, aff_flip_i)) out = resample_from_to(flipped_img, ((2, 3, 4), affine)) assert_almost_equal(img.dataobj, out.dataobj) assert_array_equal(img.affine, out.affine) # A translation of one voxel on each axis trans_aff = from_matvec(np.diag([-4, 5, 6]), [4, -5, -6]) trans_img = Nifti1Image(data, trans_aff) out = resample_from_to(trans_img, img) exp_out = np.zeros_like(data) exp_out[:-1, :-1, :-1] = data[1:, 1:, 1:] assert_almost_equal(out.dataobj, exp_out) out = resample_from_to(img, trans_img) trans_exp_out = np.zeros_like(data) trans_exp_out[1:, 1:, 1:] = data[:-1, :-1, :-1] assert_almost_equal(out.dataobj, trans_exp_out) # Test mode with translation of first axis only # Default 'constant' mode first trans1_aff = from_matvec(np.diag([-4, 5, 6]), [4, 0, 0]) trans1_img = Nifti1Image(data, trans1_aff) out = resample_from_to(img, trans1_img) exp_out = np.zeros_like(data) exp_out[1:, :, :] = data[:-1, :, :] assert_almost_equal(out.dataobj, exp_out) # Then 'nearest' mode out = resample_from_to(img, trans1_img, mode='nearest') exp_out[0, :, :] = exp_out[1, :, :] assert_almost_equal(out.dataobj, exp_out) # Test order trans_p_25_aff = from_matvec(np.diag([-4, 5, 6]), [1, 0, 0]) trans_p_25_img = Nifti1Image(data, trans_p_25_aff) # Suprising to me, but all points outside are set to 0, even with NN out = resample_from_to(img, trans_p_25_img, order=0) exp_out = np.zeros_like(data) exp_out[1:, :, :] = data[1, :, :] assert_almost_equal(out.dataobj, exp_out) out = resample_from_to(img, trans_p_25_img) exp_out = spnd.affine_transform(data, [1, 1, 1], [-0.25, 0, 0], order=3) assert_almost_equal(out.dataobj, exp_out) # Test cval out = resample_from_to(img, trans_img, cval=99) exp_out = np.zeros_like(data) + 99 exp_out[1:, 1:, 1:] = data[:-1, :-1, :-1] assert_almost_equal(out.dataobj, exp_out) # Out class out = resample_from_to(img, trans_img) assert out.__class__ == Nifti1Image # By default, type of from_img makes no difference n1_img = Nifti2Image(data, affine) out = resample_from_to(n1_img, trans_img) assert out.__class__ == Nifti1Image # Passed as keyword arg out = resample_from_to(img, trans_img, out_class=Nifti2Image) assert out.__class__ == Nifti2Image # If keyword arg is None, use type of from_img out = resample_from_to(n1_img, trans_img, out_class=None) assert out.__class__ == Nifti2Image # to_img type irrelevant in all cases n1_trans_img = Nifti2Image(data, trans_aff) out = resample_from_to(img, n1_trans_img, out_class=None) assert out.__class__ == Nifti1Image # From 2D to 3D, error, the fixed affine is not invertible img_2d = Nifti1Image(data[:, :, 0], affine) with pytest.raises(AffineError): resample_from_to(img_2d, img) # 3D to 2D, we don't need to invert the fixed matrix out = resample_from_to(img, img_2d) assert_array_equal(out.dataobj, data[:, :, 0]) # Same for tuple as to_img imput out = resample_from_to(img, (img_2d.shape, img_2d.affine)) assert_array_equal(out.dataobj, data[:, :, 0]) # 4D input and output also OK data_4d = np.arange(24 * 5).reshape((2, 3, 4, 5)) img_4d = Nifti1Image(data_4d, affine) out = resample_from_to(img_4d, img_4d) assert_almost_equal(data_4d, out.dataobj) assert_array_equal(img_4d.affine, out.affine) # Errors trying to match 3D to 4D with pytest.raises(ValueError): resample_from_to(img_4d, img) with pytest.raises(ValueError): resample_from_to(img, img_4d)
def test_resample_to_output(): # Test routine to sample iamges to output space # Image aligned to output axes - no-op data = np.arange(24).reshape((2, 3, 4)) img = Nifti1Image(data, np.eye(4)) # Check default resampling img2 = resample_to_output(img) assert_array_equal(img2.shape, (2, 3, 4)) assert_array_equal(img2.affine, np.eye(4)) assert_array_equal(img2.dataobj, data) # Check resampling with different voxel size specifications for vox_sizes in (None, 1, [1, 1, 1]): img2 = resample_to_output(img, vox_sizes) assert_array_equal(img2.shape, (2, 3, 4)) assert_array_equal(img2.affine, np.eye(4)) assert_array_equal(img2.dataobj, data) img2 = resample_to_output(img, vox_sizes) # Check 2D works img_2d = Nifti1Image(data[0], np.eye(4)) for vox_sizes in (None, 1, (1, 1), (1, 1, 1)): img3 = resample_to_output(img_2d, vox_sizes) assert_array_equal(img3.shape, (3, 4, 1)) assert_array_equal(img3.affine, np.eye(4)) assert_array_equal(img3.dataobj, data[0][..., None]) # Even 1D img_1d = Nifti1Image(data[0, 0], np.eye(4)) img3 = resample_to_output(img_1d) assert_array_equal(img3.shape, (4, 1, 1)) assert_array_equal(img3.affine, np.eye(4)) assert_array_equal(img3.dataobj, data[0, 0][..., None, None]) # But 4D does not img_4d = Nifti1Image(data.reshape(2, 3, 2, 2), np.eye(4)) with pytest.raises(ValueError): resample_to_output(img_4d) # Run vox2vox_out tests, checking output shape, coordinate transform for in_shape, in_aff, vox, out_shape, out_aff in get_outspace_params(): # Allow for expansion of image shape from < 3D in_n_dim = len(in_shape) if in_n_dim < 3: in_shape = in_shape + (1,) * (3 - in_n_dim) if not vox is None: vox = vox + (1,) * (3 - in_n_dim) assert len(out_shape) == in_n_dim out_shape = out_shape + (1,) * (3 - in_n_dim) img = Nifti1Image(np.ones(in_shape), in_aff) out_img = resample_to_output(img, vox) assert_all_in(in_shape, in_aff, out_img.shape, out_img.affine) assert out_img.shape == out_shape assert_almost_equal(out_img.affine, out_aff) # Check data is as expected with some transforms # Flip first axis out_img = resample_to_output(Nifti1Image(data, np.diag([-1, 1, 1, 1]))) assert_array_equal(out_img.dataobj, np.flipud(data)) # Subsample voxels out_img = resample_to_output(Nifti1Image(data, np.diag([4, 5, 6, 1]))) exp_out = spnd.affine_transform(data, [1/4, 1/5, 1/6], output_shape = (5, 11, 19)) assert_array_equal(out_img.dataobj, exp_out) # Unsubsample with voxel sizes out_img = resample_to_output(Nifti1Image(data, np.diag([4, 5, 6, 1])), [4, 5, 6]) assert_array_equal(out_img.dataobj, data) # A rotation to test nearest, order, cval rot_3 = from_matvec(euler2mat(np.pi / 4), [0, 0, 0]) rot_3_img = Nifti1Image(data, rot_3) out_img = resample_to_output(rot_3_img) exp_shape = (4, 4, 4) assert out_img.shape == exp_shape exp_aff = np.array([[1, 0, 0, -2 * np.cos(np.pi / 4)], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) assert_almost_equal(out_img.affine, exp_aff) rzs, trans = to_matvec(np.dot(npl.inv(rot_3), exp_aff)) exp_out = spnd.affine_transform(data, rzs, trans, exp_shape) assert_almost_equal(out_img.dataobj, exp_out) # Order assert_almost_equal( resample_to_output(rot_3_img, order=0).dataobj, spnd.affine_transform(data, rzs, trans, exp_shape, order=0)) # Cval assert_almost_equal( resample_to_output(rot_3_img, cval=99).dataobj, spnd.affine_transform(data, rzs, trans, exp_shape, cval=99)) # Mode assert_almost_equal( resample_to_output(rot_3_img, mode='nearest').dataobj, spnd.affine_transform(data, rzs, trans, exp_shape, mode='nearest')) # out_class img_ni1 = Nifti2Image(data, np.eye(4)) img_ni2 = Nifti2Image(data, np.eye(4)) # Default is Nifti1Image assert resample_to_output(img_ni2).__class__ == Nifti1Image # Can be overriden assert resample_to_output(img_ni1, out_class=Nifti2Image).__class__ == Nifti2Image # None specifies out_class from input assert resample_to_output(img_ni2, out_class=None).__class__ == Nifti2Image