Beispiel #1
0
    elif trajectory == 'spiral':
        traj = Spiral(FOV=FOV,
                      res=res,
                      oversampling=2,
                      lines_per_shot=2,
                      interleaves=10)
    # traj.plot_trajectory()

    # Non-cartesian kspace
    K = TrajToImage(traj.points, 1000.0 * traj.times, Mxy, r, 50.0)

    # Non-uniform fft
    x0 = traj.points[0].flatten().reshape((-1, 1))
    x1 = traj.points[1].flatten().reshape((-1, 1))
    x0 *= res[0] // 2 / x0.max()
    x1 *= res[1] // 2 / x1.max()
    dcf = (x0**2 + x1**2)**0.5  # density compensation function
    kxky = np.concatenate((x0, x1), axis=1)  # flattened kspace coordinates
    y = K.flatten().reshape((-1, 1))  # flattened kspace measures
    image = nufft_adjoint(y * dcf, kxky, res)  # inverse nufft

    # Show results
    fig, axs = plt.subplots(2, 3, figsize=(10, 10))
    axs[0, 0].imshow(np.abs(K_c[::2, :]))
    axs[0, 1].imshow(np.abs(ktoi(K_c[::2, :])))
    axs[0, 2].imshow(np.angle(ktoi(K_c[::2, :])))
    axs[1, 0].imshow(np.abs(itok(image)))
    axs[1, 1].imshow(np.abs(image))
    axs[1, 2].imshow(np.angle(image))
    plt.show()
Beispiel #2
0
                    np.abs(ktoi(D1.k)[..., 1, 0]).max()
                ])

            for n, nlevel in enumerate(noise_levels):

                # Standard deviation of the noise
                std = nlevel * I_max_r0

                # Generate noise in the image domain
                noise_1 = np.random.normal(0, std, D1.k.shape) \
                        + 1j*np.random.normal(0, std, D1.k.shape)
                noise_2 = np.random.normal(0, std, D2.k.shape) \
                        + 1j*np.random.normal(0, std, D2.k.shape)

                # Noise in the fourier domain
                f_noise_1 = D1.k_msk * itok(noise_1)
                f_noise_2 = D2.k_msk * itok(noise_2)

                # Noisy kspaces
                nH1, nH2 = (H1.k + f_noise_1), (H2.k + f_noise_2)
                nS1, nS2 = (S1.k + f_noise_1), (S2.k + f_noise_2)
                nD1, nD2 = (D1.k + f_noise_1), (D2.k + f_noise_2)

                # kspace to images
                IH1, IH2 = ktoi(nH1), ktoi(nH2)
                IS1, IS2 = ktoi(nS1), ktoi(nS2)
                ID1, ID2 = ktoi(nD1), ktoi(nD2)

                if n == 1:
                    s = np.std(np.real(noise_1 - noise_2).flatten())
                    m = np.max(np.abs(ktoi(D1.k - D2.k).flatten()))
Beispiel #3
0
def get_exact_image(image, epi, phantom, parameters, debug=False):
  """ Generate EXACT images
  """
  # Time-steping parameters
  t     = parameters.t
  dt    = parameters.dt
  n_t   = parameters.time_steps

 # Sequence parameters
  ke    = image.encoding_frequency     # encoding frequency
  M0    = image.M0                     # thermal equilibrium magnetization

  # Regional M0
  M0r = np.zeros([phantom.spins.Nb_samples,1])
  if isinstance(M0,np.ndarray) or isinstance(M0,list):
      M0r[phantom.spins.regions[:,0]] = M0[0]  # inner
      M0r[phantom.spins.regions[:,1]] = M0[1]  # outer
      M0r[phantom.spins.regions[:,2]] = M0[2]  # ventricle
  else:
      M0r[phantom.spins.regions[:,2]] = M0  # ventricle

  # Determine if the image and phantom geometry are 2D or 3D
  di = image.type_dim()                      # image geometric dimension
  dp = phantom.x.shape[-1]                   # phantom (fem) geometric dimension
  dk = np.sum(int(k/k) for k in ke if k!= 0) # Number of encoding directions

  # Output image
  size = np.append(image.resolution, [dk, n_t])
  mask = np.zeros(np.append(image.resolution, n_t), dtype=np.float32)

  # Output kspaces
  k_nsa_1 = kspace(size, image, epi)
  k_mask  = kspace(size, image, epi)

  # Spins positions
  x = phantom.x

  # Check k space bandwidth to avoid folding artifacts
  res, incr_bw, D = check_kspace_bw(image, x)

  # Grid, voxel width, image resolution and number of voxels
  Xf         = D['grid']
  width      = D['voxel_size']
  resolution = D['resolution']
  nr_voxels  = Xf[0].size

  # Check if the number of slices needs to be increased
  # for the generation of the connectivity when generating
  # Slice-Following (SF) images
  # if image.slice_following:
  #     Xf, SL = check_nb_slices(Xf, x, width, res)

  # Connectivity (this is done just once)
  voxel_coords = [X.flatten('F') for X in Xf]
  (s2p, excited_spins) = getConnectivity3(x, voxel_coords, width)
  s2p = np.array(s2p)

  # Spins positions with respect to its containing voxel center
  # Obs: the option -order='F'- is included to make the grid of the
  # Z coordinate at the end of the flattened array
  corners = np.array([Xf[j].flatten('F')[s2p]-0.5*width[j] for j in range(di)]).T
  x_rel = x[:, 0:dp] - corners

  # List of spins inside the excited slice
  # if image.slice_following:
  #     voxel_coords  = [X.flatten('F') for X in D['grid']] # reset voxel coords

  # Magnetization images and spins magnetizations
  m0_image = np.zeros(np.append(resolution, dk), dtype=np.complex128)
  m1_image = np.zeros(np.append(resolution, dk), dtype=np.complex128)

  # Grid to evaluate magnetizations
  X = D['grid']

  # Resolutions and cropping ranges
  ovrs_fac = image.oversampling_factor
  r, c, dr, dc = cropping_ranges(image.resolution, resolution, ovrs_fac)

  # Spins inside the ventricle
  exc_slice  = (x[:,2] < image.center[2] + image.slice_offset + 0.5*image.slice_thickness)
  exc_slice *= (x[:,2] > image.center[2] + image.slice_offset - 0.5*image.slice_thickness)

  # Time stepping
  for time_step in range(n_t):

    # Update time
    t += dt

    # Get displacements in the reference frame and deform mesh
    u = phantom.displacement(time_step)
    reshaped_u = u.vector()

    # Displacement in terms of pixels
    x_new = x_rel #+ reshaped_u - upre
    pixel_u = np.floor(np.divide(x_new, width))
    subpixel_u = x_new - np.multiply(pixel_u, width)

    # Change spins connectivity according to the new positions
    update_s2p(s2p, pixel_u, resolution)

    # Update pixel-to-spins connectivity
    # if image.slice_following:
    #   p2s = update_p2s(s2p-SL, excited_spins, nr_voxels)
    # else:
    #   p2s = update_p2s(s2p, excited_spins, nr_voxels)
    p2s = update_p2s(s2p, excited_spins, nr_voxels)

    # Update relative spins positions
    x_rel[:,:] = subpixel_u

    # Updated spins positions
    x_upd = x

    # Get magnetization on each spin
    mags = EXACT_magnetizations(M0r, ke[0:dk], reshaped_u[:,0:dk])
    for i in range(len(mags)):
        mags[i][(~exc_slice),:] = 0
    mags[-1][~phantom.spins.regions[:,2]] = 0

    # # Debug
    # if MPI_rank==0:
    #     from PyMRStrain.IO import write_vtk
    #     from PyMRStrain.Math import wrap
    #     S2P = Function(u.spins, dim=1)  # spins-to-pixel connectivity
    #     EXC = Function(u.spins, dim=1)  # excited slice (spins)
    #     rot = Function(u.spins, dim=1)
    #     theta = np.arctan(x[:,1]/x[:,0])
    #     rot.vector()[:] = wrap(theta.reshape((-1,1)), np.pi/8)
    #     EXC.vector()[exc_slice] = 1
    #     S2P.vector()[excited_spins] = s2p.reshape((-1,1))
    #     write_vtk([u,S2P,EXC,rot], path='output/Normal_{:04d}.vtu'.format(time_step), name=['displacement','s2p_connectivity','slice','rot'])

    # Fill images
    # Obs: the option -order='F'- is included because the grid was flattened
    # using this option. Therefore the reshape must be performed accordingly
    (I, m) = get_images(mags, x_upd, voxel_coords, width, p2s)
    if debug:
        MPI_print('Time step {:d}. Average nb. of spins inside a voxel: {:.0f}'.format(time_step, MPI_size*0.5*(m.max()-m.min())))
    else:
        MPI_print('Time step {:d}'.format(time_step))

    # Gather results
    m0_image[...] = gather_image(I[0].reshape(m0_image.shape,order='F'))
    m1_image[...] = gather_image(I[1].reshape(m1_image.shape,order='F'))

    # Iterates over slices
    for slice in range(resolution[2]):

      # Complex magnetization data
      for enc_dir in range(dk):

        # Magnetization expressions
        tmp0 = m0_image[...,slice,enc_dir]
        tmp1 = m1_image[...,slice,enc_dir]

        # Uncorrected kspaces
        k0 = restore_resolution(itok(tmp0), r, c, dr, dc, enc_dir, image.resolution, ovrs_fac)
        k1 = restore_resolution(itok(tmp1), r, c, dr, dc, enc_dir, image.resolution, ovrs_fac)

        # import matplotlib.pyplot as plt
        # from PyMRStrain.Math import ktoi
        # fig,ax = plt.subplots(1,2)
        # ax[0].imshow(np.angle(ktoi(itok(tmp0)[1::ovrs_fac,:])))
        # ax[1].imshow(np.angle(ktoi(k0)))
        # plt.show(block=False)
        # plt.pause(5)

        # kspace resizing and epi artifacts generation
        delta_ph = image.FOV[m_dirs[enc_dir][1]]/image.phase_profiles
        k_nsa_1.gen_to_acq(k0, delta_ph, m_dirs[enc_dir], slice, enc_dir, time_step)
        k_mask.gen_to_acq(k1, delta_ph, m_dirs[enc_dir], slice, enc_dir, time_step)

  return k_nsa_1, k_mask