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
Esempio n. 2
0
 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")
Esempio n. 3
0
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,
Esempio n. 5
0
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,