Example #1
0
    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))
Example #2
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)
Example #3
0
    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))
Example #4
0
    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))
Example #5
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
Example #6
0
        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,
Example #7
0
                                                   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
Example #8
0
        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]
Example #10
0
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)
Example #11
0
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]))
Example #12
0
    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))