def test_sensitivity_extraction_2D(self): """ This test ensures that the output of the non cartesian kspace extraction is same a that of mimicked cartesian extraction in 2D """ _mask = np.ones((self.N, self.N)) _samples = convert_mask_to_locations(_mask) fourier_op = NonCartesianFFT(samples=_samples, shape=(self.N, self.N)) Img = (np.random.randn(self.num_channel, self.N, self.N) + 1j * np.random.randn(self.num_channel, self.N, self.N)) F_img = np.asarray( [fourier_op.op(Img[i]) for i in np.arange(self.num_channel)]) Smaps_gridding, SOS_Smaps = get_Smaps(k_space=F_img, img_shape=(self.N, self.N), samples=_samples, thresh=(0.4, 0.4), mode='gridding', min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), n_cpu=1) Smaps_NFFT, SOS_Smaps = get_Smaps(k_space=F_img, img_shape=(self.N, self.N), thresh=(0.4, 0.4), samples=_samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), mode='NFFT') np.testing.assert_allclose(Smaps_gridding, Smaps_NFFT)
def test_NFFT_2D(self): """Test the adjoint operator for the 2D non-Cartesian Fourier transform, with density compensator set to 1, to vet the code path, the test is unchanged otherwise """ for num_channels in self.num_channels: print("Testing with num_channels=" + str(num_channels)) for i in range(self.max_iter): _mask = np.random.randint(2, size=(self.N, self.N)) _samples = convert_mask_to_locations(_mask) print("Process NFFT in 2D test '{0}'...", i) fourier_op = NonCartesianFFT(samples=_samples, shape=(self.N, self.N), n_coils=num_channels, implementation='cpu', density_comp=np.ones( (num_channels, _samples.shape[0]))) Img = np.random.randn(num_channels, self.N, self.N) + \ 1j * np.random.randn(num_channels, self.N, self.N) f = np.random.randn(num_channels, _samples.shape[0]) + \ 1j * np.random.randn(num_channels, _samples.shape[0]) f_p = fourier_op.op(Img) I_p = fourier_op.adj_op(f) x_d = np.vdot(Img, I_p) x_ad = np.vdot(f_p, f) np.testing.assert_allclose(x_d, x_ad, rtol=1e-10) print(" NFFT in 2D adjoint test passes")
def test_NUFFT_3D(self): """Test the adjoint operator for the 3D non-Cartesian Fourier transform on GPU """ for num_channels in self.num_channels: for platform in self.platforms: _mask = np.random.randint(2, size=(self.N, self.N, self.N)) _samples = convert_mask_to_locations(_mask) fourier_op_dir = NonCartesianFFT(samples=_samples, shape=(self.N, self.N, self.N), implementation=platform, n_coils=num_channels) Img = (np.random.randn(num_channels, self.N, self.N, self.N) + 1j * np.random.randn(num_channels, self.N, self.N, self.N)) f = (np.random.randn(num_channels, _samples.shape[0]) + 1j * np.random.randn(num_channels, _samples.shape[0])) f_p = fourier_op_dir.op(Img) I_p = fourier_op_dir.adj_op(f) x_d = np.vdot(Img, I_p) x_ad = np.vdot(f_p, f) np.testing.assert_allclose(x_d, x_ad, rtol=1e-5) print("NFFT in 3D adjoint test passes on GPU with" "num_channels = " + str(num_channels) + " on " "platform " + platform)
def test_similarity_stack_3D_nfft(self): """Test the similarity of stacked implementation of Fourier transform to that of NFFT """ for channel in self.num_channels: print("Testing with num_channels=" + str(channel)) for N in [16, 32]: # Nz is the number of slices, this would check both N=Nz # and N!=Nz Nz = 16 _mask = np.random.randint(2, size=(N, N)) # Generate random mask along z sampling_z = np.random.randint(2, size=Nz) _mask3D = np.zeros((N, N, Nz)) for idx, acq_z in enumerate(sampling_z): _mask3D[:, :, idx] = _mask * acq_z _samples = convert_mask_to_locations(_mask3D) print("Process Stack-3D similarity with NFFT for N=" + str(N)) fourier_op_stack = Stacked3DNFFT(kspace_loc=_samples, shape=(N, N, Nz), implementation='cpu', n_coils=channel) fourier_op_nfft = NonCartesianFFT(samples=_samples, shape=(N, N, Nz), implementation='cpu', n_coils=channel) Img = np.random.random((channel, N, N, Nz)) + \ 1j * np.random.random((channel, N, N, Nz)) f = np.random.random((channel, _samples.shape[0])) + \ 1j * np.random.random((channel, _samples.shape[0])) start_time = time.time() stack_f_p = fourier_op_stack.op(Img) stack_I_p = fourier_op_stack.adj_op(f) stack_runtime = time.time() - start_time start_time = time.time() nfft_f_p = fourier_op_nfft.op(Img) nfft_I_p = fourier_op_nfft.adj_op(f) np.testing.assert_allclose(stack_f_p, nfft_f_p, rtol=1e-9) np.testing.assert_allclose(stack_I_p, nfft_I_p, rtol=1e-9) nfft_runtime = time.time() - start_time print("For N=" + str(N) + " Speedup = " + str(nfft_runtime / stack_runtime)) print("Stacked FFT in 3D adjoint test passes")
def generate_test_NFFT(self, shape, field_scale): """ Factorized code to test 2D and 3D wrapped NFFT with different homogeneous B0 field shifts at constant time. """ for L, i, n_coils in product(self.L, range(self.max_iter), self.n_coils): mask = np.random.randint(2, size=shape) samples = convert_mask_to_locations(mask) samples = samples[:samples.shape[0] - (samples.shape[0] % shape[0])] field_shift = field_scale * np.random.randint(-150, 150) field_map = field_shift * np.ones(shape) # Prepare reference and wrapper operators fourier_op = NonCartesianFFT( samples=samples, shape=shape, n_coils=n_coils, implementation='cpu', density_comp=np.ones((n_coils, samples.shape[0])) ) wrapper_op = ORCFFTWrapper(fourier_op, field_map=field_map, time_vec=np.ones(shape[0]), mask=np.ones(shape), num_interpolators=L, n_bins=self.n_bins) # Forward operator img = np.squeeze(np.random.randn(n_coils, *shape) \ + 1j * np.random.randn(n_coils, *shape)) ksp_fft = fourier_op.op(img) ksp_wra = wrapper_op.op(img * np.exp(-2j * np.pi * field_shift)) np.testing.assert_allclose(ksp_fft, ksp_wra, rtol=self.rtol) # Adjoint operator ksp = np.squeeze(np.random.randn(n_coils, samples.shape[0]) \ + 1j * np.random.randn(n_coils, samples.shape[0])) img_fft = fourier_op.adj_op(ksp) img_wra = wrapper_op.adj_op(ksp * np.exp(2j * np.pi * field_shift)) np.testing.assert_allclose(img_fft, img_wra, rtol=self.rtol)
def test_NFFT_3D(self): """Test the adjoint operator for the 3D non-Cartesian Fourier transform """ for num_channels in self.num_channels: print("Testing with num_channels=" + str(num_channels)) for i in range(self.max_iter): _mask = np.random.randint(2, size=(self.N, self.N, self.N)) _samples = convert_mask_to_locations(_mask) print("Process NFFT test in 3D '{0}'...", i) fourier_op = NonCartesianFFT(samples=_samples, shape=(self.N, self.N, self.N), n_coils=num_channels, implementation='cpu') Img = np.random.randn(num_channels, self.N, self.N, self.N) + \ 1j * np.random.randn(num_channels, self.N, self.N, self.N) f = np.random.randn(num_channels, _samples.shape[0]) + \ 1j * np.random.randn(num_channels, _samples.shape[0]) f_p = fourier_op.op(Img) I_p = fourier_op.adj_op(f) x_d = np.vdot(Img, I_p) x_ad = np.vdot(f_p, f) np.testing.assert_allclose(x_d, x_ad, rtol=1e-10) print(" NFFT in 3D adjoint test passes")
def test_sensitivity_extraction_2D(self): """ This test ensures that the output of the non cartesian kspace extraction is same a that of mimicked cartesian extraction in 2D """ mask = np.ones((self.N, self.N)) samples = convert_mask_to_locations(mask) fourier_op = NonCartesianFFT(samples=samples, shape=(self.N, self.N)) Img = (np.random.randn(self.num_channel, self.N, self.N) + 1j * np.random.randn(self.num_channel, self.N, self.N)) F_img = np.asarray( [fourier_op.op(Img[i]) for i in np.arange(self.num_channel)]) Smaps_gridding, SOS_Smaps = get_Smaps(k_space=F_img, img_shape=(self.N, self.N), samples=samples, thresh=(0.4, 0.4), mode='gridding', min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), n_cpu=1) Smaps_NFFT_dc, SOS_Smaps_dc = get_Smaps(k_space=F_img, img_shape=(self.N, self.N), thresh=(0.4, 0.4), samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), mode='NFFT', density_comp=np.ones( samples.shape[0])) Smaps_NFFT, SOS_Smaps = get_Smaps( k_space=F_img, img_shape=(self.N, self.N), thresh=(0.4, 0.4), samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), mode='NFFT', ) Smaps_hann_NFFT, SOS_Smaps = get_Smaps( k_space=F_img, img_shape=(self.N, self.N), thresh=0.4, samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), window_fun="Hann", mode='NFFT', ) Smaps_hann_gridding, SOS_Smaps = get_Smaps( k_space=F_img, img_shape=(self.N, self.N), thresh=0.4, samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), window_fun="Hann", mode='gridding', ) Smaps_hamming_NFFT, SOS_Smaps = get_Smaps( k_space=F_img, img_shape=(self.N, self.N), thresh=0.4, samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), window_fun="Hamming", mode='NFFT', ) Smaps_hamming_gridding, SOS_Smaps = get_Smaps( k_space=F_img, img_shape=(self.N, self.N), thresh=0.4, samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), window_fun="Hamming", mode='gridding', ) Smaps_call_gridding, SOS_Smaps = get_Smaps( k_space=F_img, img_shape=(self.N, self.N), thresh=0.4, samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), window_fun=lambda x: 1, mode='gridding', ) Smaps_call_NFFT, SOS_Smaps = get_Smaps( k_space=F_img, img_shape=(self.N, self.N), thresh=0.4, samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), window_fun=lambda x: 1, mode='NFFT', ) np.testing.assert_allclose(Smaps_gridding, Smaps_NFFT_dc) np.testing.assert_allclose(Smaps_gridding, Smaps_NFFT) np.testing.assert_allclose(Smaps_hann_gridding, Smaps_hann_NFFT) np.testing.assert_allclose(Smaps_hamming_gridding, Smaps_hamming_NFFT) np.testing.assert_allclose(Smaps_call_gridding, Smaps_call_NFFT) # Test that we raise assert for bad mode np.testing.assert_raises(ValueError, get_Smaps, k_space=F_img, img_shape=(self.N, self.N), thresh=(0.4, 0.4), samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), mode='test') # Test that we raise assert for bad window np.testing.assert_raises( ValueError, get_Smaps, k_space=F_img, img_shape=(self.N, self.N), thresh=(0.4, 0.4), samples=samples, min_samples=(-0.5, -0.5), max_samples=(0.5, 0.5), window_fun='test', mode='gridding', )
# Get the locations of the kspace samples and the associated observations fourier_op = NonCartesianFFT( samples=kspace_loc, shape=image.shape, implementation='gpuNUFFT', ) fourier_op_density_comp = NonCartesianFFT( samples=kspace_loc, shape=image.shape, implementation='gpuNUFFT', density_comp=density_comp ) # Get the kspace data retrospectively. Note that this can be done with # `fourier_op_density_comp` as the forward operator is the same kspace_obs = fourier_op.op(image.data) # Simple adjoint image_rec0 = pysap.Image(data=np.abs(fourier_op.adj_op(kspace_obs))) # image_rec0.show() base_ssim = ssim(image_rec0, image) print('The SSIM from Adjoint is : ' + str(base_ssim)) # Density Compensation adjoint: # This preconditions k-space giving a result closer to inverse image_rec1 = pysap.Image(data=np.abs( fourier_op_density_comp.adj_op(kspace_obs)) ) # image_rec1.show() new_ssim = ssim(image_rec1, image) print('The SSIM from Density '
def test_gridsearch_single_channel(self): """Test Gridsearch script in mri.scripts for single channel reconstruction this is a test of sanity and not if the reconstruction is right. """ image = get_sample_data('2d-mri') mask = np.ones(image.shape) kspace_loc = convert_mask_to_locations(mask) fourier_op = NonCartesianFFT(samples=kspace_loc, shape=image.shape) kspace_data = fourier_op.op(image.data) # Define the keyword dictionaries based on convention metrics = { 'ssim': { 'metric': ssim, 'mapping': { 'x_new': 'test', 'y_new': None }, 'cst_kwargs': { 'ref': image, 'mask': None }, 'early_stopping': True, }, } linear_params = { 'init_class': WaveletN, 'kwargs': { 'wavelet_name': 'sym8', 'nb_scale': 4, } } regularizer_params = { 'init_class': SparseThreshold, 'kwargs': { 'linear': Identity(), 'weights': [0, 1e-5], } } optimizer_params = { # Just following convention 'kwargs': { 'optimization_alg': 'fista', 'num_iterations': 10, 'metrics': metrics, } } # Call the launch grid function and obtain results raw_results, test_cases, key_names, best_idx = launch_grid( kspace_data=kspace_data, fourier_op=fourier_op, linear_params=linear_params, regularizer_params=regularizer_params, optimizer_params=optimizer_params, reconstructor_kwargs={'gradient_formulation': 'synthesis'}, reconstructor_class=SingleChannelReconstructor, compare_metric_details={'metric': 'ssim'}, n_jobs=self.n_jobs, verbose=1, ) # In this test we dont undersample the kspace so the # reconstruction is indeed with mu=0, ie best_idx=0 np.testing.assert_equal(best_idx, 0) np.testing.assert_allclose( raw_results[best_idx][0], image, atol=1e-7, )
import numpy as np from mri.operators import NonCartesianFFT traj = np.load('/volatile/temp_traj.npy') fourier = NonCartesianFFT(traj, (384, 384, 208), 'gpuNUFFT', n_coils=20, smaps=np.ones((20, 384, 384, 208)), osf=2) for i in range(10): print(i) K = fourier.op(np.zeros((384, 384, 208))) I = fourier.adj_op(K)
# mask.show() ############################################################################# # Generate the kspace # ------------------- # # From the 2D brain slice and the acquisition mask, we retrospectively # undersample the k-space using a non cartesian acquisition mask # We then grid the kspace to get the gridded solution as a baseline # Get the kspace observation values for the kspace locations fourier_op = NonCartesianFFT(samples=kspace_loc, shape=image.shape, n_coils=cartesian_ref_image.shape[0], implementation='gpuNUFFT') kspace_obs = fourier_op.op(cartesian_ref_image) # Gridded solution grid_space = np.linspace(-0.5, 0.5, num=image.shape[0]) grid2D = np.meshgrid(grid_space, grid_space) grid_soln = np.asarray([ gridded_inverse_fourier_transform_nd(kspace_loc, kspace_obs_ch, tuple(grid2D), 'linear') for kspace_obs_ch in kspace_obs ]) image_rec0 = pysap.Image(data=np.sqrt(np.sum(np.abs(grid_soln)**2, axis=0))) # image_rec0.show() base_ssim = ssim(image_rec0, image) print('The Base SSIM is : ' + str(base_ssim)) # Obtain SMaps