def test_im2ksp_cart(self): # Image to k-space transformation for Cartesian data ksp = im2ksp(M=ph, cartesian_opt=1) self.assertEqual(ksp.shape, ph.shape) # Dimensions agree self.assertEqual( ((ksp - cart_ksp) == np.zeros(ksp.shape).astype(complex)).all(), True) # Transformation is correct
def test_im2ksp_noncart(self): # Image to k-space transformation for non-Cartesian data nufft_obj = nufft_init(kt=ktraj, params=acq_params) ksp = im2ksp( M=ph, cartesian_opt=0, NufftObj=nufft_obj, params=acq_params) # Sample the image along the trajectory self.assertEqual(ksp.shape, ktraj.shape) # Dimensions match
def add_or(M, kt, df, nonCart=None, params=None): '''Forward model for off-resonance simulation Parameters ---------- M : numpy.ndarray Image data kt : numpy.ndarray k-space trajectory df : numpy.ndarray Field map nonCart : int , optional Cartesian/Non-Cartesian trajectory option. Default is None. params : dict , optional Sequence parameters. Default is None. Returns ------- M_or : numpy.ndarray Off-resonance corrupted image data ''' '''Create a phase matrix - 2*pi*df*t for every df and every t''' if nonCart is not None: cartesian_opt = 0 NufftObj = nufft_init(kt, params) else: cartesian_opt = 1 NufftObj = None params = None kspace = im2ksp(M, cartesian_opt, NufftObj, params) M_or = np.zeros(M.shape, dtype=complex) for x in range(M.shape[0]): for y in range(M.shape[1]): phi = 2 * pi * df[x, y] * kt kspace_orc = kspace * np.exp(-1j * phi) M_corr = ksp2im(kspace_orc, cartesian_opt, NufftObj, params) M_or[x, y] = M_corr[x, y] return M_or
def test_cartesian_opt(self): # cartesian_opt can only be 0 or 1, otherwise error with self.assertRaises(ValueError): im2ksp(M=ph, cartesian_opt=5) with self.assertRaises(ValueError): ksp2im(ksp=cart_ksp, cartesian_opt=100)
def MFI(dataIn, dataInType, kt, df, Lx, nonCart=None, params=None): '''Off-resonance Correction by Multi-Frequency Interpolation Man, L., Pauly, J. M. and Macovski, A. (1997), Multifrequency interpolation for fast off‐resonance correction. Magn. Reson. Med., 37: 785-792. doi:10.1002/mrm.1910370523 Parameters ---------- dataIn : numpy.ndarray k-space raw data or image data dataInType : str Can be either 'raw' or 'im' kt : numpy.ndarray k-space trajectory df : numpy.ndarray Field map Lx : int L (frequency bins) factor nonCart : int Non-cartesian trajectory option. Default is None (Cartesian). params : dict Sequence parameters. Default is None. Returns ------- M_hat : numpy.ndarray Corrected image data. ''' if nonCart is not None and nonCart == 1: check_inputs_noncartesian(dataIn.shape, dataInType, kt.shape, df.shape, params) cartesian_opt = 0 NufftObj = nufft_init(kt, params) t_vector = params['t_vector'] T = np.tile(params['t_vector'], (1, kt.shape[1])) t_ro = T[-1, 0] - T[0, 0] # T[end] - TE N = params['N'] elif nonCart == 'EPI': # check_inputs_cartesian(dataIn.shape, dataInType, kt.shape, df.shape) cartesian_opt = 1 NufftObj = None T = np.flipud(params['t_vector']).reshape(params['N'], params['N']) T[1:params['N']:2, :] = np.fliplr(T[1:params['N']:2, :]) N = dataIn.shape[0] t_ro = params['t_readout'] t_vector = params['t_vector'] else: check_inputs_cartesian(dataIn.shape, dataInType, kt.shape, df.shape) cartesian_opt = 1 NufftObj = None N = dataIn.shape[0] t_vector = kt[0].reshape(kt.shape[1], 1) T = kt t_ro = T[0, -1] - T[0, 0] if dataInType == 'im': rawData = im2ksp(dataIn, cartesian_opt, NufftObj, params) elif dataInType == 'raw': rawData = dataIn df = np.round(df, 1) idx, idy = np.where(df == -0.0) df[idx, idy] = 0.0 # Number of frequency segments df_max = max(np.abs([df.max(), df.min()])) # Hz df_range = (df.min(), df.max()) L = ceil(df_max * 2 * pi * t_ro / pi) L = L * Lx if len(np.unique(df)) == 1: L = 1 f_L = np.linspace(df.min(), df.max(), L + 1) # Hz #T = np.tile(params['t_vector'], (1, kt.shape[1])) # reconstruct the L basic images M_MFI = np.zeros((N, N, L + 1), dtype=complex) for l in range(L + 1): phi = 2 * pi * f_L[l] * T kspace_L = rawData * np.exp(1j * phi) M_MFI[:, :, l] = ksp2im(kspace_L, cartesian_opt, NufftObj, params) # calculate MFI coefficients coeffs_LUT = coeffs_MFI_lsq(kt, f_L, df_range, t_vector) # final image reconstruction M_hat = np.zeros((N, N), dtype=complex) for i in range(M_hat.shape[0]): for j in range(M_hat.shape[1]): fieldmap_val = df[i, j] val_coeffs = coeffs_LUT[str(fieldmap_val)] M_hat[i, j] = sum(val_coeffs * M_MFI[i, j, :]) return M_hat
def fs_CPR(dataIn, dataInType, kt, df, Lx, nonCart=None, params=None): '''Off-resonance Correction by frequency-segmented Conjugate Phase Reconstruction Noll, D. C., Pauly, J. M., Meyer, C. H., Nishimura, D. G. and Macovskj, A. (1992), Deblurring for non‐2D fourier transform magnetic resonance imaging. Magn. Reson. Med., 25: 319-333. doi:10.1002/mrm.1910250210 Parameters ---------- dataIn : numpy.ndarray k-space raw data or image data dataInType : str Can be either 'raw' or 'im' kt : numpy.ndarray k-space trajectory df : numpy.ndarray Field map Lx : int L (frequency bins) factor nonCart : int Non-cartesian trajectory option. Default is None (Cartesian). params : dict Sequence parameters. Default is None (Cartesian). Returns ------- M_hat : numpy.ndarray Corrected image data. ''' if nonCart is not None and nonCart == 1: check_inputs_noncartesian(dataIn.shape, dataInType, kt.shape, df.shape, params) cartesian_opt = 0 NufftObj = nufft_init(kt, params) T = np.tile(params['t_vector'], (1, kt.shape[1])) N = params['N'] t_ro = T[-1, 0] - T[0, 0] # T[end] - TE elif nonCart == 'EPI': # check_inputs_cartesian(dataIn.shape, dataInType, kt.shape, df.shape) cartesian_opt = 1 NufftObj = None T = np.flipud(params['t_vector']).reshape(params['N'], params['N']) T[1:params['N']:2, :] = np.fliplr(T[1:params['N']:2, :]) N = dataIn.shape[0] t_ro = params['t_readout'] else: check_inputs_cartesian(dataIn.shape, dataInType, kt.shape, df.shape) cartesian_opt = 1 NufftObj = None N = dataIn.shape[0] t_vector = kt[0].reshape(kt.shape[1], 1) T = kt t_ro = T[0, -1] - T[0, 0] if dataInType == 'im': rawData = im2ksp(dataIn, cartesian_opt, NufftObj, params) elif dataInType == 'raw': rawData = dataIn # Number of frequency segments df_max = max(np.abs([df.max(), df.min()])) # Hz L = ceil(4 * df_max * 2 * pi * t_ro / pi) L = L * Lx if len(np.unique(df)) == 1: L = 1 f_L = np.linspace(df.min(), df.max(), L + 1) # Hz # T = np.tile(params['t_vector'], (1, kt.shape[1])) # reconstruct the L basic images M_fsCPR = np.zeros((N, N, L + 1), dtype=complex) for l in range(L + 1): phi = 2 * pi * f_L[l] * T kspace_L = rawData * np.exp(1j * phi) M_fsCPR[:, :, l] = ksp2im(kspace_L, cartesian_opt, NufftObj, params) # final image reconstruction M_hat = np.zeros((N, N), dtype=complex) for i in range(M_hat.shape[0]): for j in range(M_hat.shape[1]): fieldmap_val = df[i, j] closest_fL_idx = find_nearest(f_L, fieldmap_val) if fieldmap_val == f_L[closest_fL_idx]: pixel_val = M_fsCPR[i, j, closest_fL_idx] else: if fieldmap_val < f_L[closest_fL_idx]: f_vals = [f_L[closest_fL_idx - 1], f_L[closest_fL_idx]] im_vals = [ M_fsCPR[i, j, closest_fL_idx - 1], M_fsCPR[i, j, closest_fL_idx] ] else: f_vals = [f_L[closest_fL_idx], f_L[closest_fL_idx + 1]] im_vals = [ M_fsCPR[i, j, closest_fL_idx], M_fsCPR[i, j, closest_fL_idx + 1] ] pixel_val = np.interp(fieldmap_val, f_vals, im_vals) M_hat[i, j] = pixel_val return M_hat
def CPR(dataIn, dataInType, kt, df, nonCart=None, params=None): '''Off-resonance Correction by Conjugate Phase Reconstruction Maeda, A., Sano, K. and Yokoyama, T. (1988), Reconstruction by weighted correlation for MRI with time-varying gradients. IEEE Transactions on Medical Imaging, 7(1): 26-31. doi: 10.1109/42.3926 Parameters ---------- dataIn : numpy.ndarray k-space raw data or image data dataInType : str Can be either 'raw' or 'im' kt : numpy.ndarray k-space trajectory. df : numpy.ndarray Field map nonCart : int Non-cartesian trajectory option. Default is None (Cartesian). params : dict Sequence parameters. Default is None (Cartesian). Returns ------- M_hat : numpy.ndarray Corrected image data. ''' if nonCart is not None and nonCart == 1: check_inputs_noncartesian(dataIn.shape, dataInType, kt.shape, df.shape, params) cartesian_opt = 0 NufftObj = nufft_init(kt, params) T = np.tile(params['t_vector'], (1, kt.shape[1])) N = params['N'] elif nonCart == 'EPI': # check_inputs_cartesian(dataIn.shape, dataInType, kt.shape, df.shape) cartesian_opt = 1 NufftObj = None T = np.flipud(params['t_vector']).reshape(params['N'], params['N']) T[1:params['N']:2, :] = np.fliplr(T[1:params['N']:2, :]) N = dataIn.shape[0] else: check_inputs_cartesian(dataIn.shape, dataInType, kt.shape, df.shape) cartesian_opt = 1 NufftObj = None T = kt N = dataIn.shape[0] if dataInType == 'im': rawData = im2ksp(dataIn, cartesian_opt, NufftObj, params) elif dataInType == 'raw': rawData = dataIn df_values = np.unique(df) M_CPR = np.zeros((N, N, len(df_values)), dtype=complex) for i in range(len(df_values)): phi = 2 * pi * df_values[i] * T kspace_orc = rawData * np.exp(1j * phi) M_corr = ksp2im(kspace_orc, cartesian_opt, NufftObj, params) M_CPR[:, :, i] = M_corr M_hat = np.zeros((N, N), dtype=complex) for x in range(df.shape[0]): for y in range(df.shape[1]): fieldmap_val = df[x, y] idx = np.where(df_values == fieldmap_val) M_hat[x, y] = M_CPR[x, y, idx] return M_hat
def add_or_CPR(M, kt, df, nonCart=None, params=None): '''Forward model for off-resonance simulation. The number of fourier transforms = number of unique values in the field map. Parameters ---------- M : numpy.ndarray Image data kt : numpy.ndarray k-space trajectory df : numpy.ndarray Field map nonCart : int , optional Cartesian/Non-Cartesian trajectory option. Default is None. params : dict , optional Sequence parameters. Default is None. Returns ------- M_or : numpy.ndarray Off-resonance corrupted image data ''' # Create a phase matrix - 2*pi*df*t for every df and every t if nonCart is not None and nonCart == 1: cartesian_opt = 0 NufftObj = nufft_init(kt, params) T = np.tile(params['t_vector'], (1, kt.shape[1])) elif nonCart == 'EPI': cartesian_opt = 1 NufftObj = None T = np.flipud(params['t_vector']).reshape(params['N'], params['N']) T[1:params['N']:2, :] = np.fliplr(T[1:params['N']:2, :]) else: cartesian_opt = 1 NufftObj = None params = None T = kt kspace = im2ksp(M, cartesian_opt, NufftObj, params) df_values = np.unique(df) M_or_CPR = np.zeros((M.shape[0], M.shape[1], len(df_values)), dtype=complex) kspsave = np.zeros((kspace.shape[0], kspace.shape[1], len(df_values)), dtype=complex) for i in range(len(df_values)): phi = -2 * pi * df_values[i] * T kspace_or = kspace * np.exp(1j * phi) kspsave[:, :, i] = kspace_or M_corr = ksp2im(kspace_or, cartesian_opt, NufftObj, params) M_or_CPR[:, :, i] = M_corr M_or = np.zeros(M.shape, dtype=complex) for x in range(M.shape[0]): for y in range(M.shape[1]): fieldmap_val = df[x, y] idx = np.where(df_values == fieldmap_val) M_or[x, y] = M_or_CPR[x, y, idx] '''plt.imshow(abs(M_or)) plt.show()''' return M_or, kspsave