def test_adjoint_stack_3D(self): """Test the adjoint operator for the 3D non-Cartesian Fourier transform """ for channel in self.num_channels: print("Testing with num_channels=" + str(channel)) for i in range(self.max_iter): mask = np.random.randint(2, size=(self.N, self.N)) sampling_z = np.random.randint(2, size=self.N) sampling_z[self.N // 2 - 10:self.N // 2 + 10] = 1 Nz = sampling_z.sum() mask = convert_mask_to_locations(mask) z_locations = np.repeat( convert_mask_to_locations(sampling_z), mask.shape[0], ) z_locations = z_locations[:, np.newaxis] kspace_loc = np.hstack([np.tile(mask, (Nz, 1)), z_locations]) print("Process Stacked3D-FFT test in 3D '{0}'...", i) fourier_op = Stacked3DNFFT( kspace_loc=kspace_loc, shape=(self.N, self.N, self.N), implementation='cpu', n_coils=channel, ) Img = np.random.random((channel, self.N, self.N, self.N)) + \ 1j * np.random.random((channel, self.N, self.N, self.N)) f = np.random.random((channel, kspace_loc.shape[0])) + \ 1j * np.random.random((channel, kspace_loc.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("Stacked FFT in 3D adjoint test passes")
def test_self_calibrating_reconstruction(self): """ Test all the registered transformations. """ self.num_channels = 2 print("Process test for SelfCalibratingReconstructor ::") for i in range(len(self.test_cases)): print("Test Case " + str(i) + " " + str(self.test_cases[i])) image, nb_scale, optimizer, recon_type, name = self.test_cases[i] image_multichannel = np.repeat(image.data[np.newaxis], self.num_channels, axis=0) if optimizer == 'condatvu': formulation = "analysis" else: formulation = "synthesis" if recon_type == 'cartesian': fourier = FFT(samples=convert_mask_to_locations(self.mask), shape=image.shape, n_coils=self.num_channels) else: fourier = NonCartesianFFT(samples=convert_mask_to_locations( self.mask), shape=image.shape, n_coils=self.num_channels) kspace_data = fourier.op(image_multichannel) linear_op, regularizer_op = \ self.get_linear_n_regularization_operator( wavelet_name=name, dimension=len(fourier.shape), nb_scale=2, n_coils=self.num_channels, gradient_formulation=formulation, ) # For self calibrating reconstruction the n_coils # for wavelet operation is 1 linear_op.n_coils = 1 reconstructor = SelfCalibrationReconstructor( fourier_op=fourier, linear_op=linear_op, regularizer_op=regularizer_op, gradient_formulation=formulation, verbose=0, ) x_final, costs, _ = reconstructor.reconstruct( kspace_data=kspace_data, optimization_alg=optimizer, num_iterations=self.num_iter, ) fourier_0 = FFT( samples=convert_mask_to_locations(self.mask), shape=image.shape, n_coils=self.num_channels, ) recon = fourier_0.adj_op(fourier_0.op(image_multichannel)) np.testing.assert_allclose(np.abs(x_final), np.sqrt(np.sum(np.abs(recon)**2, axis=0)), rtol=1e-3)
def test_sparse_calibrationless_reconstruction(self): """ Test all the registered transformations. """ self.num_channels = 2 print("Process test for SparseCalibrationlessReconstructor ::") for i in range(len(self.test_cases)): print("Test Case " + str(i) + " " + str(self.test_cases[i])) image, nb_scale, optimizer, recon_type, name = self.test_cases[i] image_multichannel = np.repeat(image.data[np.newaxis], self.num_channels, axis=0) if optimizer == 'condatvu': formulation = "analysis" else: formulation = "synthesis" if recon_type == 'cartesian': fourier = FFT(samples=convert_mask_to_locations(self.mask), shape=image.shape, n_coils=self.num_channels) else: fourier = NonCartesianFFT(samples=convert_mask_to_locations( self.mask), shape=image.shape, n_coils=self.num_channels) kspace_data = fourier.op(image_multichannel) linear_op, regularizer_op = \ self.get_linear_n_regularization_operator( wavelet_name=name, dimension=len(fourier.shape), nb_scale=2, n_coils=2, n_jobs=2, gradient_formulation=formulation, ) reconstructor = CalibrationlessReconstructor( fourier_op=fourier, linear_op=linear_op, regularizer_op=regularizer_op, gradient_formulation=formulation, verbose=1, ) x_final, costs, _ = reconstructor.reconstruct( kspace_data=kspace_data, optimization_alg=optimizer, num_iterations=self.num_iter, ) fourier_0 = FFT( samples=convert_mask_to_locations(self.mask), shape=image.shape, n_coils=self.num_channels, ) data_0 = fourier_0.op(image_multichannel) # mu is 0 for above single channel reconstruction and # hence we expect the result to be the inverse fourier transform np.testing.assert_allclose(x_final, fourier_0.adj_op(data_0))
def test_extract_k_space_center_3D(self): """ This test ensures that the output of the non cartesian kspace extraction is same a that of mimicked cartesian extraction in 3D """ _mask = np.ones((self.N, self.N, self.Nz)) _samples = convert_mask_to_locations(_mask) Img = (np.random.randn(self.num_channel, self.N, self.N, self.Nz) + 1j * np.random.randn(self.num_channel, self.N, self.N, self.Nz)) Nby2_percent = self.N * self.percent / 2 Nzby2_percent = self.Nz * self.percent / 2 low = int(self.N / 2 - Nby2_percent) high = int(self.N / 2 + Nby2_percent + 1) lowz = int(self.Nz / 2 - Nzby2_percent) highz = int(self.Nz / 2 + Nzby2_percent + 1) center_Img = Img[:, low:high, low:high, lowz:highz] thresh = self.percent * 0.5 data_thresholded, samples_thresholded = \ extract_k_space_center_and_locations( data_values=np.reshape(Img, (self.num_channel, self.N * self.N * self.Nz)), samples_locations=_samples, thr=(thresh, thresh, thresh), img_shape=(self.N, self.N, self.Nz)) np.testing.assert_allclose(center_Img.reshape(data_thresholded.shape), data_thresholded)
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_FFT(self): """Test the adjoint operator for the 2D non-Cartesian Fourier transform """ for i, num_coil in product(range(self.max_iter), self.num_channels): _mask = np.random.randint(2, size=(self.N, self.N)) _samples = convert_mask_to_locations(_mask) print("Process FFT test '{0}'...", i) fourier_op_dir = FFT(samples=_samples, shape=(self.N, self.N), n_coils=num_coil) fourier_op_adj = FFT(samples=_samples, shape=(self.N, self.N), n_coils=num_coil) Img = np.squeeze( np.random.randn(num_coil, self.N, self.N) + 1j * np.random.randn(num_coil, self.N, self.N)) f = np.squeeze( np.random.randn(num_coil, self.N, self.N) + 1j * np.random.randn(num_coil, self.N, self.N)) f_p = fourier_op_dir.op(Img) I_p = fourier_op_adj.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(" FFT adjoint test passes")
def test_extract_k_space_center_2D_fft(self): """ Ensure that the extracted k-space center is right for cartesian case""" mask = np.random.randint(0, 2, (self.N, self.N)) samples = convert_mask_to_locations(mask) Img = (np.random.randn(self.num_channel, self.N, self.N) + 1j * np.random.randn(self.num_channel, self.N, self.N)) Nby2_percent = self.N * self.percent / 2 low = int(self.N / 2 - Nby2_percent) high = int(self.N / 2 + Nby2_percent + 1) center_Img = Img[:, low:high, low:high] cutoff_mask = mask[low:high, low:high] locations = np.where(cutoff_mask.reshape(cutoff_mask.size)) center_Img = center_Img.reshape( (center_Img.shape[0], cutoff_mask.size))[:, locations[0]] thresh = self.percent * 0.5 data_thresholded, samples_thresholded = \ extract_k_space_center_and_locations( data_values=Img, samples_locations=samples, thr=(thresh, thresh), img_shape=(self.N, self.N)) np.testing.assert_allclose( center_Img, data_thresholded)
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_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_stack_3D_error(self): np.testing.assert_raises(ValueError, get_stacks_fourier, np.random.randn(12, 3), (self.N, self.N, self.N)) # Generate random mask along z sampling_z = np.random.randint(2, size=self.N) _mask3D = np.zeros((self.N, self.N, self.N)) for idx, acq_z in enumerate(sampling_z): _mask3D[:, :, idx] = np.random.randint(2, size=(self.N, self.N)) * acq_z sampling = convert_mask_to_locations(_mask3D) np.testing.assert_raises(ValueError, get_stacks_fourier, sampling, (self.N, self.N, self.N))
def test_sampling_converters(self): """Test the adjoint operator for the 2D non-Cartesian Fourier transform """ for i in range(self.max_iter): print("Process test convert mask to samples test '{0}'...", i) Nx = np.random.randint(8, 512) Ny = np.random.randint(8, 512) mask = np.random.randint(2, size=(Nx, Ny)) samples = convert_mask_to_locations(mask) recovered_mask = convert_locations_to_mask(samples, (Nx, Ny)) self.assertEqual(mask.all(), recovered_mask.all()) mismatch = 0. + (np.mean(np.allclose(mask, recovered_mask))) print(" mismatch = ", mismatch) print(" Test convert mask to samples and it's adjoint passes for", " the 2D cases")
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 test_check_asserts(self): # Tests to check for asserts image, nb_scale, optimizer, recon_type, name = self.test_cases[0] fourier = NonCartesianFFT( samples=convert_mask_to_locations(self.mask), shape=image.shape, ) kspace_data = fourier.op(image.data) linear_op, regularizer_op = \ self.get_linear_n_regularization_operator( wavelet_name=name, dimension=len(fourier.shape), nb_scale=2, gradient_formulation="synthesis", ) reconstructor = CalibrationlessReconstructor( fourier_op=fourier, linear_op=linear_op, regularizer_op=regularizer_op, gradient_formulation="synthesis", verbose=1, ) np.testing.assert_raises( ValueError, reconstructor.reconstruct, kspace_data=kspace_data, optimization_alg="test_fail", num_iterations=self.num_iter, ) fourier.n_coils = 10 reconstructor = SelfCalibrationReconstructor( fourier_op=fourier, linear_op=linear_op, regularizer_op=regularizer_op, gradient_formulation="synthesis", verbose=1, ) np.testing.assert_raises( ValueError, reconstructor.reconstruct, kspace_data=kspace_data, optimization_alg=optimizer, num_iterations=self.num_iter, )
def test_extract_k_space_center_2D(self): """ Ensure that the extracted k-space center is right""" _mask = np.ones((self.N, self.N)) _samples = convert_mask_to_locations(_mask) Img = (np.random.randn(self.num_channel, self.N, self.N) + 1j * np.random.randn(self.num_channel, self.N, self.N)) Nby2_percent = self.N * self.percent / 2 low = int(self.N / 2 - Nby2_percent) high = int(self.N / 2 + Nby2_percent + 1) center_Img = Img[:, low:high, low:high] thresh = self.percent * 0.5 data_thresholded, samples_thresholded = \ extract_k_space_center_and_locations( data_values=np.reshape(Img, (self.num_channel, self.N * self.N)), samples_locations=_samples, thr=(thresh, thresh), img_shape=(self.N, self.N)) np.testing.assert_allclose(center_Img.reshape(data_thresholded.shape), data_thresholded)
def generate_test_stacked_NFFT(self, shape, field_scale): """ Factorized code to test 3D-stacked 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[:-1]) mask = np.tile(mask[..., None], (1, 1, shape[-1])) 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 = Stacked3DNFFT( kspace_loc=samples, shape=shape, implementation='cpu', n_coils=n_coils, ) 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_adjoint_stack_3D(self): """Test the adjoint operator for the 3D non-Cartesian Fourier transform """ for channel in self.num_channels: print("Testing with num_channels=" + str(channel)) for i in range(self.max_iter): _mask = np.random.randint(2, size=(self.N, self.N)) _mask3D = np.asarray([_mask for i in np.arange(self.N)]) _samples = convert_mask_to_locations(_mask3D.swapaxes(0, 2)) print("Process Stacked3D-FFT test in 3D '{0}'...", i) fourier_op = Stacked3DNFFT(kspace_loc=_samples, shape=(self.N, self.N, self.N), implementation='cpu', n_coils=channel) Img = np.random.random((channel, self.N, self.N, self.N)) + \ 1j * np.random.random((channel, self.N, self.N, self.N)) f = np.random.random((channel, _samples.shape[0])) + \ 1j * np.random.random((channel, _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("Stacked FFT 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', )
def test_stack3d_self_calibration_recon(self): # This test carries out a self calibration recon using Stack3D self.num_channels = 2 self.z_size = 10 for i in range(len(self.test_cases)): image, nb_scale, optimizer, recon_type, name = self.test_cases[i] if recon_type == 'cartesian' or name == 24: continue # Make a dummy 3D image from 2D image = np.moveaxis( np.repeat(image.data[np.newaxis], self.z_size, axis=0), 0, 2) # Make dummy multichannel image image = np.repeat(image[np.newaxis], self.num_channels, axis=0) sampling_z = np.random.randint(2, size=image.shape[3]) sampling_z[self.z_size // 2 - 3:self.z_size // 2 + 3] = 1 Nz = sampling_z.sum() mask = convert_mask_to_locations(self.mask) z_locations = np.repeat(convert_mask_to_locations(sampling_z), mask.shape[0]) z_locations = z_locations[:, np.newaxis] kspace_loc = np.hstack([np.tile(mask, (Nz, 1)), z_locations]) fourier = Stacked3DNFFT(kspace_loc=kspace_loc, shape=image.shape[1:], implementation='cpu', n_coils=self.num_channels) kspace_obs = fourier.op(image) if optimizer == 'condatvu': formulation = "analysis" else: formulation = "synthesis" linear_op, regularizer_op = \ self.get_linear_n_regularization_operator( wavelet_name=name, dimension=len(fourier.shape), nb_scale=2, n_coils=2, n_jobs=2, gradient_formulation=formulation, ) # For self calibrating reconstruction the n_coils # for wavelet operation is 1 linear_op.n_coils = 1 reconstructor = SelfCalibrationReconstructor( fourier_op=fourier, linear_op=linear_op, regularizer_op=regularizer_op, gradient_formulation=formulation, num_check_lips=0, smaps_extraction_mode='Stack', verbose=1, ) x_final, _, _, = reconstructor.reconstruct( kspace_data=kspace_obs, optimization_alg=optimizer, num_iterations=5, ) fourier_0 = FFT( samples=kspace_loc, shape=image.shape[1:], n_coils=self.num_channels, ) recon = fourier_0.adj_op(fourier_0.op(image)) np.testing.assert_allclose( np.abs(x_final), np.sqrt(np.sum(np.abs(recon)**2, axis=0)), 0.1)
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, )
image = get_sample_data('3d-pmri') image = pysap.Image(data=np.sqrt(np.sum(np.abs(image.data)**2, axis=0))) # Reducing the size of the volume for faster computation image.data = image.data[:, :, 48:-48] # Obtain MRI non-cartesian sampling plane mask_radial = get_sample_data("mri-radial-samples") # Tiling the plane on the z-direction # sampling_z = np.ones(image.shape[2]) # no sampling sampling_z = np.random.randint(2, size=image.shape[2]) # random sampling sampling_z[22:42] = 1 Nz = sampling_z.sum() # Number of acquired plane z_locations = np.repeat(convert_mask_to_locations(sampling_z), mask_radial.shape[0]) z_locations = z_locations[:, np.newaxis] kspace_loc = np.hstack([np.tile(mask_radial.data, (Nz, 1)), z_locations]) mask = pysap.Image(data=np.moveaxis( convert_locations_to_mask(kspace_loc, image.shape), -1, 0)) # View Input # image.show() # mask.show() ############################################################################# # Generate the kspace # ------------------- # # From the 2D brain slice and the acquisition mask, we retrospectively
axis=-1) # View Input # image.show() # mask.show() ############################################################################# # Generate the kspace # ------------------- # # From the 3D Orange volume and the acquisition mask, we retrospectively # undersample the k-space using a cartesian acquisition mask # We then reconstruct the zero order solution as a baseline # Get the locations of the kspace samples kspace_loc = convert_mask_to_locations(mask.data) # Generate the subsampled kspace fourier_op = FFT(samples=kspace_loc, shape=image.shape) kspace_data = fourier_op.op(image) # Zero order solution image_rec0 = pysap.Image(data=fourier_op.adj_op(kspace_data), metadata=image.metadata) # image_rec0.show() # Calculate SSIM base_ssim = ssim(image_rec0, image) print(base_ssim) ############################################################################# # FISTA optimization
def test_online_accumulating_calibrationless(self): self.num_channels = 2 for i in range(len(self.test_cases)): image, nb_scale, optimizer, recon_type, name = self.test_cases[i] if recon_type != 'cartesian': continue if optimizer == 'condatvu': formulation = "analysis" else: formulation = "synthesis" image_multichannel = np.repeat(image.data[np.newaxis], self.num_channels, axis=0) fourier = FFT(samples=convert_mask_to_locations(self.mask), shape=image.shape, n_coils=self.num_channels) kspace_data = fourier.op(image_multichannel) linear_op, _ = \ self.get_linear_n_regularization_operator( wavelet_name=name, dimension=len(fourier.shape), nb_scale=2, n_coils=2, n_jobs=2, image_shape=image.shape, ) regularizer_op_gl = GroupLASSO(weights=0) linear_op.op(image_multichannel) regularizer_op_owl = OWL( alpha=0, beta=0, mode='band_based', n_coils=self.num_channels, bands_shape=linear_op.coeffs_shape, ) for regularizer_op in [regularizer_op_gl, regularizer_op_owl]: print(image, nb_scale, optimizer, recon_type, name, regularizer_op) kspace_gen = KspaceGeneratorBase(full_kspace=kspace_data, mask=fourier.mask, max_iter=10) reconstructor = CalibrationlessReconstructor( fourier_op=fourier, linear_op=linear_op, regularizer_op=regularizer_op, gradient_formulation=formulation, num_check_lips=0, verbose=1, ) x_final, costs, _ = reconstructor.reconstruct( kspace_data=kspace_gen, optimization_alg=optimizer, ) fourier_0 = FFT( samples=convert_mask_to_locations(self.mask), shape=image.shape, n_coils=self.num_channels, ) data_0 = fourier_0.op(image_multichannel) # mu is 0 for above single channel reconstruction and # hence we expect the result to be the inverse fourier # transform np.testing.assert_allclose(x_final, fourier_0.adj_op(data_0), 0.01)