def extract_k_space_center_and_locations(data_values, samples_locations, thr=None, img_shape=None, is_fft=False): """ This class extract the k space center for a given threshold and extracts the corresponding sampling locations Parameters ---------- data_values: np.ndarray The value of the samples samples_locations: np.ndarray The samples location in the k-sapec domain (between [-0.5, 0.5[) thr: tuple or float The threshold used to extract the k_space center img_shape: tuple The image shape to estimate the cartesian density is_fft: bool default False Checks if the incoming data is from FFT, in which case, masking can be done more directly Returns ------- The extracted center of the k-space """ if thr is None: if img_shape is None: raise ValueError('target image cartesian image shape must be fill') raise NotImplementedError else: if data_values.ndim > 2: warnings.warn('Data Values seem to have rank ' + str(data_values.ndim) + ' (>2). Using is_fft for now.') is_fft = True if is_fft: img_shape = np.asarray(data_values[0].shape) mask = convert_locations_to_mask(samples_locations, img_shape) indices = np.where(np.reshape(mask, mask.size))[0] data_ordered = np.asarray([ np.reshape(data_values[channel], mask.size)[indices] for channel in range(data_values.shape[0]) ]) else: data_ordered = np.copy(data_values) condition = np.logical_and.reduce( tuple( np.abs(samples_locations[:, i]) <= thr[i] for i in range(len(thr)))) index = np.linspace(0, samples_locations.shape[0] - 1, samples_locations.shape[0], dtype=np.int) index = np.extract(condition, index) center_locations = samples_locations[index, :] data_thresholded = data_ordered[:, index] return data_thresholded, center_locations
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 extract_k_space_center_and_locations(data_values, samples_locations, thr=None, img_shape=None, window_fun=None, is_fft=False, density_comp=None): r""" This class extract the k space center for a given threshold and extracts the corresponding sampling locations Parameters ---------- data_values: np.ndarray The value of the samples samples_locations: np.ndarray The samples location in the k-sapec domain (between [-0.5, 0.5[) thr: tuple or float The threshold used to extract the k_space center img_shape: tuple The image shape to estimate the cartesian density is_fft: bool default False Checks if the incoming data is from FFT, in which case, masking can be done more directly density_comp: np.ndarray default None The density compensation for kspace data in case it exists and we use density compensated adjoint for Smap estimation window_fun: "Hann", "Hanning", "Hamming", or a callable, default None. The window function to apply to the selected data. It is computed with the center locations selected. Only works with circular mask. If window_fun is a callable, it takes as input the array (n_samples x n_dims) of sample positions and returns an array of n_samples weights to be applied to the selected k-space values, before the smaps estimation. Returns ------- The extracted center of the k-space, i.e. both the kspace locations and kspace values. If the density compensators are passed, the corresponding compensators for the center of k-space data will also be returned. The return stypes for density compensation and kspace data is same as input Notes ----- The Hann (or Hanning) and Hamming windows of width :math:`2\theta` are defined as: .. math:: w(x,y) = a_0 - (1-a_0) * \cos(\pi * \sqrt{x^2+y^2}/\theta), \sqrt{x^2+y^2} \le \theta In the case of Hann window :math:`a_0=0.5`. For Hamming window we consider the optimal value in the equiripple sense: :math:`a_0=0.53836`. .. Wikipedia:: https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows """ if thr is None: if img_shape is None: raise ValueError('target image cartesian image shape must be fill') raise NotImplementedError if data_values.ndim > 2: warnings.warn('Data Values seem to have rank ' + str(data_values.ndim) + ' (>2). Using is_fft for now.') is_fft = True if is_fft: img_shape = np.asarray(data_values[0].shape) mask = convert_locations_to_mask(samples_locations, img_shape) indices = np.where(np.reshape(mask, mask.size))[0] data_ordered = np.asarray([ np.reshape(data_values[channel], mask.size)[indices] for channel in range(data_values.shape[0]) ]) else: data_ordered = np.copy(data_values) if window_fun is None: if isinstance(thr, float): thr = (thr, ) * samples_locations.shape[1] condition = np.logical_and.reduce( tuple( np.abs(samples_locations[:, i]) <= thr[i] for i in range(len(thr)))) elif isinstance(thr, float): condition = np.sum(np.square(samples_locations), axis=1) <= thr**2 else: raise ValueError("threshold type is not supported with select window") index = np.linspace(0, samples_locations.shape[0] - 1, samples_locations.shape[0], dtype=np.int) index = np.extract(condition, index) center_locations = samples_locations[index, :] data_thresholded = data_ordered[:, index] if window_fun is not None: if callable(window_fun): window = window_fun(center_locations) else: if window_fun == "Hann" or window_fun == "Hanning": a_0 = 0.5 elif window_fun == "Hamming": a_0 = 0.53836 else: raise ValueError("Unsupported window function.") radius = np.linalg.norm(center_locations, axis=1) window = a_0 + (1 - a_0) * np.cos(np.pi * radius / thr) data_thresholded = window * data_thresholded if density_comp is not None: density_comp = density_comp[index] return data_thresholded, center_locations, density_comp else: return data_thresholded, center_locations
# 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 # undersample the k-space using a radial acquisition mask # We then reconstruct the zero order solution as a baseline # Get the locations of the kspace samples and the associated observations fourier_op = Stacked3DNFFT(kspace_loc=kspace_loc,
from modopt.opt.linear import Identity from modopt.opt.proximity import SparseThreshold import numpy as np # Loading input data image = get_sample_data('3d-pmri') image = pysap.Image(data=np.sqrt(np.sum(np.abs(image.data)**2, axis=0))) # Obtain MRI non-cartesian mask radial_mask = get_sample_data("mri-radial-samples") z_locations = np.repeat(np.linspace(-0.5, 0.5, image.shape[2], endpoint=False), radial_mask.shape[0]) z_locations = z_locations[:, np.newaxis] kspace_loc = np.hstack( [np.tile(radial_mask.data, (image.shape[2], 1)), z_locations]) mask = pysap.Image(data=convert_locations_to_mask(kspace_loc, image.shape)) # View Input # image.show() # mask.show() ############################################################################# # Generate the kspace # ------------------- # # From the 2D brain slice and the acquisition mask, we retrospectively # undersample the k-space using a radial acquisition mask # We then reconstruct the zero order solution as a baseline # Get the locations of the kspace samples and the associated observations fourier_op = Stacked3DNFFT(kspace_loc=kspace_loc,