def test_simulated_2d(self): # # Kind of neat - seeing how phase changes with coil sensitivity... # view(np.angle(coil_ims0)) # Do GS solution to ESM then take SOS recon_gs = np.zeros(self.coil_ims0.shape,dtype='complex') for ii in range(self.num_coils): recon_gs[ii,...] = gs_recon(self.coil_ims0[ii,...],self.coil_ims1[ii,...],self.coil_ims2[ii,...],self.coil_ims3[ii,...]) # view(np.angle(recon_gs)) # realize this is actually a movie - they all just look the same... recon_gs_sos = sos(recon_gs,axes=(0)) view(recon_gs_sos) # Do PCA n_components = 4 pca0 = coil_pca(self.coil_ims0,coil_dim=0,n_components=n_components) pca1 = coil_pca(self.coil_ims1,coil_dim=0,n_components=n_components) pca2 = coil_pca(self.coil_ims2,coil_dim=0,n_components=n_components) pca3,expl_var = coil_pca(self.coil_ims3,coil_dim=0,n_components=n_components,give_explained_var=True) # view(expl_var.real) # view(np.angle(pca3)) # Do GS solution to ESM then take SOS, this time using PCA'd data recon_pca_gs = np.zeros(pca0.shape,dtype='complex') for ii in range(n_components): # view(np.concatenate((pca0[ii,...],pca1[ii,...],pca2[ii,...],pca3[ii,...]))) recon_pca_gs[ii,...] = gs_recon(pca0[ii,...],pca1[ii,...],pca2[ii,...],pca3[ii,...]) # view(np.angle(recon_pca_gs)) recon_pca_gs_sos = sos(recon_pca_gs,axes=(0))
def test_multiphase(self): # Check out what we got: # view(self.kspace,fft=True,movie_axis=0,montage_axis=3) # Under sample even, odd lines kspace = self.kspace.copy() Rx = 2 kspace[0,0::Rx,:,:] = 0 kspace[1,1::Rx,:,:] = 0 # view(kspace[0,...],fft=False) # Make an autocalibration region by combining center lines from each # Right now still struggling to get GRAPPA to work... num_acl_lines = 24 acl_idx = range(int(kspace.shape[2]/2-num_acl_lines/2),int(kspace.shape[2]/2+num_acl_lines/2)) acl = self.kspace[0,:,acl_idx,:].transpose((2,0,1)) view(acl,log=True) # We also need to get some coil sensitivity maps, let's try a crude one # first from original data. Later we'll do espirit... imspace = np.fft.fftshift(np.fft.fft2(self.kspace,axes=(1,2)),axes=(1,2)) comb_sos = sos(imspace[0,...],axes=-1)[...,None] sens = (np.abs(imspace[0,...])/np.tile(comb_sos,(1,1,4))).transpose((2,0,1)) view(sens) # Get coils in the image domain with dims in order grappa2d expects coil_ims_pc_0 = np.fft.fftshift(np.fft.ifft2(kspace[0,...],axes=(0,1)),axes=(0,1)).transpose((2,0,1)) view(coil_ims_pc_0) recon = grappa2d(coil_ims_pc_0,sens,acs=acl,Rx=2,Ry=1) recon = sos(recon,axes=0) view(recon)
def test_grappa2d(self): from mr_utils.recon.grappa import grappa2d from mr_utils.test_data import GRAPPA # Get everything set up with downsampling and such im = GRAPPA.phantom_shl() sens = GRAPPA.csm() # view(sens) coils = sens * im kspace = np.fft.fftshift( np.fft.fft2(np.fft.ifftshift(coils), axes=(1, 2))) Rx = 2 kspace_d = np.zeros(kspace.shape, dtype='complex') kspace_d[:, ::Rx, :] = kspace[:, ::Rx, :] # Get the undersampled image space coil images coil_ims = np.fft.fftshift( np.fft.ifft2(np.fft.ifftshift(kspace_d), axes=(1, 2))) # Get the autocalibration signal center_row, pad = int(sens.shape[1] / 2), 8 mask = np.zeros(kspace_d.shape, dtype=bool) mask[:, center_row - pad:center_row + pad, :] = True acs = kspace[mask].reshape((sens.shape[0], -1, mask.shape[-1])) # view(acs) # Run the recon recon = grappa2d(coil_ims, sens, acs, Rx, Ry=1, kernel_size=(3, 3)) # Check to see if the answers match recon = sos(recon, axes=0) recon_mat = GRAPPA.Im_Recon() self.assertTrue(np.allclose(recon, recon_mat))
def test_simulated_2d_kspace(self): # Do PCA on kspace n_components = 4 pca0 = coil_pca(self.kspace_coil_ims0,coil_dim=0,n_components=n_components) pca1 = coil_pca(self.kspace_coil_ims1,coil_dim=0,n_components=n_components) pca2 = coil_pca(self.kspace_coil_ims2,coil_dim=0,n_components=n_components) pca3,expl_var = coil_pca(self.kspace_coil_ims3,coil_dim=0,n_components=n_components,give_explained_var=True) # view(expl_var.imag) # Put it back in image space pca0 = np.fft.ifftshift(np.fft.ifft2(np.fft.ifftshift(pca0,axes=(1,2)),axes=(1,2)),axes=(1,2)) pca1 = np.fft.ifftshift(np.fft.ifft2(np.fft.ifftshift(pca1,axes=(1,2)),axes=(1,2)),axes=(1,2)) pca2 = np.fft.ifftshift(np.fft.ifft2(np.fft.ifftshift(pca2,axes=(1,2)),axes=(1,2)),axes=(1,2)) pca3 = np.fft.ifftshift(np.fft.ifft2(np.fft.ifftshift(pca3,axes=(1,2)),axes=(1,2)),axes=(1,2)) # Do GS solution to ESM then take SOS, this time using PCA'd data recon_pca_gs = np.zeros(pca0.shape,dtype='complex') for ii in range(n_components): # view(np.concatenate((pca0[ii,...],pca1[ii,...],pca2[ii,...],pca3[ii,...]))) recon_pca_gs[ii,...] = gs_recon(pca0[ii,...],pca1[ii,...],pca2[ii,...],pca3[ii,...]) # view(np.angle(recon_pca_gs)) recon_pca_gs_sos = sos(recon_pca_gs,axes=(0))
def M0fun(x, y, T1, T2, theta, TR, alpha): '''Residual for M0 estimation.''' y00 = ssfp(T1, T2, TR, alpha, field_map=theta, phase_cyc=0, M0=x[3]) y01 = ssfp(T1, T2, TR, alpha, field_map=theta, phase_cyc=np.pi, M0=x[3]) y0 = sos((y00, y01)) return y0 - y
T2 = np.random.random(1)[0] * (bnds[1][1] - bnds[0][1]) + bnds[0][1] df = np.random.random(1)[0] * (bnds[1][2] - bnds[0][2]) + bnds[0][2] M0 = np.random.random(1)[0] * (bnds[1][3] - bnds[0][3]) + bnds[0][3] # Simulate acquisiton of two phase cycles y_train0 = ssfp(T1, T2, TR, alpha, field_map=df, phase_cyc=0, M0=M0) y_train1 = ssfp(T1, T2, TR, alpha, field_map=df, phase_cyc=np.pi, M0=M0) y_train = np.array( (y_train0.real, y_train1.real, y_train0.imag, y_train1.imag)) M0_train = sos((y_train0, y_train1)) # Initialize x0 = np.zeros(4) # x0 = (T1, T2, theta, M0) loss = ['linear', 'soft_l1', 'huber', 'cauchy', 'arctan'] weights = [1, 2] x0[0] = (bnds[1][0] + bnds[0][0]) / 2 x0[1] = (bnds[1][1] + bnds[0][1]) / 2 x0[2] = (bnds[1][2] + bnds[0][2]) / 2 x0[3] = M0_train # Guess M0 is SOS # Do a 2 step update for a fixed number of steps: for ii in range(10): # Solve for M0, only to modify x[3] x = least_squares(M0fun, x0,
axes=(1, 2)), axes=(1, 2)) kspace_coil_ims3 = np.fft.fftshift(np.fft.fft2(np.fft.fftshift(coil_ims3, axes=(1, 2)), axes=(1, 2)), axes=(1, 2)) view(np.angle(coil_ims0)) # Do GS solution to ESM then take SOS recon_gs = np.zeros(coil_ims0.shape, dtype='complex') for ii in range(num_coils): recon_gs[ii, ...] = gs_recon(coil_ims0[ii, ...], coil_ims1[ii, ...], coil_ims2[ii, ...], coil_ims3[ii, ...]) recon_gs_sos = sos(recon_gs, axes=(0)) view(recon_gs_sos) # Do PCA n_components = 4 pca0 = coil_pca(coil_ims0, coil_dim=0, n_components=n_components) pca1 = coil_pca(coil_ims1, coil_dim=0, n_components=n_components) pca2 = coil_pca(coil_ims2, coil_dim=0, n_components=n_components) pca3, expl_var = coil_pca(coil_ims3, coil_dim=0, n_components=n_components, give_explained_var=True) view(expl_var.real) view(np.angle(pca3)) # Do GS solution to ESM then take SOS, this time using PCA'd data
data = np.load(data_fft_filename) else: # Else we'll have to do it ourselves data = np.load(dirname(__file__) + '/data.npy') # Put 'er in image space print('Starting fft...') data = np.fft.fftshift(np.fft.fft2(data, axes=(0, 1)), axes=(0, 1)) np.save(data_fft_filename, data) print('Finished saving fft!') # Tell me about it print('Data shape is:', data.shape) sx, sy, nc, nt, ns = data.shape[:] # Take a look at it in all its glory -- notice significant motion view(sos(data[..., 1::16, :], axes=2).squeeze(), montage_axis=-1, movie_axis=-2) # For each coil for all slices for each possible GS recon in N time points N = 16 # since we have 16 unique phase-cycles... print('Starting GS recons...') sh = np.array(data.shape) num_gs_recons = int(N / 4) # need 4 coil images for GS recon sh[3] = num_gs_recons recons = np.zeros(sh, dtype=data.dtype) for ii in trange(num_gs_recons, desc='GS recons', leave=False): for cc in trange(nc, desc='Coils', leave=False): ims = data[..., cc, ii:N:4, :] recons[..., cc, ii, :] = gs_recon3d( *[x.squeeze() for x in np.split(ims, 4, axis=-2)])
path = 'mr_utils/test_data/examples/coils/' imspace, kspace = load_test_data(path, ['imspace', 'kspace']) print(imspace.shape) nx, ny, nc, npcs = imspace.shape[:] trim = int(nx / 4) pcs = np.linspace(0, 2 * np.pi, npcs, endpoint=False) # Get mask ngs = int(npcs / 4) tmp = np.zeros((nx, ny, nc, ngs), dtype='complex') for coil in range(nc): for ii in range(ngs): tmp[..., coil, ii] = gs_recon(imspace[..., coil, ii::4], pc_axis=-1) im_true = np.mean(tmp, axis=-1) im_true = sos(im_true, axes=-1) thresh = threshold_li(im_true) mask = im_true > thresh # view(im_true) # view(mask) # Define coil combination functions ccs, cc_list = get_coil_combine_funs(np.min([nx, ny]), v='') # Do coil combine then ESM res = np.zeros((len(ccs), nx, ny), dtype='complex') err_cc_then_gs = np.zeros(len(ccs)) for fun, cc in enumerate(ccs): tmp = np.zeros((nx, ny, ngs), dtype='complex') idx = list(range(npcs))[::4]
def comparison_numerical_phantom(SNR=None): '''Compare coil by coil, Walsh method, and Inati iterative method.''' true_im = get_true_im_numerical_phantom() csms = get_coil_sensitivity_maps() params = get_numerical_phantom_params(SNR=SNR) pc_vals = params['pc_vals'] dim = params['dim'] noise_std = params['noise_std'] coil_nums = params['coil_nums'] # We want to solve gs_recon for each coil we have in the pc set err = np.zeros((5, len(csms))) rip = err.copy() for ii, csm in enumerate(csms): # I have coil sensitivities, now I need images to apply them to. # coil_ims: (pc,coil,x,y) coil_ims = np.zeros((len(pc_vals), csm.shape[0], dim, dim), dtype='complex') for jj, pc in enumerate(pc_vals): im = bssfp_2d_cylinder(dims=(dim, dim), phase_cyc=pc) im += 1j * im coil_ims[jj, ...] = im * csm coil_ims[jj, ...] += np.random.normal(0, noise_std, coil_ims[ jj, ...].shape) / 2 + 1j * np.random.normal( 0, noise_std, coil_ims[jj, ...].shape) / 2 # Solve the gs_recon coil by coil coil_ims_gs = np.zeros((csm.shape[0], dim, dim), dtype='complex') for kk in range(csm.shape[0]): coil_ims_gs[kk, ...] = gs_recon(*[ x.squeeze() for x in np.split(coil_ims[:, kk, ...], len(pc_vals)) ]) coil_ims_gs[np.isnan(coil_ims_gs)] = 0 # Easy way out: combine all the coils using sos im_est_sos = sos(coil_ims_gs) # view(im_est_sos) # Take coil by coil solution and do Walsh on it to collapse coil dim # walsh csm_walsh, _ = calculate_csm_walsh(coil_ims_gs) im_est_recon_then_walsh = np.sum(csm_walsh * np.conj(coil_ims_gs), axis=0) im_est_recon_then_walsh[np.isnan(im_est_recon_then_walsh)] = 0 # view(im_est_recon_then_walsh) # inati csm_inati, im_est_recon_then_inati = calculate_csm_inati_iter( coil_ims_gs) # Collapse the coil dimension of each phase-cycle using Walsh,Inati pc_est_walsh = np.zeros((len(pc_vals), dim, dim), dtype='complex') pc_est_inati = np.zeros((len(pc_vals), dim, dim), dtype='complex') for jj in range(len(pc_vals)): ## Walsh csm_walsh, _ = calculate_csm_walsh(coil_ims[jj, ...]) pc_est_walsh[jj, ...] = np.sum(csm_walsh * np.conj(coil_ims[jj, ...]), axis=0) # view(csm_walsh) # view(pc_est_walsh) ## Inati csm_inati, pc_est_inati[jj, ...] = calculate_csm_inati_iter( coil_ims[jj, ...], smoothing=1) # pc_est_inati[jj,...] = np.sum(csm_inati*np.conj(coil_ims[jj,...]),axis=0) # view(csm_inati) # Now solve the gs_recon using collapsed coils im_est_walsh = gs_recon( *[x.squeeze() for x in np.split(pc_est_walsh, len(pc_vals))]) im_est_inati = gs_recon( *[x.squeeze() for x in np.split(pc_est_inati, len(pc_vals))]) # view(im_est_walsh) # view(im_est_recon_then_walsh) # Compute error metrics err[0, ii] = compare_nrmse(im_est_sos, true_im) err[1, ii] = compare_nrmse(im_est_recon_then_walsh, true_im) err[2, ii] = compare_nrmse(im_est_recon_then_inati, true_im) err[3, ii] = compare_nrmse(im_est_walsh, true_im) err[4, ii] = compare_nrmse(im_est_inati, true_im) im_est_sos[np.isnan(im_est_sos)] = 0 im_est_recon_then_walsh[np.isnan(im_est_recon_then_walsh)] = 0 im_est_recon_then_inati[np.isnan(im_est_recon_then_inati)] = 0 im_est_walsh[np.isnan(im_est_walsh)] = 0 im_est_inati[np.isnan(im_est_inati)] = 0 rip[0, ii] = ripple_normal(im_est_sos) rip[1, ii] = ripple_normal(im_est_recon_then_walsh) rip[2, ii] = ripple_normal(im_est_recon_then_inati) rip[3, ii] = ripple_normal(im_est_walsh) rip[4, ii] = ripple_normal(im_est_inati) # view(im_est_inati) # # SOS of the gs solution on each individual coil gives us low periodic # # ripple accross the phantom, similar to Walsh method: # plt.plot(np.abs(true_im[int(dim/2),:]),'--',label='True Im') # plt.plot(np.abs(im_est_sos[int(dim/2),:]),'-.',label='SOS') # plt.plot(np.abs(im_est_recon_then_walsh[int(dim/2),:]),label='Recon then Walsh') # plt.plot(np.abs(im_est_walsh[int(dim/2),:]),label='Walsh then Recon') # # plt.plot(np.abs(im_est_inati[int(dim/2),:]),label='Inati') # plt.legend() # plt.show() # # Let's show some stuff # plt.plot(coil_nums,err[0,:],'*-',label='SOS') # plt.plot(coil_nums,err[1,:],label='Recon then Walsh') # plt.plot(coil_nums,err[2,:],label='Walsh then Recon') # # plt.plot(coil_nums,err[3,:],label='Inati') # plt.legend() # plt.show() print('SOS RMSE:', np.mean(err[0, :])) print('recon then walsh RMSE:', np.mean(err[1, :])) print('recon then inati RMSE:', np.mean(err[2, :])) print('walsh then recon RMSE:', np.mean(err[3, :])) print('inati then recon RMSE:', np.mean(err[4, :])) print('SOS ripple:', np.mean(err[0, :])) print('recon then walsh ripple:', np.mean(rip[1, :])) print('recon then inati ripple:', np.mean(rip[2, :])) print('walsh then recon ripple:', np.mean(rip[3, :])) print('inati then recon ripple:', np.mean(rip[4, :])) view(im_est_recon_then_walsh[int(dim / 2), :]) view(im_est_recon_then_inati[int(dim / 2), :]) view(im_est_walsh[int(dim / 2), :]) view(im_est_inati[int(dim / 2), :]) # view(im_est_inati) # view(np.stack((im_est_recon_then_walsh,im_est_recon_then_inati,im_est_walsh,im_est_inati))) return (err)
def comparison_knee(): '''Coil by coil, Walsh method, and Inati iterative method for knee data.''' # Load the knee data dir = '/home/nicholas/Documents/rawdata/SSFP_SPECTRA_dphiOffset_08022018/' files = [ 'meas_MID362_TRUFI_STW_TE3_FID29379', 'meas_MID363_TRUFI_STW_TE3_dphi_45_FID29380', 'meas_MID364_TRUFI_STW_TE3_dphi_90_FID29381', 'meas_MID365_TRUFI_STW_TE3_dphi_135_FID29382', 'meas_MID366_TRUFI_STW_TE3_dphi_180_FID29383', 'meas_MID367_TRUFI_STW_TE3_dphi_225_FID29384', 'meas_MID368_TRUFI_STW_TE3_dphi_270_FID29385', 'meas_MID369_TRUFI_STW_TE3_dphi_315_FID29386' ] pc_vals = [0, 45, 90, 135, 180, 225, 270, 315] dims = (512, 256) num_coils = 4 num_avgs = 16 # # Load in raw once, then save as npy with collapsed avg dimension # pcs = np.zeros((len(files),dims[0],dims[1],num_coils),dtype='complex') # for ii,file in enumerate(files): # pcs[ii,...] = np.mean(load_raw('%s/%s.dat' % (dir,file),use='s2i'),axis=-1) # np.save('%s/te3.npy' % dir,pcs) # pcs looks like (pc,x,y,coil) pcs = np.load('%s/te3.npy' % dir) pcs = np.fft.fftshift(np.fft.fft2(pcs, axes=(1, 2)), axes=(1, 2)) # print(pcs.shape) # view(pcs,fft=True,montage_axis=0,movie_axis=3) # Do recon then coil combine coils0 = np.zeros((pcs.shape[-1], pcs.shape[1], pcs.shape[2]), dtype='complex') coils1 = coils0.copy() for ii in range(pcs.shape[-1]): # We have two sets: 0,90,180,27 and 45,135,225,315 idx0 = [0, 2, 4, 6] idx1 = [1, 3, 5, 7] coils0[ii, ...] = gs_recon(*[x.squeeze() for x in pcs[idx0, :, :, ii]]) coils1[ii, ...] = gs_recon(*[x.squeeze() for x in pcs[idx1, :, :, ii]]) # Then do the coil combine csm_walsh, _ = calculate_csm_walsh(coils0) im_est_recon_then_walsh0 = np.sum(csm_walsh * np.conj(coils0), axis=0) # view(im_est_recon_then_walsh0) csm_walsh, _ = calculate_csm_walsh(coils1) im_est_recon_then_walsh1 = np.sum(csm_walsh * np.conj(coils1), axis=0) # view(im_est_recon_then_walsh1) rip0 = ripple(im_est_recon_then_walsh0) rip1 = ripple(im_est_recon_then_walsh1) print('recon then walsh: ', np.mean([rip0, rip1])) # Now try inati csm_inati, im_est_recon_then_inati0 = calculate_csm_inati_iter(coils0, smoothing=5) csm_inati, im_est_recon_then_inati1 = calculate_csm_inati_iter(coils1, smoothing=5) rip0 = ripple(im_est_recon_then_inati0) rip1 = ripple(im_est_recon_then_inati1) print('recon then inati: ', np.mean([rip0, rip1])) # Now try sos im_est_recon_then_sos0 = sos(coils0, axes=0) im_est_recon_then_sos1 = sos(coils1, axes=0) rip0 = ripple(im_est_recon_then_sos0) rip1 = ripple(im_est_recon_then_sos1) print('recon then sos: ', np.mean([rip0, rip1])) # view(im_est_recon_then_sos) ## Now the other way, combine then recon pcs0 = np.zeros((2, pcs.shape[0], pcs.shape[1], pcs.shape[2]), dtype='complex') pcs1 = pcs0.copy() for ii in range(pcs.shape[0]): # Walsh it up csm_walsh, _ = calculate_csm_walsh(pcs[ii, ...].transpose((2, 0, 1))) pcs0[0, ii, ...] = np.sum(csm_walsh * np.conj(pcs[ii, ...].transpose( (2, 0, 1))), axis=0) # view(pcs0[ii,...]) # Inati it up csm_inati, pcs0[1, ii, ...] = calculate_csm_inati_iter(pcs[ii, ...].transpose( (2, 0, 1)), smoothing=5) ## Now perform gs_recon on each coil combined set # Walsh im_est_walsh_then_recon0 = gs_recon( *[x.squeeze() for x in pcs0[0, idx0, ...]]) im_est_walsh_then_recon1 = gs_recon( *[x.squeeze() for x in pcs0[0, idx1, ...]]) # Inati im_est_inati_then_recon0 = gs_recon( *[x.squeeze() for x in pcs0[1, idx0, ...]]) im_est_inati_then_recon1 = gs_recon( *[x.squeeze() for x in pcs0[1, idx1, ...]]) # view(im_est_walsh_then_recon0) # view(im_est_walsh_then_recon1) view(im_est_inati_then_recon0) view(im_est_inati_then_recon1) rip0 = ripple(im_est_walsh_then_recon0) rip1 = ripple(im_est_walsh_then_recon1) print('walsh then recon: ', np.mean([rip0, rip1])) rip0 = ripple(im_est_inati_then_recon0) rip1 = ripple(im_est_inati_then_recon1) print('inati then recon: ', np.mean([rip0, rip1]))
def test_recon(self): from mr_utils.test_data import GRAPPA # Get the shepp logan phantom im = GRAPPA.phantom_shl() dim = im.shape[0] # Get simple coil sensitivities N = 6 # csm = simple_csm(N,(dim,dim)) csm = GRAPPA.csm() # self.assertTrue(np.allclose(csm,csm_mat)) # Apply csm to image to get coil images coils = csm * im coils_mat = GRAPPA.phantom_ch() self.assertTrue(np.allclose(coils, coils_mat)) # Put each channel into kspace kspace = np.fft.fftshift( np.fft.fft2(np.fft.ifftshift(coils), axes=(1, 2))) kspace_mat = GRAPPA.phantom_ch_k() self.assertTrue(np.allclose(kspace, kspace_mat)) # Undersample by Rx Rx = 2 kspace_d = np.zeros(kspace.shape, dtype='complex') kspace_d[:, ::Rx, :] = kspace[:, ::Rx, :] kspace_d_mat = GRAPPA.phantom_ch_k_u() self.assertTrue(np.allclose(kspace_d, kspace_d_mat)) # Choose center fully samples lines as autocalibration signal (ACS) center_row, pad = int(dim / 2), 8 mask = np.zeros(kspace_d.shape, dtype=bool) mask[:, center_row - pad:center_row + pad, :] = True autocal = kspace[mask].reshape((N, -1, mask.shape[-1])) autocal_mat = GRAPPA.phantom_ch_k_acl() self.assertTrue( np.allclose( np.pad(autocal, ((0, 0), (24, 24), (0, 0)), mode='constant'), autocal_mat)) # Separate the autocalibration region into patches to get source matrix patch_size = (3, 3) S0 = np.zeros((N, (autocal.shape[1] - 2) * (autocal.shape[2] - 2), patch_size[0] * patch_size[1]), dtype='complex') for ii in range(N): S0[ii, :, :] = view_as_windows(autocal[ii, :, :], patch_size).reshape( (S0.shape[1], S0.shape[2])) S0_mat = GRAPPA.S_ch_temp() self.assertTrue(np.allclose(np.conj(S0), S0_mat)) # Remove the unknown values. The remaiming values form source matrix, # S, for each coil S_temp = S0[:, :, [0, 1, 2, 6, 7, 8]] S_temp_mat = GRAPPA.S_ch() self.assertTrue(np.allclose(np.conj(S_temp), S_temp_mat)) S = np.hstack(S_temp[:]) S_mat = GRAPPA.S() self.assertTrue(np.allclose(np.conj(S), S_mat)) # The middle pts form target vector, T, for each coil T = S0[:, :, 4].T T_mat = GRAPPA.T() self.assertTrue(np.allclose(np.conj(T), T_mat)) # Invert S to find weights, W W = np.linalg.pinv(S).dot(T) W_mat = GRAPPA.W() self.assertTrue(np.allclose(np.conj(W), W_mat)) # Now onto the forward problem to fill in the missing lines... # Make patches out of all acquired data (skip the missing lines) S0 = np.zeros((N, int((kspace_d.shape[1] - 2) / Rx) * (kspace_d.shape[2] - 2), patch_size[0] * patch_size[1]), dtype='complex') for ii in range(N): S0[ii, :, :] = view_as_windows(kspace_d[ii, :, :], patch_size, step=(Rx, 1)).reshape( (S0.shape[1], S0.shape[2])) S0_mat = GRAPPA.S_ch_new_temp() self.assertTrue(np.allclose(np.conj(S0), S0_mat)) # Remove the unknown values. The remaiming values form source matrix, # S, for each coil S_new_temp = S0[:, :, [0, 1, 2, 6, 7, 8]] S_new_temp_mat = GRAPPA.S_ch_new() self.assertTrue(np.allclose(np.conj(S_new_temp), S_new_temp_mat)) S_new = np.hstack(S_new_temp[:]) S_new_mat = GRAPPA.S_new() self.assertTrue(np.allclose(np.conj(S_new), S_new_mat)) T_new = S_new.dot(W) T_new_mat = GRAPPA.T_new() self.assertTrue(np.allclose(np.conj(T_new), T_new_mat)) # Back fill in the missing lines to recover the image lines = np.reshape(T_new.T, (N, -1, dim - 2)) lines_mat = GRAPPA.T_ch_new_M() self.assertTrue(np.allclose(lines, lines_mat)) kspace_d[:, 1:-1:Rx, 1:-1] = lines recon = sos(np.fft.fftshift( np.fft.ifft2(np.fft.ifftshift(kspace_d), axes=(1, 2))), axes=0) recon_mat = GRAPPA.Im_Recon() self.assertTrue(np.allclose(recon, recon_mat))