np.save('datas/' + title + '.npy', save_pynufft) # Plot K-space # kx = np.real(y_pynufft) # ky = np.imag(y_pynufft) # plt.figure() # plt.plot(kx,ky, 'w.') # ax = plt.gca() # ax.set_facecolor('k') # plt.title('K-space Pynufft') # plt.show() if adj == True: # backward test print('Self-adjoint Test...') if gpu == True: gx2 = NufftObj.adjoint(gy) img_reconstruct_ = gx2.get() else: img_reconstruct_ = NufftObj.adjoint(y_pynufft) # print(np.abs(img_reconstruct_)/np.max(np.abs(img_reconstruct_))) img_reconstruct = np.abs(img_reconstruct_) / np.max( np.abs(img_reconstruct_)) img_reconstruct = img_reconstruct.astype(np.float64) # plt.figure() # plt.suptitle('Comparaison original/selfadjoint') # plt.subplot(121) # plt.imshow(image, cmap='gray') # plt.subplot(122)
# nufftObj.x_Nd = nufftObj.thr.to_device(Il[:3].astype(dtype)) # gx = nufftObj.thr.copy_array(nufftObj.x_Nd) #x = numpy.einsum('cxyz -> xyzc', Il[0:3]).copy() # coil must be the last dimension; Assume it is a C-order array gy = nufftObj.forward(x) #y = np.copy(gy.get()) # Checking the shape of the kspace #print("K-space shapes: ", y.shape) # Computing the backward pass gx2 = nufftObj.adjoint(gy) rec_Il = gx2.get() #np.copy(gx.get()) print(rec_Il.shape) # Plotting the results import matplotlib.pyplot matplotlib.pyplot.subplot(2,3,1) matplotlib.pyplot.imshow(x[:,:,64,0].real) matplotlib.pyplot.title('input_image (64-th slice, first coil)') matplotlib.pyplot.subplot(2,3,2) matplotlib.pyplot.imshow(x[:,:,64,1].real) matplotlib.pyplot.title('input_image (64-th slice, second coil)') matplotlib.pyplot.subplot(2,3,3) matplotlib.pyplot.imshow(x[:,:,64,2].real) matplotlib.pyplot.title('input_image (64-th slice, third coil)')
class NUFFT(Singleton): """ GPU implementation of N-D non uniform Fast Fourrier Transform class. Attributes ---------- samples: np.ndarray the mask samples in the Fourier domain. shape: tuple of int shape of the image (necessarly a square/cubic matrix). nufftObj: The pynufft object depending on the required computational platform platform: string, 'opencl' or 'cuda' string indicating which hardware platform will be used to compute the NUFFT Kd: int or tuple int or tuple indicating the size of the frequency grid, for regridding. if int, will be evaluated to (Kd,)*nb_dim of the image Jd: int or tuple Size of the interpolator kernel. If int, will be evaluated to (Jd,)*dims image n_coils: int default 1 Number of coils used to acquire the signal in case of multiarray receiver coils acquisition. If n_coils > 1, please organize data as n_coils X data_per_coil """ numOfInstances = 0 def __init__(self, samples, shape, platform='cuda', Kd=None, Jd=None, n_coils=1, verbosity=0): """ Initilize the 'NUFFT' class. Parameters ---------- samples: np.ndarray the mask samples in the Fourier domain. shape: tuple of int shape of the image (necessarly a square/cubic matrix). platform: string, 'cpu', 'opencl' or 'cuda' string indicating which hardware platform will be used to compute the NUFFT Kd: int or tuple int or tuple indicating the size of the frequency grid, for regridding. If int, will be evaluated to (Kd,)*nb_dim of the image Jd: int or tuple Size of the interpolator kernel. If int, will be evaluated to (Jd,)*dims image n_coils: int Number of coils used to acquire the signal in case of multiarray receiver coils acquisition """ if (n_coils < 1) or (type(n_coils) is not int): raise ValueError('The number of coils should be an integer >= 1') if not pynufft_available: raise ValueError('PyNUFFT Package is not installed, please ' 'consider using `gpuNUFFT` or install the ' 'PyNUFFT package') self.nb_coils = n_coils self.shape = shape self.platform = platform self.samples = samples * (2 * np.pi) # Pynufft use samples in # [-pi, pi[ instead of [-0.5, 0.5[ self.dim = samples.shape[1] # number of dimensions of the image if type(Kd) == int: self.Kd = (Kd, ) * self.dim elif type(Kd) == tuple: self.Kd = Kd elif Kd is None: # Preferential option self.Kd = tuple([2 * ix for ix in shape]) if type(Jd) == int: self.Jd = (Jd, ) * self.dim elif type(Jd) == tuple: self.Jd = Jd elif Jd is None: # Preferential option self.Jd = (5, ) * self.dim for (i, s) in enumerate(shape): assert (self.shape[i] <= self.Kd[i]), 'size of frequency grid' + \ 'must be greater or equal ' \ 'than the image size' if verbosity > 0: print('Creating the NUFFT object...') if self.platform == 'opencl': warn('Attemping to use OpenCL plateform. Make sure to ' 'have all the dependecies installed') Singleton.__init__(self) if self.getNumInstances() > 1: warn('You have created more than one NUFFT object. ' 'This could cause memory leaks') self.nufftObj = NUFFT_hsa(API='ocl', platform_number=None, device_number=None, verbosity=verbosity) self.nufftObj.plan( om=self.samples, Nd=self.shape, Kd=self.Kd, Jd=self.Jd, batch=1, # TODO self.nb_coils, ft_axes=tuple(range(samples.shape[1])), radix=None) elif self.platform == 'cuda': warn('Attemping to use Cuda plateform. Make sure to ' 'have all the dependecies installed and ' 'to create only one instance of NUFFT GPU') Singleton.__init__(self) if self.getNumInstances() > 1: warn('You have created more than one NUFFT object. ' 'This could cause memory leaks') self.nufftObj = NUFFT_hsa(API='cuda', platform_number=None, device_number=None, verbosity=verbosity) self.nufftObj.plan( om=self.samples, Nd=self.shape, Kd=self.Kd, Jd=self.Jd, batch=1, # TODO self.nb_coils, ft_axes=tuple(range(samples.shape[1])), radix=None) else: raise ValueError('Wrong type of platform. Platform must be' '\'opencl\' or \'cuda\'') def __del__(self): # This is an important desctructor to ensure that the device memory # is freed # TODO this is still not freeing the memory right on device. # Mostly issue with reikna library. # Refer : https://github.com/fjarri/reikna/issues/53 if self.platform == 'opencl' or self.platform == 'cuda': self.nufftObj.release() def op(self, img): """ This method calculates the masked non-cartesian Fourier transform of a 3-D image. Parameters ---------- img: np.ndarray input 3D array with the same shape as shape. Returns ------- x: np.ndarray masked Fourier transform of the input image. """ if self.nb_coils == 1: dtype = np.complex64 # Send data to the mCPU/GPU platform self.nufftObj.x_Nd = self.nufftObj.thr.to_device(img.astype(dtype)) gx = self.nufftObj.thr.copy_array(self.nufftObj.x_Nd) # Forward operator of the NUFFT gy = self.nufftObj.forward(gx) y = np.squeeze(gy.get()) else: dtype = np.complex64 # Send data to the mCPU/GPU platform y = [] for ch in range(self.nb_coils): self.nufftObj.x_Nd = self.nufftObj.thr.to_device( np.copy(img[ch]).astype(dtype)) gx = self.nufftObj.thr.copy_array(self.nufftObj.x_Nd) # Forward operator of the NUFFT gy = self.nufftObj.forward(gx) y.append(np.squeeze(gy.get())) y = np.asarray(y) return y * 1.0 / np.sqrt(np.prod(self.Kd)) def adj_op(self, x): """ This method calculates inverse masked non-uniform Fourier transform of a 1-D coefficients array. Parameters ---------- x: np.ndarray masked non-uniform Fourier transform 1D data. Returns ------- img: np.ndarray inverse 3D discrete Fourier transform of the input coefficients. """ if self.nb_coils == 1: dtype = np.complex64 cuda_array = self.nufftObj.thr.to_device(x.astype(dtype)) gx = self.nufftObj.adjoint(cuda_array) img = np.squeeze(gx.get()) else: dtype = np.complex64 img = [] for ch in range(self.nb_coils): cuda_array = self.nufftObj.thr.to_device( np.copy(x[ch]).astype(dtype)) gx = self.nufftObj.adjoint(cuda_array) img.append(gx.get()) img = np.asarray(np.squeeze(img)) return img * np.sqrt(np.prod(self.Kd))