Beispiel #1
0
    def _get_data(self):
        if self.coord is None:
            self.img_shape = list(self.y.shape[1:])
            ndim = len(self.img_shape)

            self.y = sp.resize(
                self.y, [self.num_coils] + ndim * [self.ksp_calib_width])

            if self.weights is not None:
                self.weights = sp.resize(
                    self.weights, ndim * [self.ksp_calib_width])

        else:
            self.img_shape = sp.estimate_shape(self.coord)
            calib_idx = np.amax(np.abs(self.coord), axis=-
                                1) < self.ksp_calib_width / 2

            self.coord = self.coord[calib_idx]
            self.y = self.y[:, calib_idx]

            if self.weights is not None:
                self.weights = self.weights[calib_idx]

        if self.weights is None:
            self.y = sp.to_device(self.y / np.abs(self.y).max(), self.device)
        else:
            self.y = sp.to_device(self.weights**0.5 *
                                  self.y / np.abs(self.y).max(), self.device)

        if self.coord is not None:
            self.coord = sp.to_device(self.coord, self.device)
        if self.weights is not None:
            self.weights = sp.to_device(self.weights, self.device)

        self.weights = _estimate_weights(self.y, self.weights, self.coord)
Beispiel #2
0
    def __init__(self,
                 ksp,
                 calib_width=24,
                 thresh=0.01,
                 kernel_width=6,
                 crop=0.8,
                 max_iter=100,
                 device=sp.cpu_device,
                 output_eigenvalue=False,
                 show_pbar=True):
        self.device = sp.Device(device)
        self.output_eigenvalue = output_eigenvalue
        self.crop = crop

        img_ndim = ksp.ndim - 1
        num_coils = len(ksp)
        with sp.get_device(ksp):
            # Get calibration region
            calib_shape = [num_coils] + [calib_width] * img_ndim
            calib = sp.resize(ksp, calib_shape)
            calib = sp.to_device(calib, device)

        xp = self.device.xp
        with self.device:
            # Get calibration matrix
            kernel_shape = [num_coils] + [kernel_width] * img_ndim
            kernel_strides = [1] * (img_ndim + 1)
            mat = sp.array_to_blocks(calib, kernel_shape, kernel_strides)
            mat = mat.reshape([-1, sp.prod(kernel_shape)])

            # Perform SVD on calibration matrix
            _, S, VH = xp.linalg.svd(mat, full_matrices=False)
            VH = VH[S > thresh * S.max(), :]

            # Get kernels
            num_kernels = len(VH)
            kernels = VH.reshape([num_kernels] + kernel_shape)
            img_shape = ksp.shape[1:]

            # Get covariance matrix in image domain
            AHA = xp.zeros(img_shape[::-1] + (num_coils, num_coils),
                           dtype=ksp.dtype)
            for kernel in kernels:
                img_kernel = sp.ifft(sp.resize(kernel, ksp.shape),
                                     axes=range(-img_ndim, 0))
                aH = xp.expand_dims(img_kernel.T, axis=-1)
                a = xp.conj(aH.swapaxes(-1, -2))
                AHA += aH @ a

            AHA *= (sp.prod(img_shape) / kernel_width**img_ndim)
            self.mps = xp.ones(ksp.shape[::-1] + (1, ), dtype=ksp.dtype)

            alg = sp.alg.PowerMethod(
                lambda x: AHA @ x,
                self.mps,
                norm_func=lambda x: xp.sum(
                    xp.abs(x)**2, axis=-2, keepdims=True)**0.5,
                max_iter=max_iter)

        super().__init__(alg, show_pbar=show_pbar)
Beispiel #3
0
    def _output(self):
        xp = self.device.xp
        # Coil by coil to save memory
        with self.device:
            mps_rss = 0
            mps = np.empty([self.num_coils] + self.img_shape, dtype=self.dtype)
            for c in range(self.num_coils):
                mps_c = sp.ifft(sp.resize(self.mps_ker[c], self.img_shape))
                mps_rss += xp.abs(mps_c)**2
                sp.copyto(mps[c], mps_c)

            mps_rss = sp.to_device(mps_rss**0.5, sp.cpu_device)
            mps /= mps_rss

        return mps
Beispiel #4
0
    def _output(self):
        xp = self.device.xp
        # Normalize by root-sum-of-squares.
        with self.device:
            rss = 0
            mps = np.empty([self.num_coils] + self.img_shape, dtype=self.dtype)
            for c in range(self.num_coils):
                mps_c = sp.ifft(sp.resize(self.mps_ker[c], self.img_shape))
                rss += xp.abs(mps_c)**2
                sp.copyto(mps[c], mps_c)

            rss = sp.to_device(rss)
            if self.comm is not None:
                self.comm.allreduce(rss)

            rss = rss**0.5
            mps /= rss
            return mps
Beispiel #5
0
def array_to_image(arr, color=False):
    """
    Flattens all dimensions except the last two

    """
    if color:
        arr = np.divide(arr,
                        np.abs(arr).max(),
                        out=np.zeros_like(arr),
                        where=arr != 0)

    if arr.ndim == 2:
        return arr
    elif color and arr.ndim == 3:
        return arr

    if color:
        ndim = 3
    else:
        ndim = 2

    arr = sp.resize(arr,
                    arr.shape[:-2] + (arr.shape[-2] + 2, arr.shape[-1] + 2))
    shape = arr.shape
    batch = sp.prod(shape[:-ndim])
    mshape = mosaic_shape(batch)

    if sp.prod(mshape) == batch:
        img = arr.reshape((batch, ) + shape[-ndim:])
    else:
        img = np.zeros((sp.prod(mshape), ) + shape[-ndim:], dtype=arr.dtype)
        img[:batch, ...] = arr.reshape((batch, ) + shape[-ndim:])

    img = img.reshape(mshape + shape[-ndim:])
    if color:
        img = np.transpose(img, (0, 2, 1, 3, 4))
        img = img.reshape(
            (shape[-3] * mshape[-2], shape[-2] * mshape[-1], shape[-1]))
    else:
        img = np.transpose(img, (0, 2, 1, 3))
        img = img.reshape((shape[-2] * mshape[-2], shape[-1] * mshape[-1]))

    return img
Beispiel #6
0
def prepare_knee_data(ismrmrd_path):
    """Convert ISMRMRD file to slices along readout.

    Args:
        ismrmrd_path (pathlib.Path): file path to ISMRMRD file.

    """

    logging.info('Processing {}'.format(ismrmrd_path.stem))
    dset = ismrmrd.Dataset(str(ismrmrd_path))
    hdr = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header())

    matrix_size_x = hdr.encoding[0].encodedSpace.matrixSize.x
    matrix_size_y = hdr.encoding[0].encodedSpace.matrixSize.y
    number_of_slices = hdr.encoding[0].encodingLimits.slice.maximum + 1
    number_of_channels = hdr.acquisitionSystemInformation.receiverChannels

    ksp = np.zeros(
        [number_of_channels, number_of_slices, matrix_size_y, matrix_size_x],
        dtype=np.complex64)
    for acqnum in range(dset.number_of_acquisitions()):
        acq = dset.read_acquisition(acqnum)

        y = acq.idx.kspace_encode_step_1
        ksp[:, acq.idx.slice, y, :] = acq.data

    ksp = np.fft.fft(np.fft.ifftshift(ksp, axes=-3), axis=-3)
    ksp_lr_bf = sp.resize(ksp, [
        number_of_channels, number_of_slices // 2, matrix_size_y // 2,
        matrix_size_x // 2
    ])
    ksp_lr = sp.resize(ksp_lr_bf, ksp.shape)
    del ksp

    #ksp_lr = sp.resize(sp.resize(ksp, [number_of_channels,
    #                                   number_of_slices // 2,
    #                                   matrix_size_y // 2,
    #                                   matrix_size_x]),
    #                   ksp.shape)

    #img = np.sum(np.abs(sp.ifft(ksp, axes=[-1, -2, -3]))**2, axis=0)**0.5
    img_lr_bf = np.sum(np.abs(sp.ifft(ksp_lr_bf, axes=[-1, -2, -3]))**2,
                       axis=0)**0.5
    #np.save("./stefan_data/img_lr_bf.npy", img_lr_bf)
    #quit()
    img_lr = np.sum(np.abs(sp.ifft(ksp_lr, axes=[-1, -2, -3]))**2, axis=0)**0.5
    smallMatrixX = matrix_size_x // 2
    scale = 1 / img_lr.max()
    scale2 = 1 / img_lr_bf.max()
    for i in range(matrix_size_x):
        logging.info('Processing {}_{:03d}'.format(ismrmrd_path.stem, i))
        #img_i_path = ismrmrd_path.parents[1] / 'img' / '{}_{:03d}'.format(ismrmrd_path.stem, i)
        #img_lr_i_path = ismrmrd_path.parents[1] / 'img_lr' / '{}_{:03d}'.format(ismrmrd_path.stem, i)
        img_lr_i_path = ismrmrd_path.parents[
            1] / 'img_lr2' / '{}_{:03d}'.format(ismrmrd_path.stem, i)
        if i < smallMatrixX:
            img_lr_bf_i_path = ismrmrd_path.parents[
                1] / 'img_lr2_bf' / '{}_{:03d}'.format(ismrmrd_path.stem, i)

        #img_i = img[..., i]
        img_lr_i = img_lr[..., i]
        if i < smallMatrixX:
            img_lr_bf_i = img_lr_bf[..., i]
        #np.save(str(img_i_path), img_i * scale)
        np.save(str(img_lr_i_path), img_lr_i * scale)
        if i < smallMatrixX:
            np.save(str(img_lr_bf_i_path), img_lr_bf_i * scale2)
Beispiel #7
0
def espirit_maps(ksp,
                 calib_width=24,
                 thresh=0.001,
                 kernel_width=6,
                 crop=0.8,
                 max_power_iter=30,
                 device=sp.cpu_device,
                 output_eigenvalue=False):
    """Generate ESPIRiT maps from k-space.

    Currently only supports outputting one set of maps.

    Args:
        ksp (array): k-space array of shape [num_coils, n_ndim, ..., n_1]
        calib (tuple of ints): length-2 image shape.
        thresh (float): threshold for the calibration matrix.
        kernel_width (int): kernel width for the calibration matrix.
        max_power_iter (int): maximum number of power iterations.
        device (Device): computing device.
        crop (int): cropping threshold.

    Returns:
        array: ESPIRiT maps of the same shape as ksp.

    References:
        Martin Uecker, Peng Lai, Mark J. Murphy, Patrick Virtue, Michael Elad,
        John M. Pauly, Shreyas S. Vasanawala, and Michael Lustig
        ESPIRIT - An Eigenvalue Approach to Autocalibrating Parallel MRI:
        Where SENSE meets GRAPPA.
        Magnetic Resonance in Medicine, 71:990-1001 (2014)

    """
    img_ndim = ksp.ndim - 1
    num_coils = len(ksp)
    with sp.get_device(ksp):
        # Get calibration region
        calib_shape = [num_coils] + [calib_width] * img_ndim
        calib = sp.resize(ksp, calib_shape)
        calib = sp.to_device(calib, device)

    device = sp.Device(device)
    xp = device.xp
    with device:
        # Get calibration matrix
        kernel_shape = [num_coils] + [kernel_width] * img_ndim
        kernel_strides = [1] * (img_ndim + 1)
        mat = sp.array_to_blocks(calib, kernel_shape, kernel_strides)
        mat = mat.reshape([-1, sp.prod(kernel_shape)])

        # Perform SVD on calibration matrix
        _, S, VH = xp.linalg.svd(mat, full_matrices=False)
        VH = VH[S > thresh * S.max(), :]

        # Get kernels
        num_kernels = len(VH)
        kernels = VH.reshape([num_kernels] + kernel_shape)
        img_shape = ksp.shape[1:]

        # Get covariance matrix in image domain
        AHA = xp.zeros(img_shape[::-1] + (num_coils, num_coils),
                       dtype=ksp.dtype)
        for kernel in kernels:
            img_kernel = sp.ifft(sp.resize(kernel, ksp.shape),
                                 axes=range(-img_ndim, 0))
            aH = xp.expand_dims(img_kernel.T, axis=-1)
            a = xp.conj(aH.swapaxes(-1, -2))
            AHA += aH @ a

        AHA *= (sp.prod(img_shape) / kernel_width**img_ndim)

        # Power Iteration to compute top eigenvector
        mps = xp.ones(ksp.shape[::-1] + (1, ), dtype=ksp.dtype)
        for _ in range(max_power_iter):
            sp.copyto(mps, AHA @ mps)
            eig_value = xp.sum(xp.abs(mps)**2, axis=-2, keepdims=True)**0.5
            mps /= eig_value

        # Normalize phase with respect to first channel
        mps = mps.T[0]
        mps *= xp.conj(mps[0] / xp.abs(mps[0]))

        # Crop maps by thresholding eigenvalue
        eig_value = eig_value.T[0]
        mps *= eig_value > crop

        if output_eigenvalue:
            return mps, eig_value
        else:
            return mps