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)
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)
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
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
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
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)
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