def test_dki_errors(): # first error of DKI module is if a unknown fit method is given assert_raises(ValueError, dki.DiffusionKurtosisModel, gtab_2s, fit_method="JOANA") # second error of DKI module is if a min_signal is defined as negative assert_raises(ValueError, dki.DiffusionKurtosisModel, gtab_2s, min_signal=-1) # try case with correct min_signal dkiM = dki.DiffusionKurtosisModel(gtab_2s, min_signal=1) dkiF = dkiM.fit(DWI) assert_array_almost_equal(dkiF.model_params, multi_params) # third error is if a given mask do not have same shape as data dkiM = dki.DiffusionKurtosisModel(gtab_2s) # test a correct mask dkiF = dkiM.fit(DWI) mask_correct = dkiF.fa > 0 mask_correct[1, 1] = False multi_params[1, 1] = np.zeros(27) mask_not_correct = np.array([[True, True, False], [True, False, False]]) dkiF = dkiM.fit(DWI, mask=mask_correct) assert_array_almost_equal(dkiF.model_params, multi_params) # test a incorrect mask assert_raises(ValueError, dkiM.fit, DWI, mask=mask_not_correct) # error if data with only one non zero b-value is given assert_raises(ValueError, dki.DiffusionKurtosisModel, gtab)
def test_kurtosis_fa(): # KFA = sqrt(4/5) if kurtosis is non-zero only in one direction mevals = np.array([[0.002, 0, 0], [0.003, 0, 0]]) angles = [(45, 0), (45, 0)] fie = 0.5 frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) dkiF.kfa assert_almost_equal(dkiF.kfa, np.sqrt(4 / 5)) # KFA = sqrt(13/5) for systems of two tensors with same AD and RD values # See appendix of Gleen et al., 2015 Quantitative assessment of diffusional # kurtosis anisotropy. NMR Biomed 28; 448-459. doi:10.1002/nbm.3271 mevals = np.array([[0.003, 0.001, 0.001], [0.003, 0.001, 0.001]]) angles = [(40, -10), (-45, 10)] fie = 0.5 frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) dkiF.kfa assert_almost_equal(dkiF.kfa, np.sqrt(13 / 15)) # KFA = 0 if MKT = 0 mevals = np.array([[0.003, 0.001, 0.001], [0.003, 0.001, 0.001]]) angles = [(40, -10), (40, -10)] fie = 0.5 frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) dkiF.kfa assert_almost_equal(dkiF.kfa, 0)
def fit(self): """ Fits a dki model to the data Standard DTI measures (FA,MD,RD,AD) are calculated from the DKI model, accounting for additional variance. DKI measures of MK,RK,AK are computed from the DKI model. Residual image has the same dimensions as the original input image. Calculated as |Avg(B0_volumes)-predicted_image| Noise is equal to the stdev across volumes of the residual image, and SNR is Avg(B0_volumes)/Noise, removing NaNs. """ data = self.data.get_data() #Generate the dk model print("Generating the models.") dkimodel = dki.DiffusionKurtosisModel(self.gradient_table) print("Fitting the data.") self.dki_fitted = dkimodel.fit(data) #Generate the lower-triangular dataset print("Generating the kurtosis tensor data.") self.out_dti = nib.nifti1.Nifti1Image(self.dki_fitted.lower_triangular(), self.data.get_affine()) self.out_dki = nib.nifti1.Nifti1Image(self.dki_fitted.kt, self.data.get_affine()) #Generate the residuals if self.out_residual_path != None or self.out_noise_path != None or self.out_snr_path != None: print("Estimating input data.") estimate_data = self.dki_fitted.predict(self.gradient_table, S0=self.b0_average) print("Calculating residuals.") residuals = np.absolute(data - estimate_data) noise = np.std(residuals, axis=3) snr = np.nan_to_num(self.b0_average / noise) self.out_residual = nib.nifti1.Nifti1Image(residuals.astype(np.float32), self.data.get_affine()) self.out_noise = nib.nifti1.Nifti1Image(noise.astype(np.float32), self.data.get_affine()) self.out_snr = nib.nifti1.Nifti1Image(snr.astype(np.float32), self.data.get_affine())
def DKE_by_slice(data, gtab, slices='all'): """ Fits the DKE model by slice to decrease memory requirements Do all slices, or array subset thereof """ import dipy.reconst.dki as dki import numpy as np print('Creating diffusion kurtosis model') dkimodel = dki.DiffusionKurtosisModel(gtab) n_contrasts = 3 #number of contrasts that we are going to have output from the dki model out_data = np.zeros( list(np.shape(data)[0:3]) + [n_contrasts]) #replace the diff dir axis with our own for the results if slices is 'all': slices = np.arange(0, np.shape(data)[2]) print("Performing diffusion kurtosis estimation by slice: "), #lets loop across the z dimension - index 2 for zslice in slices: print(zslice), slice_d = data[:, :, zslice, :] dkifit = dkimodel.fit(slice_d) MK = dkifit.mk(0, 3) AK = dkifit.ak(0, 3) RK = dkifit.rk(0, 3) #assign to our out_data out_data[:, :, zslice, 0] = MK out_data[:, :, zslice, 1] = AK out_data[:, :, zslice, 2] = RK print("") return out_data
def fit_dki(dwi, blur=False): """Fit a DKI model to a DWI, applying a mask if provided. Parameters --------- dwi : DiffusionWeightedImage DWI data to fit to the model. blur : bool, optional True if the image should be blurred before the model fit. Returns ------- dwifit : DiffusionKurtosisFit A fit from which parameter maps can be generated """ dkimodel = dki.DiffusionKurtosisModel(dwi.gtab) data = dwi.get_image() if blur: data = ndi.gaussian_filter(data, [0.5, 0.5, 0, 0]) try: mask = dwi.mask except AttributeError: mask = np.ones(data.shape[:3]) return dkimodel.fit(data, mask)
def test_dki_predict(): dkiM = dki.DiffusionKurtosisModel(gtab_2s) pred = dkiM.predict(crossing_ref, S0=100) assert_array_almost_equal(pred, signal_cross) # just to check that it works with more than one voxel: pred_multi = dkiM.predict(multi_params, S0=100) assert_array_almost_equal(pred_multi, DWI) # Check that it works with more than one voxel, and with a different S0 # in each voxel: pred_multi = dkiM.predict(multi_params, S0=100*np.ones(pred_multi.shape[:3])) assert_array_almost_equal(pred_multi, DWI) # check the function predict of the DiffusionKurtosisFit object dkiF = dkiM.fit(DWI) pred_multi = dkiF.predict(gtab_2s, S0=100) assert_array_almost_equal(pred_multi, DWI) dkiF = dkiM.fit(pred_multi) pred_from_fit = dkiF.predict(dkiM.gtab, S0=100) assert_array_almost_equal(pred_from_fit, DWI) # Test the module function: pred = dki.dki_prediction(crossing_ref, gtab_2s, S0=100) assert_array_almost_equal(pred, signal_cross) # Test the module function with S0 volume: pred = dki.dki_prediction(multi_params, gtab_2s, S0=100 * np.ones(multi_params.shape[:3])) assert_array_almost_equal(pred, DWI)
def test_split_dki_param(): dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="OLS") dkiF = dkiM.fit(DWI) evals, evecs, kt = dki.split_dki_param(dkiF.model_params) assert_array_almost_equal(evals, dkiF.evals) assert_array_almost_equal(evecs, dkiF.evecs) assert_array_almost_equal(kt, dkiF.kt)
def test_multi_voxel_kurtosis_maximum(): # Multi-voxel simulations parameters FIE = np.array([[[0.30, 0.32], [0.74, 0.51]], [[0.47, 0.21], [0.80, 0.63]]]) RDI = np.zeros((2, 2, 2)) ADI = np.array([[[1e-3, 1.3e-3], [0.8e-3, 1e-3]], [[0.9e-3, 0.99e-3], [0.89e-3, 1.1e-3]]]) ADE = np.array([[[2.2e-3, 2.3e-3], [2.8e-3, 2.1e-3]], [[1.9e-3, 2.5e-3], [1.89e-3, 2.1e-3]]]) Tor = np.array([[[2.6, 2.4], [2.8, 2.1]], [[2.9, 2.5], [2.7, 2.3]]]) RDE = ADE / Tor # prepare simulation: DWIsim = np.zeros((2, 2, 2, gtab_2s.bvals.size)) for i in range(2): for j in range(2): for k in range(2): ADi = ADI[i, j, k] RDi = RDI[i, j, k] ADe = ADE[i, j, k] RDe = RDE[i, j, k] fie = FIE[i, j, k] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie * 100, (1 - fie) * 100] theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) DWIsim[i, j, k, :] = signal # Ground truth Maximum kurtosis RD = FIE * RDI + (1 - FIE) * RDE RK = 3 * FIE * (1 - FIE) * ((RDI - RDE) / RD)**2 # prepare inputs dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(DWIsim) sphere = get_sphere('symmetric724') # TEST - when no sphere is given k_max = dki.kurtosis_maximum(dkiF.model_params) assert_almost_equal(k_max, RK, decimal=4) # TEST - when sphere is given k_max = dki.kurtosis_maximum(dkiF.model_params, sphere) assert_almost_equal(k_max, RK, decimal=4) # TEST - when mask is given mask = np.ones((2, 2, 2), dtype='bool') mask[1, 1, 1] = 0 RK[1, 1, 1] = 0 k_max = dki.kurtosis_maximum(dkiF.model_params, mask=mask) assert_almost_equal(k_max, RK, decimal=4)
def test_dki_predict(): dkiM = dki.DiffusionKurtosisModel(gtab_2s) pred = dkiM.predict(crossing_ref, S0=100) assert_array_almost_equal(pred, signal_cross) # just to check that it works with more than one voxel: pred_multi = dkiM.predict(multi_params, S0=100) assert_array_almost_equal(pred_multi, DWI)
def test_dki_fits(): """ DKI fits are tested on noise free crossing fiber simulates """ # OLS fitting dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="OLS") dkiF = dkiM.fit(signal_cross) assert_array_almost_equal(dkiF.model_params, crossing_ref) # WLS fitting dki_wlsM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dki_wlsF = dki_wlsM.fit(signal_cross) assert_array_almost_equal(dki_wlsF.model_params, crossing_ref) # testing multi-voxels dkiF_multi = dkiM.fit(DWI) assert_array_almost_equal(dkiF_multi.model_params, multi_params) dkiF_multi = dki_wlsM.fit(DWI) assert_array_almost_equal(dkiF_multi.model_params, multi_params)
def test_dki_predict(): dkiM = dki.DiffusionKurtosisModel(gtab_2s) pred = dkiM.predict(crossing_ref, S0=100) assert_array_almost_equal(pred, signal_cross) # just to check that it works with more than one voxel: pred_multi = dkiM.predict(multi_params, S0=100) assert_array_almost_equal(pred_multi, DWI) # check the function predict of the DiffusionKurtosisFit object dkiF = dkiM.fit(DWI) pred_multi = dkiF.predict(gtab, S0=100) assert_array_almost_equal(pred_multi, DWI[:, :, :, :65])
def test_single_voxel_DKI_stats(): # tests if AK and RK are equal to expected values for a single fiber # simulate randomly oriented ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # Reference values AD = fie * ADi + (1 - fie) * ADe AK = 3 * fie * (1 - fie) * ((ADi - ADe) / AD)**2 RD = fie * RDi + (1 - fie) * RDe RK = 3 * fie * (1 - fie) * ((RDi - RDe) / RD)**2 ref_vals = np.array([AD, AK, RD, RK]) # simulate fiber randomly oriented theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) evals, evecs = decompose_tensor(from_lower_triangular(dt)) dki_par = np.concatenate((evals, evecs[0], evecs[1], evecs[2], kt), axis=0) # Estimates using dki functions ADe1 = dti.axial_diffusivity(evals) RDe1 = dti.radial_diffusivity(evals) AKe1 = axial_kurtosis(dki_par) RKe1 = radial_kurtosis(dki_par) e1_vals = np.array([ADe1, AKe1, RDe1, RKe1]) assert_array_almost_equal(e1_vals, ref_vals) # Estimates using the kurtosis class object dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) e2_vals = np.array([dkiF.ad, dkiF.ak(), dkiF.rd, dkiF.rk()]) assert_array_almost_equal(e2_vals, ref_vals) # test MK (note this test correspond to the MK singularity L2==L3) MK_as = dkiF.mk() sph = Sphere(xyz=gtab.bvecs[gtab.bvals > 0]) MK_nm = np.mean(dkiF.akc(sph)) assert_array_almost_equal(MK_as, MK_nm, decimal=1)
def test_compare_MK_method(): # tests if analytical solution of MK is equal to the average of directional # kurtosis sampled from a sphere # DKI Model fitting dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal_cross) # MK analytical solution MK_as = dkiF.mk(None, None, analytical=True) # MK numerical method MK_nm = dkiF.mk(None, None, analytical=False) assert_array_almost_equal(MK_as, MK_nm, decimal=3)
def test_compare_RK_methods(): # tests if analytical solution of RK is equal to the perpendicular kurtosis # relative to the first diffusion axis # DKI Model fitting dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal_cross) # RK analytical solution RK_as = dkiF.rk(analytical=True) # RK numerical method RK_nm = dkiF.rk(analytical=False) assert_array_almost_equal(RK_as, RK_nm)
def test_MK_singularities(): # To test MK in case that analytical solution was a singularity not covered # by other tests dkiM = dki.DiffusionKurtosisModel(gtab_2s) # test singularity L1 == L2 - this is the case of a prolate diffusion # tensor for crossing fibers at 90 degrees angles_all = np.array([[(90, 0), (90, 0), (0, 0), (0, 0)], [(89.9, 0), (89.9, 0), (0, 0), (0, 0)]]) for angles_90 in angles_all: s_90, dt_90, kt_90 = multi_tensor_dki(gtab_2s, mevals_cross, S0=100, angles=angles_90, fractions=frac_cross, snr=None) dkiF = dkiM.fit(s_90) MK = dkiF.mk() sph = Sphere(xyz=gtab.bvecs[gtab.bvals > 0]) MK_nm = np.mean(dkiF.akc(sph)) assert_almost_equal(MK, MK_nm, decimal=2) # test singularity L1 == L3 and L1 != L2 # since L1 is defined as the larger eigenvalue and L3 the smallest # eigenvalue, this singularity teoretically will never be called, # because for L1 == L3, L2 have also to be = L1 and L2. # Nevertheless, I decided to include this test since this singularity # is revelant for cases that eigenvalues are not ordered # artificially revert the eigenvalue and eigenvector order dki_params = dkiF.model_params.copy() dki_params[1] = dkiF.model_params[2] dki_params[2] = dkiF.model_params[1] dki_params[4] = dkiF.model_params[5] dki_params[5] = dkiF.model_params[4] dki_params[7] = dkiF.model_params[8] dki_params[8] = dkiF.model_params[7] dki_params[10] = dkiF.model_params[11] dki_params[11] = dkiF.model_params[10] MK = dki.mean_kurtosis(dki_params) MK_nm = np.mean(dki.apparent_kurtosis_coef(dki_params, sph)) assert_almost_equal(MK, MK_nm, decimal=2)
def test_compare_MK_method(): # tests if analytical solution of MK is equal to the average of directional # kurtosis sampled from a sphere # DKI Model fitting dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal_cross) # MK analytical solution MK_as = dkiF.mk() # MK numerical method sph = Sphere(xyz=gtab.bvecs[gtab.bvals > 0]) MK_nm = np.mean(dki.apparent_kurtosis_coef(dkiF.model_params, sph), axis=-1) assert_array_almost_equal(MK_as, MK_nm, decimal=1)
def test_compare_RK_methods(): # tests if analytical solution of RK is equal to the perpendicular kurtosis # relative to the first diffusion axis # DKI Model fitting dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal_cross) # MK analytical solution RK_as = dkiF.rk() # MK numerical method evecs = dkiF.evecs p_dir = perpendicular_directions(evecs[:, 0], num=30, half=True) ver = Sphere(xyz=p_dir) RK_nm = np.mean(dki.apparent_kurtosis_coef(dkiF.model_params, ver), axis=-1) assert_array_almost_equal(RK_as, RK_nm)
def fit_dki(data_files, bval_files, bvec_files, mask=None, min_kurtosis=-1, max_kurtosis=3, out_dir=None, b0_threshold=0): """ Fit the DKI model, save files with derived maps Parameters ---------- data_files : str or list Files containing DWI data. If this is a str, that's the full path to a single file. If it's a list, each entry is a full path. bval_files : str or list Equivalent to `data_files`. bvec_files : str or list Equivalent to `data_files`. mask : ndarray, optional Binary mask, set to True or 1 in voxels to be processed. Default: Process all voxels. min_kurtosis : float, optional The minimal plausible value of kurtosis. Default: -1. max_kurtosis : float, optional The maximal plausible value of kurtosis. Default: 3. out_dir : str, optional A full path to a directory to store the maps that get computed. Default: maps get stored in the same directory as the last DWI file in `data_files`. b0_threshold : float Returns ------- file_paths : a dict with the derived maps that were computed and full-paths to the files containing these maps. Note ---- Maps that are calculated: FA, MD, AD, RD, MK, AK, RK """ img, data, gtab, mask = ut.prepare_data(data_files, bval_files, bvec_files, mask=mask, b0_threshold=b0_threshold) dkimodel = dki.DiffusionKurtosisModel(gtab) dkifit = dkimodel.fit(data, mask=mask) FA = dkifit.fa MD = dkifit.md AD = dkifit.ad RD = dkifit.rd MK = dkifit.mk(min_kurtosis, max_kurtosis) AK = dkifit.ak(min_kurtosis, max_kurtosis) RK = dkifit.rk(min_kurtosis, max_kurtosis) params = dkifit.model_params maps = [FA, MD, AD, RD, MK, AK, RK, params] names = ['FA', 'MD', 'AD', 'RD', 'MK', 'AK', 'RK', 'params'] if out_dir is None: if isinstance(data_files, list): out_dir = op.join(op.split(data_files[0])[0], 'dki') else: out_dir = op.join(op.split(data_files)[0], 'dki') if not op.exists(out_dir): os.makedirs(out_dir) aff = img.affine file_paths = {} for m, n in zip(maps, names): file_paths[n] = op.join(out_dir, 'dki_%s.nii.gz' % n) nib.save(nib.Nifti1Image(m, aff), file_paths[n]) return file_paths
def dkifit(dwi_file, bvec_file, bval_file, mask_file, out, min_kurtosis=-0.42, max_kurtosis=10, micro=False): """ The diffusion kurtosis model is an expansion of the diffusion tensor model (see Reconstruction of the diffusion signal with the Tensor model). In addition to the diffusion tensor (DT), the diffusion kurtosis model quantifies the degree to which water diffusion in biological tissues is non-Gaussian using the kurtosis tensor (KT) [Jensen2005]. Measurements of non-Gaussian diffusion from the diffusion kurtosis model are of interest because they can be used to charaterize tissue microstructural heterogeneity [Jensen2010] and to derive concrete biophysical parameters, such as the density of axonal fibres and diffusion tortuosity [Fieremans2011]. Theoretically, computing classical scalar measures from DTI and DKI should be analogous. However, according to recent studies, the diffusion statistics from the kurtosis model are expected to have better accuracy [Veraar2011], [NetoHe2012]. Kurtosis measures are susceptible to high amplitude outliers. The impact of high amplitude kurtosis outliers can be removed by introducing as an optional input the extremes of the typical values of kurtosis. Here these are assumed to be on the range between -0.42 and 10. This code uses dipy. Parameters ---------- dwi_file: str (mandatory) Diffusion weighted image data file (can be multi-shell). A 4D series of data volumes. bvec_file: str (mandatory) b vectors file. Gradient directions. An ASCII text file containing a list of gradient directions applied during diffusion weighted volumes. The order of entries in this file must match the order of volumes in the input data series. bval_file: str (mandatory) b values file. An ASCII text file containing a list of b values applied during each volume acquisition. The order of entries in this file must match the order of volumes in the input data and entries in the gradient directions text file. mask_file: str (mandatory) Brain binary mask file (i.e. from BET). A single binarized volume in diffusion space containing ones inside the brain and zeros outside the brain. out: str (mandatory) User specifies a basename that will be used to name the outputs. min_kurtosis: float, default -0.42 To keep kurtosis values within a plausible biophysical range, mean kurtosis values that are smaller than `min_kurtosis` are replaced with `min_kurtosis`. max_kurtosis: float, default 10 To keep kurtosis values within a plausible biophysical range, mean kurtosis values that are larger than `max_kurtosis` are replaced with `max_kurtosis`. micro: bool, default False If set, estimate yhe DKI based microstructural model. Returns ------- fa_file: str the fractional anisotropy (FA). md_file: str the mean diffusivity (MD). ad_file: str the axial diffusivity (AD). rd_file: str the radial diffusivity (RD). ci_file: str the lineraity, planarity and sphericity Westion shapes. mk_file: str the non-Gaussian measures of mean kurtosis (MK). ak_file: str the axial kurtosis (AK). rk_file: str the radial kurtosis (RK) dkimask_file: str well-aligned fiber mask. dkiawf_file: str the Axonal water fraction (AWF). dkitortuosity_file: str the tortuosity. """ # Load the image dwi_image = nibabel.load(dwi_file) mask_image = nibabel.load(mask_file) # Smooth the data data = dwi_image.get_data() fwhm = 1.25 gauss_std = fwhm / numpy.sqrt(8 * numpy.log(2)) data_smooth = numpy.zeros(data.shape) for indx in range(data.shape[-1]): data_smooth[..., indx] = gaussian_filter(data[..., indx], sigma=gauss_std) # Load the bvalues and bvectors bvals, bvecs = read_bvals_bvecs(bval_file, bvec_file) gtab = gradient_table(bvals, bvecs) # Create/fit the model model = dki.DiffusionKurtosisModel(gtab, fit_method="WLS") fit = model.fit(data_smooth, mask=mask_image.get_data()) # Get the tensor part scalars kt_image = nibabel.Nifti1Image(fit.kt, affine=dwi_image.affine) dkikt_file = os.path.join(out, "dki_kt.nii.gz") nibabel.save(kt_image, dkikt_file) fa_image = nibabel.Nifti1Image(fit.fa, affine=dwi_image.affine) dkifa_file = os.path.join(out, "dki_fa.nii.gz") nibabel.save(fa_image, dkifa_file) md_image = nibabel.Nifti1Image(fit.md, affine=dwi_image.affine) dkimd_file = os.path.join(out, "dki_md.nii.gz") nibabel.save(md_image, dkimd_file) ad_image = nibabel.Nifti1Image(fit.ad, affine=dwi_image.affine) dkiad_file = os.path.join(out, "dki_ad.nii.gz") nibabel.save(ad_image, dkiad_file) rd_image = nibabel.Nifti1Image(fit.rd, affine=dwi_image.affine) dkird_file = os.path.join(out, "dki_rd.nii.gz") nibabel.save(rd_image, dkird_file) cl_image = nibabel.Nifti1Image(fit.linearity, affine=dwi_image.affine) dkicl_file = os.path.join(out, "dki_cl.nii.gz") nibabel.save(cl_image, dkicl_file) cp_image = nibabel.Nifti1Image(fit.planarity, affine=dwi_image.affine) dkicp_file = os.path.join(out, "dki_cp.nii.gz") nibabel.save(cp_image, dkicp_file) cs_image = nibabel.Nifti1Image(fit.sphericity, affine=dwi_image.affine) dkics_file = os.path.join(out, "dki_cs.nii.gz") nibabel.save(cs_image, dkics_file) # Get the kutosis part scalars mk_image = nibabel.Nifti1Image(fit.mk(min_kurtosis, max_kurtosis), affine=dwi_image.affine) dkimk_file = os.path.join(out, "dki_mk.nii.gz") nibabel.save(mk_image, dkimk_file) ak_image = nibabel.Nifti1Image(fit.ak(min_kurtosis, max_kurtosis), affine=dwi_image.affine) dkiak_file = os.path.join(out, "dki_ak.nii.gz") nibabel.save(ak_image, dkiak_file) rk_image = nibabel.Nifti1Image(fit.rk(min_kurtosis, max_kurtosis), affine=dwi_image.affine) dkirk_file = os.path.join(out, "dki_rk.nii.gz") nibabel.save(rk_image, dkirk_file) # Estimate the microstructural model if requested dkimask_file, dkiawf_file, dkitortuosity_file = None, None, None if micro: # Create a white matter mask based on the westin shapes # Fieremans et al. [Fieremans2011] well_aligned_mask = numpy.ones(dwi_image.shape[:-1], dtype="bool") cl = fit.linearity.copy() well_aligned_mask[cl < 0.4] = False cp = fit.planarity.copy() well_aligned_mask[cp > 0.2] = False cs = fit.sphericity.copy() well_aligned_mask[cs > 0.35] = False # Removing nan associated with background voxels well_aligned_mask[numpy.isnan(cl)] = False well_aligned_mask[numpy.isnan(cp)] = False well_aligned_mask[numpy.isnan(cs)] = False # Save mask mask_image = nibabel.Nifti1Image(well_aligned_mask.astype(int), affine=dwi_image.affine) dkimask_file = os.path.join(out, "dki_mask.nii.gz") nibabel.save(mask_image, dkimask_file) # Create/fit the model micro_model = dki_micro.KurtosisMicrostructureModel(gtab) micro_fit = micro_model.fit(data_smooth, mask=well_aligned_mask) # Get scalars awf_image = nibabel.Nifti1Image(micro_fit.awf, affine=dwi_image.affine) dkiawf_file = os.path.join(out, "dki_awf.nii.gz") nibabel.save(awf_image, dkiawf_file) tortuosity_image = nibabel.Nifti1Image(micro_fit.tortuosity, affine=dwi_image.affine) dkitortuosity_file = os.path.join(out, "dki_tortuosity.nii.gz") nibabel.save(tortuosity_image, dkitortuosity_file) return (dkikt_file, dkifa_file, dkimd_file, dkiad_file, dkird_file, dkicl_file, dkicp_file, dkics_file, dkimk_file, dkiak_file, dkirk_file, dkimask_file, dkiawf_file, dkitortuosity_file)
def test_kurtosis_maximum(): # TEST 1 # simulate a crossing fibers interserting at 70 degrees. The first fiber # is aligned to the x-axis while the second fiber is aligned to the x-z # plane with an angular deviation of 70 degrees from the first one. # According to Neto Henriques et al, 2015 (NeuroImage 111: 85-99), the # kurtosis tensor of this simulation will have a maxima aligned to axis y angles = [(90, 0), (90, 0), (20, 0), (20, 0)] signal_70, dt_70, kt_70 = multi_tensor_dki(gtab_2s, mevals_cross, S0=100, angles=angles, fractions=frac_cross, snr=None) # prepare inputs dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(signal_70) MD = dkiF.md kt = dkiF.kt R = dkiF.evecs evals = dkiF.evals dt = lower_triangular(np.dot(np.dot(R, np.diag(evals)), R.T)) sphere = get_sphere('symmetric724') # compute maxima k_max_cross, max_dir = dki._voxel_kurtosis_maximum(dt, MD, kt, sphere, gtol=1e-5) yaxis = np.array([0., 1., 0.]) cos_angle = np.abs(np.dot(max_dir[0], yaxis)) assert_almost_equal(cos_angle, 1.) # TEST 2 # test the function on cases of well aligned fibers oriented in a random # defined direction. According to Neto Henriques et al, 2015 (NeuroImage # 111: 85-99), the maxima of kurtosis is any direction perpendicular to the # fiber direction. Moreover, according to multicompartmetal simulations, # kurtosis in this direction has to be equal to: fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 RD = fie*RDi + (1-fie)*RDe RK = 3 * fie * (1-fie) * ((RDi-RDe) / RD) ** 2 # prepare simulation: theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie*100, (1 - fie)*100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # prepare inputs dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(signal) MD = dkiF.md kt = dkiF.kt R = dkiF.evecs evals = dkiF.evals dt = lower_triangular(np.dot(np.dot(R, np.diag(evals)), R.T)) # compute maxima k_max, max_dir = dki._voxel_kurtosis_maximum(dt, MD, kt, sphere, gtol=1e-5) # check if max direction is perpendicular to fiber direction fdir = np.array([sphere2cart(1., np.deg2rad(theta), np.deg2rad(phi))]) cos_angle = np.abs(np.dot(max_dir[0], fdir[0])) assert_almost_equal(cos_angle, 0., decimal=5) # check if max direction is equal to expected value assert_almost_equal(k_max, RK) # According to Neto Henriques et al., 2015 (NeuroImage 111: 85-99), # e.g. see figure 1 of this article, kurtosis maxima for the first test is # also equal to the maxima kurtosis value of well-aligned fibers, since # simulations parameters (apart from fiber directions) are equal assert_almost_equal(k_max_cross, RK) # Test 3 - Test performance when kurtosis is spherical - this case, can be # problematic since a spherical kurtosis does not have an maximum k_max, max_dir = dki._voxel_kurtosis_maximum(dt_sph, np.mean(evals_sph), kt_sph, sphere, gtol=1e-2) assert_almost_equal(k_max, Kref_sphere) # Test 4 - Test performance when kt have all elements zero - this case, can # be problematic this case does not have an maximum k_max, max_dir = dki._voxel_kurtosis_maximum(dt_sph, np.mean(evals_sph), np.zeros(15), sphere, gtol=1e-2) assert_almost_equal(k_max, 0.0)
def calc_cod1000(subject): s3 = boto3.resource('s3') boto3.setup_default_session(profile_name='cirrus') bucket = s3.Bucket('hcp-dki') path_dti = '%s/%s_cod_dti_1000.nii.gz' % (subject, subject) path_dki = '%s/%s_cod_dki_1000.nii.gz' % (subject, subject) if not (exists(path_dti, bucket.name) and exists(path_dki, bucket.name)): print("File doesn't exist - going ahead") with tempfile.TemporaryDirectory() as tempdir: try: bucket = setup_boto() dwi_file = op.join(tempdir, 'data.nii.gz') bvec_file = op.join(tempdir, 'data.bvec') bval_file = op.join(tempdir, 'data.bval') data_files = {} data_files[dwi_file] = \ 'HCP_900/%s/T1w/Diffusion/data.nii.gz' % subject data_files[bvec_file] = \ 'HCP_900/%s/T1w/Diffusion/bvecs' % subject data_files[bval_file] = \ 'HCP_900/%s/T1w/Diffusion/bvals' % subject for k in data_files.keys(): if not op.exists(k): bucket.download_file(data_files[k], k) wm_file = op.join(tempdir, 'wm.nii.gz') boto3.setup_default_session(profile_name='cirrus') s3 = boto3.resource('s3') bucket = s3.Bucket('hcp-dki') s3.meta.client.download_file( 'hcp-dki', '%s/%s_white_matter_mask.nii.gz' % (subject, subject), wm_file) wm_mask = nib.load(wm_file).get_data().astype(bool) dwi_img = nib.load(dwi_file) data = dwi_img.get_data() bvals = np.loadtxt(bval_file) bvecs = np.loadtxt(bvec_file) idx = bvals < 1985 if not exists(path_dki, bucket.name): gtab = dpg.gradient_table(bvals, bvecs, b0_threshold=10) dki_model = dki.DiffusionKurtosisModel(gtab) # Use all the data to calculate the mode pred = xval.kfold_xval(dki_model, data, 5, mask=wm_mask) # But compare only on the b=1000 shell (same as DTI): cod = xval.coeff_of_determination(pred[..., idx], data[..., idx]) cod_file = op.join(tempdir, 'cod_dki_1000.nii.gz') nib.save(nib.Nifti1Image(cod, dwi_img.affine), cod_file) s3.meta.client.upload_file(cod_file, 'hcp-dki', path_dki) if not exists(path_dti, bucket.name): data = data[..., idx] gtab = dpg.gradient_table(bvals[idx], bvecs[:, idx].squeeze(), b0_threshold=10) model = dti.TensorModel(gtab) pred = xval.kfold_xval(model, data, 5, mask=wm_mask) cod = xval.coeff_of_determination(pred, data) cod_file = op.join(tempdir, 'cod_dti_1000.nii.gz') nib.save(nib.Nifti1Image(cod, dwi_img.affine), cod_file) s3.meta.client.upload_file(cod_file, 'hcp-dki', path_dti) return subject, True except Exception as err: return subject, err.args else: return subject, True
def make_maps(subject): s3 = boto3.resource('s3') boto3.setup_default_session(profile_name='cirrus') bucket = s3.Bucket('hcp-dki') path = '%s/%s_dki_1000_3000_MK.nii.gz' % (subject, subject) if not exists(path, bucket.name): with tempfile.TemporaryDirectory() as tempdir: try: bucket = setup_boto() dwi_file = op.join(tempdir, 'data.nii.gz') bvec_file = op.join(tempdir, 'data.bvec') bval_file = op.join(tempdir, 'data.bval') data_files = {} data_files[dwi_file] = \ 'HCP_900/%s/T1w/Diffusion/data.nii.gz' % subject data_files[bvec_file] = \ 'HCP_900/%s/T1w/Diffusion/bvecs' % subject data_files[bval_file] = \ 'HCP_900/%s/T1w/Diffusion/bvals' % subject for k in data_files.keys(): if not op.exists(k): bucket.download_file(data_files[k], k) wm_file = op.join(tempdir, 'wm.nii.gz') boto3.setup_default_session(profile_name='cirrus') s3 = boto3.resource('s3') bucket = s3.Bucket('hcp-dki') s3.meta.client.download_file( 'hcp-dki', '%s/%s_white_matter_mask.nii.gz' % (subject, subject), wm_file) wm_mask = nib.load(wm_file).get_data().astype(bool) dwi_img = nib.load(dwi_file) data = dwi_img.get_data() bvals = np.loadtxt(bval_file) bvecs = np.loadtxt(bvec_file) gtab = dpg.gradient_table(bvals, bvecs) idx1000 = ((gtab.bvals < 1100) | (gtab.bvals <= 5)) idx2000 = (((gtab.bvals > 1100) & (gtab.bvals < 2100)) | (gtab.bvals <= 5)) idx3000 = ((gtab.bvals > 2100) | (gtab.bvals <= 5)) data1000 = data[..., idx1000] data2000 = data[..., idx2000] data3000 = data[..., idx3000] data1000_2000 = data[..., idx1000 + idx2000] data1000_3000 = data[..., idx1000 + idx3000] data2000_3000 = data[..., idx2000 + idx3000] gtab1000 = dpg.gradient_table(gtab.bvals[idx1000], gtab.bvecs[idx1000], b0_threshold=10) gtab2000 = dpg.gradient_table(gtab.bvals[idx1000], gtab.bvecs[idx1000], b0_threshold=10) gtab3000 = dpg.gradient_table(gtab.bvals[idx1000], gtab.bvecs[idx1000], b0_threshold=10) gtab1000_2000 = dpg.gradient_table( gtab.bvals[idx1000 + idx2000], gtab.bvecs[idx1000 + idx2000], b0_threshold=10) gtab1000_3000 = dpg.gradient_table( gtab.bvals[idx1000 + idx3000], gtab.bvecs[idx1000 + idx3000], b0_threshold=10) gtab2000_3000 = dpg.gradient_table( gtab.bvals[idx2000 + idx3000], gtab.bvecs[idx2000 + idx3000], b0_threshold=10) dti_model1000 = dti.TensorModel(gtab1000) dti_model2000 = dti.TensorModel(gtab2000) dti_model3000 = dti.TensorModel(gtab3000) dti_model1000_2000 = dti.TensorModel(gtab1000_2000) dti_model1000_3000 = dti.TensorModel(gtab1000_3000) dti_model2000_3000 = dti.TensorModel(gtab2000_3000) dti_fit1000 = dti_model1000.fit(data1000, mask=wm_mask) dti_fit2000 = dti_model2000.fit(data2000, mask=wm_mask) dti_fit3000 = dti_model3000.fit(data3000, mask=wm_mask) dti_fit1000_2000 = dti_model1000_2000.fit(data1000_2000, mask=wm_mask) dti_fit1000_3000 = dti_model1000_3000.fit(data1000_3000, mask=wm_mask) dti_fit2000_3000 = dti_model2000_3000.fit(data2000_3000, mask=wm_mask) for FA, fa_file in zip([ dti_fit1000.fa, dti_fit2000.fa, dti_fit3000.fa, dti_fit1000_2000.fa, dti_fit2000_3000.fa, dti_fit1000_3000.fa ], [ '%s_dti_1000_FA.nii.gz' % subject, '%s_dti_2000_FA.nii.gz' % subject, '%s_dti_3000_FA.nii.gz' % subject, '%s_dti_1000_2000_FA.nii.gz' % subject, '%s_dti_2000_3000_FA.nii.gz' % subject, '%s_dti_1000_3000_FA.nii.gz' % subject, ]): nib.save(nib.Nifti1Image(FA, dwi_img.affine), op.join(tempdir, fa_file)) s3.meta.client.upload_file(op.join(tempdir, fa_file), 'hcp-dki', '%s/%s' % (subject, fa_file)) for MD, md_file in zip([ dti_fit1000.md, dti_fit2000.md, dti_fit3000.md, dti_fit1000_2000.md, dti_fit2000_3000.md, dti_fit1000_3000.md ], [ '%s_dti_1000_MD.nii.gz' % subject, '%s_dti_2000_MD.nii.gz' % subject, '%s_dti_3000_MD.nii.gz' % subject, '%s_dti_1000_2000_MD.nii.gz' % subject, '%s_dti_2000_3000_MD.nii.gz' % subject, '%s_dti_1000_3000_MD.nii.gz' % subject, ]): nib.save(nib.Nifti1Image(MD, dwi_img.affine), op.join(tempdir, md_file)) s3.meta.client.upload_file(op.join(tempdir, md_file), 'hcp-dki', '%s/%s' % (subject, md_file)) dki_model1000_2000 = dki.DiffusionKurtosisModel(gtab1000_2000) dki_model1000_3000 = dki.DiffusionKurtosisModel(gtab1000_3000) dki_model2000_3000 = dki.DiffusionKurtosisModel(gtab2000_3000) dki_fit1000_2000 = dki_model1000_2000.fit(data1000_2000) dki_fit1000_3000 = dki_model1000_3000.fit(data1000_3000) dki_fit2000_3000 = dki_model2000_3000.fit(data2000_3000) for FA, fa_file in zip([ dki_fit1000_2000.fa, dki_fit2000_3000.fa, dki_fit1000_3000.fa ], [ '%s_dki_1000_2000_FA.nii.gz' % subject, '%s_dki_2000_3000_FA.nii.gz' % subject, '%s_dki_1000_3000_FA.nii.gz' % subject, ]): nib.save(nib.Nifti1Image(FA, dwi_img.affine), op.join(tempdir, fa_file)) s3.meta.client.upload_file(op.join(tempdir, fa_file), 'hcp-dki', '%s/%s' % (subject, fa_file)) for MD, md_file in zip([ dki_fit1000_2000.md, dki_fit2000_3000.md, dki_fit1000_3000.md ], [ '%s_dki_1000_2000_MD.nii.gz' % subject, '%s_dki_2000_3000_MD.nii.gz' % subject, '%s_dki_1000_3000_MD.nii.gz' % subject, ]): nib.save(nib.Nifti1Image(MD, dwi_img.affine), op.join(tempdir, md_file)) s3.meta.client.upload_file(op.join(tempdir, md_file), 'hcp-dki', '%s/%s' % (subject, md_file)) for MK, mk_file in zip([ dki_fit1000_2000.mk(), dki_fit2000_3000.mk(), dki_fit1000_3000.mk() ], [ '%s_dki_1000_2000_MK.nii.gz' % subject, '%s_dki_2000_3000_MK.nii.gz' % subject, '%s_dki_1000_3000_MK.nii.gz' % subject, ]): nib.save(nib.Nifti1Image(MK, dwi_img.affine), op.join(tempdir, mk_file)) s3.meta.client.upload_file(op.join(tempdir, mk_file), 'hcp-dki', '%s/%s' % (subject, mk_file)) return subject, True except Exception as err: return subject, err.args else: return subject, True
def main(self): self.imgFile = str(self.imgFile) self.maskFile = str(self.maskFile) self.mk_low_high = [ float(x) for x in self.mk_low_high[1:-1].split(',') ] self.mk_low_high.sort() self.fa_low_high = [ float(x) for x in self.fa_low_high[1:-1].split(',') ] self.fa_low_high.sort() self.md_low_high = [ float(x) for x in self.md_low_high[1:-1].split(',') ] self.md_low_high.sort() hdr = None affine = None if not self.out_dir: self.out_dir = os.path.dirname(self.imgFile) outPrefix = os.path.join(self.out_dir, os.path.basename(self.imgFile).split('.')[0]) if self.imgFile.endswith('.nii.gz') or self.imgFile.endswith('.nii'): bvals, bvecs = read_bvals_bvecs(self.bvalFile, self.bvecFile) outFormat = '.nii.gz' img = nib.load(self.imgFile) data = img.get_data() affine = img.affine grad_axis = 3 if len(data.shape) != 4: raise AttributeError('Not a valid dwi, check dimension') elif self.imgFile.endswith('.nrrd') or self.imgFile.endswith('.nhdr'): img = nrrd.read(self.imgFile) data = img[0] hdr = img[1] outFormat = '.nrrd' bvals, bvecs, b_max, grad_axis, N = nrrd_bvals_bvecs(hdr) # put the gradients along last axis if grad_axis != 3: data = np.moveaxis(data, grad_axis, 3) # provide the user a liberty to specify different file formats for dwi and mask if self.maskFile.endswith('.nii.gz') or self.maskFile.endswith('.nii'): mask_data = nib.load(self.maskFile).get_data() elif self.maskFile.endswith('.nrrd') or self.maskFile.endswith( '.nhdr'): mask_data = nrrd.read(self.maskFile)[0] data = applymask(data, mask_data) gtab = gradient_table(bvals, bvecs) dtimodel = dti.TensorModel(gtab) dtifit = dtimodel.fit(data, mask_data) evals = dtifit.evals fa = dtifit.fa md = dtifit.md ad = dtifit.ad rd = dtifit.rd evals_zero = evals < 0. evals_zero_mask = (evals_zero[..., 0] | evals_zero[..., 1] | evals_zero[..., 2]) * 1 mkFlag = check_multi_b(gtab, n_bvals=3) if mkFlag: dkimodel = dki.DiffusionKurtosisModel(gtab) dkifit = dkimodel.fit(data, mask_data) mk = dkifit.mk( 0, 3) # http://nipy.org/dipy/examples_built/reconst_dki.html else: warnings.warn( "DIPY DKI requires at least 3 b-shells (which can include b=0), " "kurtosis quality cannot be computed.") fa_mask = mask_calc(fa, self.fa_low_high) md_mask = mask_calc(md, self.md_low_high) where_b0s = np.where(bvals == 0)[0] where_dwi = np.where(bvals != 0)[0] bse_data = data[..., where_b0s].mean(-1) b0File = outPrefix + '_b0' + outFormat save_map(b0File, bse_data, affine, hdr) # prevent division by zero during normalization bse_data[bse_data < 1] = 1. extend_bse = np.expand_dims(bse_data, grad_axis) extend_bse = np.repeat(extend_bse, len(where_dwi), grad_axis) curtail_dwi = np.take(data, where_dwi, axis=grad_axis) # 1 / b0 * min(b0 - Gi) minOverGrads = np.min(extend_bse - curtail_dwi, axis=grad_axis) / bse_data # another way to prevent division by zero: 1/b0 * min(b0-Gi) with condition at b0~eps # minOverGrads = np.min(extend_bse - curtail_dwi, axis=grad_axis) / (bse_data + eps) # minOverGrads[(bse_data < eps) & (minOverGrads < 5 * eps)] = 0. # minOverGrads[(bse_data < eps) & (minOverGrads > 5 * eps)] = 10. minOverGradsNegativeMask = (minOverGrads < 0) * 1 # compute histograms print('\nminOverGrads (b0-Gi)/b0 histogram') bins = [-inf, 0, inf] negative, _ = hist_calc(minOverGrads, bins) print('\nevals<0 histogram') bins = [-inf, 0, inf] hist_calc(evals, bins) print('\nfractional anisotropy histogram') bins = form_bins(self.fa_low_high) hist_calc(fa, bins) print('\nmean diffusivity histogram') bins = form_bins(self.md_low_high) hist_calc(md, bins) if mkFlag: print('\nmean kurtosis mask') bins = form_bins(self.mk_low_high) hist_calc(mk, bins) # save histograms print('\nCreating minOverGrads image ...') save_map(outPrefix + '_minOverGrads' + outFormat, minOverGrads, affine, hdr) print('\nCreating minOverGrads<0 mask ...') save_map(outPrefix + '_minOverGradsMask' + outFormat, minOverGradsNegativeMask.astype('short'), affine, hdr) print('\nCreating evals<0 mask ...') save_map(outPrefix + '_evalsZeroMask' + outFormat, evals_zero_mask.astype('short'), affine, hdr) if mkFlag: mk_mask = mask_calc(mk, self.mk_low_high) print('\nCreating mk image ...') save_map(outPrefix + '_MK' + outFormat, mk, affine, hdr) print('Creating mk out of range mask ...') save_map(outPrefix + '_MK_mask' + outFormat, mk_mask.astype('short'), affine, hdr) else: mk = np.zeros(fa.shape) print('\nCreating fa image ...') save_map(outPrefix + '_FA' + outFormat, fa, affine, hdr) print('Creating fa out of range mask ...') save_map(outPrefix + '_FA_mask' + outFormat, fa_mask.astype('short'), affine, hdr) print('\nCreating md image ....') save_map(outPrefix + '_MD' + outFormat, md, affine, hdr) print('Creating md out of range mask ...') save_map(outPrefix + '_MD_mask' + outFormat, md_mask.astype('short'), affine, hdr) # conclusion N_mask = mask_data.size print('\n\nConclusion: ') print('The masked dwi has %.5f%% voxels with values less than b0' % (negative * 100)) print('The masked dwi has %.5f%% voxels with negative eigen value' % (evals_zero_mask.sum() / N_mask * 100)) print('The masked dwi has %.5f%% voxels with FA out of [%f,%f]' % (fa_mask.sum() / N_mask * 100, self.fa_low_high[0], self.fa_low_high[1])) print('The masked dwi has %.5f%% voxels with MD out of [%f,%f]' % (md_mask.sum() / N_mask * 100, self.md_low_high[0], self.md_low_high[1])) if mkFlag: print('The masked dwi has %.5f%% voxels with MK out of [%f,%f]' % (mk_mask.sum() / N_mask * 100, self.mk_low_high[0], self.mk_low_high[1])) # perform roi based analysis if self.template and self.labelMap: antsReg(b0File, self.maskFile, self.template, outPrefix) warp = outPrefix + '1Warp.nii.gz' trans = outPrefix + '0GenericAffine.mat' outLabelMapFile = outPrefix + '_labelMap.nii.gz' applyXform(self.labelMap, b0File, warp, trans, outLabelMapFile, interp='NearestNeighbor') rm = local['rm'] rm(warp, trans, outPrefix + 'Warped.nii.gz', outPrefix + '1InverseWarp.nii.gz', outPrefix + 'InverseWarped.nii.gz') outLabelMap = nib.load(outLabelMapFile).get_data() labels = np.unique(outLabelMap)[1:] label2name = parse_labels(labels, self.lut._path if self.lut else None) print('Creating ROI based statistics ...') stat_file = outPrefix + f'_{self.name}_stat.csv' df = pd.DataFrame(columns=[ 'region', 'FA_mean', 'FA_std', 'MD_mean', 'MD_std', 'AD_mean', 'AD_std', 'RD_mean', 'RD_std', 'total_{min_i(b0-Gi)<0}', 'total_evals<0', 'MK_mean', 'MK_std', ]) for i, label in enumerate(label2name.keys()): roi = outLabelMap == int(label) properties = [ num2str(x) for x in [ fa[roi > 0].mean(), fa[roi > 0].std(), md[roi > 0]. mean(), md[roi > 0].std(), ad[roi > 0].mean(), ad[ roi > 0].std(), rd[roi > 0].mean(), rd[roi > 0].std(), minOverGradsNegativeMask[ roi > 0].sum(), evals_zero_mask[roi > 0].sum(), mk[ roi > 0].mean(), mk[roi > 0].std() ] ] df.loc[i] = [label2name[label]] + properties df = df.set_index('region') # print(df) df.to_csv(stat_file) print('See ', os.path.abspath(stat_file))
def _fit(gtab, data, mask=None): dkimodel = dki.DiffusionKurtosisModel(gtab) return dkimodel.fit(data, mask=mask)
def fit_dki_dipy(input_dwi, input_bval, input_bvec, output_dir, fit_method='', mask='', include_micro_fit='FALSE'): if fit_method == '': fit_method = 'OLS' img = nib.load(input_dwi) data = img.get_data() bvals, bvecs = read_bvals_bvecs( input_bval, input_bvec, ) gtab = gradient_table(bvals, bvecs) if mask != '': mask_data = nib.load(mask).get_data() values = np.array(bvals) ii = np.where(values == bvals.min())[0] b0_average = np.mean(data[:, :, :, ii], axis=3) #Recommended to smooth data prior to fitting: fwhm = 2.00 gauss_std = fwhm / np.sqrt( 8 * np.log(2)) # converting fwhm to Gaussian std data_smooth = np.zeros(data.shape) for v in range(data.shape[-1]): data_smooth[..., v] = filters.gaussian_filter(data[..., v], sigma=gauss_std) dkimodel = dki.DiffusionKurtosisModel(gtab, fit_method) if mask != '': dkifit = dkimodel.fit(data_smooth, mask_data) else: dkifit = dkimodel.fit(data_smooth) if not os.path.exists(output_dir): os.mkdir(output_dir) output_evecs = output_dir + '/dki_eigenvectors.nii.gz' output_evals = output_dir + '/dki_eigenvalues.nii.gz' output_fa = output_dir + '/dki_FA.nii.gz' output_md = output_dir + '/dki_MD.nii.gz' output_rd = output_dir + '/dki_RD.nii.gz' output_ad = output_dir + '/dki_AD.nii.gz' output_mk = output_dir + '/dki_MK.nii.gz' output_ak = output_dir + '/dki_AK.nii.gz' output_rk = output_dir + '/dki_RK.nii.gz' #Calculate Parameters for Kurtosis Model evals_img = nib.Nifti1Image(dkifit.evals.astype(np.float32), img.get_affine(), img.header) nib.save(evals_img, output_evals) evecs_img = nib.Nifti1Image(dkifit.evecs.astype(np.float32), img.get_affine(), img.header) nib.save(evecs_img, output_evecs) dki_fa = dkifit.fa dki_fa_img = nib.Nifti1Image(dki_fa.astype(np.float32), img.get_affine(), img.header) nib.save(dki_fa_img, output_fa) dki_md = dkifit.md dki_md_img = nib.Nifti1Image(dki_md.astype(np.float32), img.get_affine(), img.header) nib.save(dki_md_img, output_md) dki_ad = dkifit.ad dki_ad_img = nib.Nifti1Image(dki_ad.astype(np.float32), img.get_affine(), img.header) nib.save(dki_ad_img, output_ad) dki_rd = dkifit.rd dki_rd_img = nib.Nifti1Image(dki_rd.astype(np.float32), img.get_affine(), img.header) nib.save(dki_rd_img, output_rd) MK = dkifit.mk(0, 3) AK = dkifit.ak(0, 3) RK = dkifit.rk(0, 3) dki_mk_img = nib.Nifti1Image(MK.astype(np.float32), img.get_affine(), img.header) nib.save(dki_mk_img, output_mk) dki_ak_img = nib.Nifti1Image(AK.astype(np.float32), img.get_affine(), img.header) nib.save(dki_ak_img, output_ak) dki_rk_img = nib.Nifti1Image(RK.astype(np.float32), img.get_affine(), img.header) nib.save(dki_rk_img, output_rk) if include_micro_fit == 'TRUE': import dipy.reconst.dki_micro as dki_micro well_aligned_mask = np.ones(data.shape[:-1], dtype='bool') # Diffusion coefficient of linearity (cl) has to be larger than 0.4, thus # we exclude voxels with cl < 0.4. cl = dkifit.linearity.copy() well_aligned_mask[cl < 0.2] = False # Diffusion coefficient of planarity (cp) has to be lower than 0.2, thus # we exclude voxels with cp > 0.2. cp = dkifit.planarity.copy() well_aligned_mask[cp > 0.2] = False # Diffusion coefficient of sphericity (cs) has to be lower than 0.35, thus # we exclude voxels with cs > 0.35. cs = dkifit.sphericity.copy() well_aligned_mask[cs > 0.2] = False # Removing nan associated with background voxels well_aligned_mask[np.isnan(cl)] = False well_aligned_mask[np.isnan(cp)] = False well_aligned_mask[np.isnan(cs)] = False dki_micro_model = dki_micro.KurtosisMicrostructureModel( gtab, fit_method) dki_micro_fit = dki_micro_model.fit(data_smooth, mask=well_aligned_mask) output_awf = output_dir + '/dki_micro_AWF.nii.gz' output_tort = output_dir + '/dki_micro_TORT.nii.gz' dki_micro_awf = dki_micro_fit.awf dki_micro_tort = dki_micro_fit.tortuosity dki_micro_awf_img = nib.Nifti1Image(dki_micro_awf.astype(np.float32), img.get_affine(), img.header) nib.save(dki_micro_awf_img, output_awf) dki_micro_tort_img = nib.Nifti1Image(dki_micro_tort.astype(np.float32), img.get_affine(), img.header) nib.save(dki_micro_tort_img, output_tort)
def Kurtosis(dwi, mask): import numpy as np import dipy.reconst.dki as dki import dipy.reconst.dti as dti import dipy.reconst.dki_micro as dki_micro from dipy.data import fetch_cfin_multib from dipy.data import read_cfin_dwi from dipy.segment.mask import median_otsu from dipy.io.image import load_nifti, save_nifti from scipy.ndimage.filters import gaussian_filter import nibabel as nib from dipy.core.gradients import gradient_table from dipy.io import read_bvals_bvecs from sklearn import preprocessing import dipy.denoise.noise_estimate as ne # determine the noise needed for RESTORE import os bval = '/media/amr/HDD/Work/October_Acquistion/bval_multishell' bvec = '/media/amr/HDD/Work/October_Acquistion/bvec_multishell' protocol = '/media/amr/HDD/Work/October_Acquistion/MDT_multishell_protocol.prtcl' data, affine = load_nifti(dwi) mask, affine_mask = load_nifti(mask) protocol = np.loadtxt(protocol) fbval = bval fbvec = bvec bval, bvec = read_bvals_bvecs(fbval, fbvec) gnorm = protocol[:, 3] Delta = protocol[:, 4] delta = protocol[:, 5] TE = protocol[:, 6] TR = protocol[:, 8] if np.dot(bvec[5, :], bvec[5, :]) == 1.0: gtab = gradient_table(bval, bvec, big_delta=Delta, small_delta=delta, b0_threshold=0, atol=1) else: bvec = preprocessing.normalize(bvec, norm='l2') gtab = gradient_table(bval, bvec, big_delta=Delta, small_delta=delta, b0_threshold=0, atol=0.01) #without disable_background_masking, it does not work with some subjects sigma = ne.estimate_sigma(data, disable_background_masking=True) # dkimodel = dki.DiffusionKurtosisModel(gtab, fit_method='WLS') the old way also the default dkimodel = dki.DiffusionKurtosisModel(gtab, fit_method='RESTORE', sigma=sigma) #AWF and TORT from microstructure model dki_micro_model = dki_micro.KurtosisMicrostructureModel( gtab, fit_method='RESTORE') # fit the models dkifit = dkimodel.fit(data, mask=mask) dki_micro_fit = dki_micro_model.fit(data, mask=mask) FA = dkifit.fa MD = dkifit.md AD = dkifit.ad RD = dkifit.rd KA = dkifit.kfa MK = dkifit.mk(0, 3) AK = dkifit.ak(0, 3) RK = dkifit.rk(0, 3) AWF = dki_micro_fit.awf #Axonal watrer Fraction TORT = dki_micro_fit.tortuosity #Tortouisty save_nifti('DKI_FA.nii', FA, affine) save_nifti('DKI_MD.nii', MD, affine) save_nifti('DKI_AD.nii', AD, affine) save_nifti('DKI_RD.nii', RD, affine) save_nifti('DKI_KA.nii', KA, affine) save_nifti('DKI_MK.nii', MK, affine) save_nifti('DKI_AK.nii', AK, affine) save_nifti('DKI_RK.nii', RK, affine) save_nifti('DKI_AWF.nii', AWF, affine) save_nifti('DKI_TORT.nii', TORT, affine) DKI_FA = os.path.abspath('DKI_FA.nii') DKI_MD = os.path.abspath('DKI_MD.nii') DKI_AD = os.path.abspath('DKI_AD.nii') DKI_RD = os.path.abspath('DKI_RD.nii') DKI_KA = os.path.abspath('DKI_KA.nii') DKI_MK = os.path.abspath('DKI_MK.nii') DKI_AK = os.path.abspath('DKI_AK.nii') DKI_RK = os.path.abspath('DKI_RK.nii') DKI_AWF = os.path.abspath('DKI_AWF.nii') DKI_TORT = os.path.abspath('DKI_TORT.nii') return DKI_FA, DKI_MD, DKI_AD, DKI_RD, DKI_KA, DKI_MK, DKI_AK, DKI_RK, DKI_AWF, DKI_TORT
def hcp_dki(subject, aws_access_key, aws_secret_key, hcp_aws_access_key, hcp_aws_secret_key, outbucket): fs = s3fs.S3FileSystem(key=aws_access_key, secret=aws_secret_key) remote_p2s_path =\ "%s/derivatives/patch2self" % (outbucket) remote_dti_path =\ "%s/derivatives/dti" % (outbucket) remote_dti1000_path =\ "%s/derivatives/dti1000" % (outbucket) remote_dki_path =\ "%s/derivatives/dki" % (outbucket) remote_sst_path =\ "%s/derivatives/sst" % (outbucket) logging.basicConfig(level=logging.INFO) log = logging.getLogger(__name__) # noqa log.info(f"Getting data for subject {subject}") # get HCP data for the given subject / session _, hcp_bids = fetch_hcp([subject], profile_name=False, aws_access_key_id=hcp_aws_access_key, aws_secret_access_key=hcp_aws_secret_key) dwi_path = op.join(afd.afq_home, 'HCP_1200', 'derivatives', 'dmriprep', f'sub-{subject}', 'ses-01', 'dwi') dwi_img = nib.load(op.join(dwi_path, f'sub-{subject}_dwi.nii.gz')) dwi_data = dwi_img.get_fdata() b0_threshold = 50 gtab = gradient_table(op.join(dwi_path, f'sub-{subject}_dwi.bval'), op.join(dwi_path, f'sub-{subject}_dwi.bvec'), b0_threshold=b0_threshold) rpath = op.join(remote_p2s_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_desc-denoised_dwi.nii.gz') lpath = "./denoised_data.nii.gz" if not fs.exists(rpath): log.info("Denoising with patch2self") t1 = time.time() den_data = patch2self(dwi_data, gtab.bvals, b0_threshold=b0_threshold, clip_negative_vals=False, shift_intensity=True) log.info(f"That took {time.time() - t1} seconds") den_img = nib.Nifti1Image(den_data, dwi_img.affine) nib.save(den_img, lpath) fs.upload(lpath, rpath) else: log.info("Looks like I've already denoised this subject") log.info("Downloading data from S3") fs.download(rpath, lpath) den_data = nib.load(lpath).get_fdata() log.info("Calculating SST") data_dwi = den_data[..., ~gtab.b0s_mask] mean_dwi = np.mean(den_data[..., ~gtab.b0s_mask], -1) sst = np.sum((data_dwi - mean_dwi[..., None])**2, -1) lpath = "data_sst.nii.gz" nib.save(nib.Nifti1Image(sst, dwi_img.affine), lpath) rpath = op.join(remote_sst_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_desc-sst.nii.gz') fs.upload(lpath, rpath) lpath = "dti_params.nii.gz" rpath = op.join(remote_dti_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_diffmodel.nii.gz') if not fs.exists(rpath): log.info("Fitting DTI") t1 = time.time() dtim = dti.TensorModel(gtab) dtif = dtim.fit(den_data, mask=np.ones(den_data.shape[:3])) nib.save(nib.Nifti1Image(dtif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) log.info(f"That took {time.time() - t1} seconds") else: log.info("Looks like I've already fit DTI") log.info("Downloading DTI params from S3") fs.download(rpath, lpath) dtim = dti.TensorModel(gtab) dti_params = nib.load("dti_params.nii.gz") S0 = np.mean(den_data[..., gtab.b0s_mask], -1) pred = dtim.predict(dti_params.get_fdata(), S0=S0) lpath = "dti_pred.nii.gz" rpath = op.join(remote_dti_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_prediction-DTI_diffmodel.nii.gz') nib.save(nib.Nifti1Image(pred, dwi_img.affine), lpath) fs.upload(lpath, rpath) # We calculate SSE only over diffusion-weighted volumes sse = np.sum( (pred[..., ~gtab.b0s_mask] - den_data[..., ~gtab.b0s_mask])**2, -1) lpath = "dti_sse.nii.gz" rpath = op.join(remote_dti_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_SSE-DTI_diffmodel.nii.gz') nib.save(nib.Nifti1Image(sse, dwi_img.affine), lpath) fs.upload(lpath, rpath) ### DTI 1000 lpath = "dti1000_params.nii.gz" rpath = op.join(remote_dti1000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_diffmodel.nii.gz') dwi1000 = den_data[..., gtab.bvals < 1100] gtab1000 = gradient_table(gtab.bvals[gtab.bvals < 1100], gtab.bvecs[gtab.bvals < 1100]) if not fs.exists(rpath): log.info("Fitting DTI") t1 = time.time() dtim = dti.TensorModel(gtab1000) dtif = dtim.fit(dwi1000, mask=np.ones(den_data.shape[:3])) nib.save(nib.Nifti1Image(dtif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) log.info(f"That took {time.time() - t1} seconds") else: log.info("Looks like I've already fit DTI with b=1000") log.info("Downloading DTI params from S3") fs.download(rpath, lpath) dtim = dti.TensorModel(gtab1000) dti_params = nib.load("dti_params.nii.gz") S0 = np.mean(dwi1000[..., gtab1000.b0s_mask], -1) pred = dtim.predict(dti_params.get_fdata(), S0=S0) lpath = "dti1000_pred.nii.gz" rpath = op.join(remote_dti1000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_prediction-DTI_diffmodel.nii.gz') nib.save(nib.Nifti1Image(pred, dwi_img.affine), lpath) fs.upload(lpath, rpath) # We calculate SSE only over diffusion-weighted volumes sse = np.sum( (pred[..., ~gtab1000.b0s_mask] - dwi1000[..., ~gtab1000.b0s_mask])**2, -1) lpath = "dti1000_sse.nii.gz" rpath = op.join(remote_dti1000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_SSE-DTI_diffmodel.nii.gz') nib.save(nib.Nifti1Image(sse, dwi_img.affine), lpath) fs.upload(lpath, rpath) ### DKI lpath = "dki_params.nii.gz" rpath = op.join(remote_dki_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_diffmodel.nii.gz') if not fs.exists(rpath): log.info("Fitting DKI") t1 = time.time() dkim = dki.DiffusionKurtosisModel(gtab) dkif = dkim.fit(den_data) log.info(f"That took {time.time() - t1} seconds") nib.save(nib.Nifti1Image(dkif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) else: log.info("Looks like I've already fit DKI") log.info("Downloading DKI params from S3") fs.download(rpath, lpath) dkim = dki.DiffusionKurtosisModel(gtab) dki_params = nib.load("dki_params.nii.gz") pred = dkim.predict(dki_params.get_fdata(), S0=S0) lpath = "dki_pred.nii.gz" rpath = op.join(remote_dki_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_prediction-DKI_diffmodel.nii.gz') nib.save(nib.Nifti1Image(pred, dwi_img.affine), lpath) fs.upload(lpath, rpath) # We calculate SSE only over diffusion-weighted volumes sse = np.sum( (pred[..., ~gtab.b0s_mask] - den_data[..., ~gtab.b0s_mask])**2, -1) lpath = "dki_sse.nii.gz" rpath = op.join(remote_dki_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_SSE-DKI_diffmodel.nii.gz') nib.save(nib.Nifti1Image(sse, dwi_img.affine), lpath) fs.upload(lpath, rpath)
def main(): logger = logging.getLogger("Compute_DKI_Metrics") logger.setLevel(logging.INFO) parser = _build_args_parser() args = parser.parse_args() if not args.not_all: args.dki_fa = args.dki_fa or 'dki_fa.nii.gz' args.dki_md = args.dki_md or 'dki_md.nii.gz' args.dki_ad = args.dki_ad or 'dki_ad.nii.gz' args.dki_rd = args.dki_rd or 'dki_rd.nii.gz' args.mk = args.mk or 'mk.nii.gz' args.rk = args.rk or 'rk.nii.gz' args.ak = args.ak or 'ak.nii.gz' args.dki_residual = args.dki_residual or 'dki_residual.nii.gz' args.msk = args.msk or 'msk.nii.gz' args.msd = args.msd or 'msd.nii.gz' outputs = [args.dki_fa, args.dki_md, args.dki_ad, args.dki_rd, args.mk, args.rk, args.ak, args.dki_residual, args.msk, args.msd] if args.not_all and not any(outputs): parser.error('When using --not_all, you need to specify at least ' + 'one metric to output.') assert_inputs_exist( parser, [args.input, args.bvals, args.bvecs], args.mask) assert_outputs_exist(parser, args, outputs) img = nib.load(args.input) data = img.get_fdata() affine = img.affine if args.mask is None: mask = None else: mask = nib.load(args.mask).get_fdata().astype(np.bool) # Validate bvals and bvecs bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) if not is_normalized_bvecs(bvecs): logging.warning('Your b-vectors do not seem normalized...') bvecs = normalize_bvecs(bvecs) # Find the volume indices that correspond to the shells to extract. tol = args.tolerance shells, _ = identify_shells(bvals, tol) if not len(shells) >= 3: parser.error('Data is not multi-shell. You need at least 2 non-zero' + ' b-values') if (shells > 2500).any(): logging.warning('You seem to be using b > 2500 s/mm2 DWI data. ' + 'In theory, this is beyond the optimal range for DKI') check_b0_threshold(args, bvals.min()) gtab = gradient_table(bvals, bvecs, b0_threshold=bvals.min()) fwhm = args.smooth if fwhm > 0: # converting fwhm to Gaussian std gauss_std = fwhm / np.sqrt(8 * np.log(2)) data_smooth = np.zeros(data.shape) for v in range(data.shape[-1]): data_smooth[..., v] = gaussian_filter(data[..., v], sigma=gauss_std) data = data_smooth # Compute DKI dkimodel = dki.DiffusionKurtosisModel(gtab) dkifit = dkimodel.fit(data, mask=mask) min_k = args.min_k max_k = args.max_k if args.dki_fa: FA = dkifit.fa FA[np.isnan(FA)] = 0 FA = np.clip(FA, 0, 1) fa_img = nib.Nifti1Image(FA.astype(np.float32), affine) nib.save(fa_img, args.dki_fa) if args.dki_md: MD = dkifit.md md_img = nib.Nifti1Image(MD.astype(np.float32), affine) nib.save(md_img, args.dki_md) if args.dki_ad: AD = dkifit.ad ad_img = nib.Nifti1Image(AD.astype(np.float32), affine) nib.save(ad_img, args.dki_ad) if args.dki_rd: RD = dkifit.rd rd_img = nib.Nifti1Image(RD.astype(np.float32), affine) nib.save(rd_img, args.dki_rd) if args.mk: MK = dkifit.mk(min_k, max_k) mk_img = nib.Nifti1Image(MK.astype(np.float32), affine) nib.save(mk_img, args.mk) if args.ak: AK = dkifit.ak(min_k, max_k) ak_img = nib.Nifti1Image(AK.astype(np.float32), affine) nib.save(ak_img, args.ak) if args.rk: RK = dkifit.rk(min_k, max_k) rk_img = nib.Nifti1Image(RK.astype(np.float32), affine) nib.save(rk_img, args.rk) if args.msk or args.msd: # Compute MSDKI msdki_model = msdki.MeanDiffusionKurtosisModel(gtab) msdki_fit = msdki_model.fit(data, mask=mask) if args.msk: MSK = msdki_fit.msk MSK[np.isnan(MSK)] = 0 MSK = np.clip(MSK, min_k, max_k) msk_img = nib.Nifti1Image(MSK.astype(np.float32), affine) nib.save(msk_img, args.msk) if args.msd: MSD = msdki_fit.msd msd_img = nib.Nifti1Image(MSD.astype(np.float32), affine) nib.save(msd_img, args.msd) if args.dki_residual: S0 = np.mean(data[..., gtab.b0s_mask], axis=-1) data_p = dkifit.predict(gtab, S0) R = np.mean(np.abs(data_p[..., ~gtab.b0s_mask] - data[..., ~gtab.b0s_mask]), axis=-1) norm = np.linalg.norm(R) if norm != 0: R = R / norm if args.mask is not None: R *= mask R_img = nib.Nifti1Image(R.astype(np.float32), affine) nib.save(R_img, args.dki_residual)
the data's structural information is preserved by the PCA denoising algorithm (right panel). Below we show how the denoised data can be saved. """ nib.save(nib.Nifti1Image(denoised_arr, affine), 'denoised_mppca.nii.gz') print("Entire denoised data saved in denoised_mppca.nii.gz") """ Additionally, we show how the PCA denoising algorithm affects different diffusion measurements. For this, we run the diffusion kurtosis model below on both original and denoised versions of the data: """ dkimodel = dki.DiffusionKurtosisModel(gtab) maskdata, mask = median_otsu(data, vol_idx=[0, 1], median_radius=4, numpass=2, autocrop=False, dilate=1) dki_orig = dkimodel.fit(data, mask=mask) dki_den = dkimodel.fit(denoised_arr, mask=mask) """ We use the following code to plot the MD, FA and MK estimates from the two data fits: """
def hcp_dki(subject, aws_access_key, aws_secret_key, hcp_aws_access_key, hcp_aws_secret_key, outbucket): fs = s3fs.S3FileSystem(key=aws_access_key, secret=aws_secret_key) remote_dti1000_path =\ "%s/derivatives/dti1000" % (outbucket) remote_dti1000_2000_path =\ "%s/derivatives/dti1000_2000" % (outbucket) remote_dki1000_2000_path =\ "%s/derivatives/dki1000_2000" % (outbucket) remote_dki2000_3000_path =\ "%s/derivatives/dki2000_3000" % (outbucket) remote_dki1000_3000_path =\ "%s/derivatives/dki1000_3000" % (outbucket) logging.basicConfig(level=logging.INFO) log = logging.getLogger(__name__) # noqa log.info(f"Getting data for subject {subject}") # get HCP data for the given subject / session _, hcp_bids = fetch_hcp( [subject], profile_name=False, aws_access_key_id=hcp_aws_access_key, aws_secret_access_key=hcp_aws_secret_key) dwi_path = op.join(afd.afq_home, 'HCP_1200', 'derivatives', 'dmriprep', f'sub-{subject}', 'ses-01', 'dwi') dwi_img = nib.load(op.join(dwi_path, f'sub-{subject}_dwi.nii.gz')) dwi_data = dwi_img.get_fdata() b0_threshold = 50 gtab = gradient_table( op.join(dwi_path, f'sub-{subject}_dwi.bval'), op.join(dwi_path, f'sub-{subject}_dwi.bvec'), b0_threshold=b0_threshold) ### DTI 1000 last_result = op.join( remote_dti1000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_MD.nii.gz') if not fs.exists(last_result): lpath = "dti1000_params.nii.gz" rpath = op.join(remote_dti1000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_diffmodel.nii.gz') dwi1000 = dwi_data[..., gtab.bvals < 1100] gtab1000 = gradient_table(gtab.bvals[gtab.bvals < 1100], gtab.bvecs[gtab.bvals < 1100]) if not fs.exists(rpath): log.info("Fitting DTI") t1 = time.time() dtim = dti.TensorModel(gtab1000) dtif = dtim.fit(dwi1000, mask=np.ones(dwi_data.shape[:3])) nib.save(nib.Nifti1Image(dtif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) log.info(f"That took {time.time() - t1} seconds") else: log.info("Looks like I've already fit DTI with b=1000") log.info("Downloading DTI params from S3") fs.download(rpath, lpath) dtim = dti.TensorModel(gtab1000) dti_params = nib.load(lpath).get_fdata() dtif = dti.TensorFit(dtim, dti_params) lpath = "dti1000_fa.nii.gz" nib.save(nib.Nifti1Image(dtif.fa, dwi_img.affine), lpath) rpath = op.join(remote_dti1000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_FA.nii.gz') fs.upload(lpath, rpath) lpath = "dti1000_md.nii.gz" nib.save(nib.Nifti1Image(dtif.md, dwi_img.affine), lpath) rpath = op.join(remote_dti1000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_MD.nii.gz') fs.upload(lpath, rpath) ### DTI 1000 + 2000 last_result = op.join( remote_dti1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_MD.nii.gz') if not fs.exists(last_result): lpath = "dti1000_2000_params.nii.gz" rpath = op.join( remote_dti1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_diffmodel.nii.gz') dwi1000_2000 = dwi_data[..., gtab.bvals < 2100] gtab1000_2000 = gradient_table( gtab.bvals[gtab.bvals < 2100], gtab.bvecs[gtab.bvals < 2100]) if not fs.exists(rpath): log.info("Fitting DTI with b=1000 and 2000") t1 = time.time() dtim = dti.TensorModel(gtab1000_2000) dtif = dtim.fit(dwi1000_2000, mask=np.ones(dwi_data.shape[:3])) nib.save(nib.Nifti1Image(dtif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) log.info(f"That took {time.time() - t1} seconds") else: log.info("Looks like I've already fit DTI with b=1000 and b=2000") log.info("Downloading DTI params from S3") fs.download(rpath, lpath) dtim = dti.TensorModel(gtab1000_2000) dti_params = nib.load(lpath).get_fdata() dtif = dti.TensorFit(dtim, dti_params) lpath = "dti1000_2000_fa.nii.gz" nib.save(nib.Nifti1Image(dtif.fa, dwi_img.affine), lpath) rpath = op.join( remote_dti1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_FA.nii.gz') fs.upload(lpath, rpath) lpath = "dti1000_2000_md.nii.gz" nib.save(nib.Nifti1Image(dtif.md, dwi_img.affine), lpath) rpath = op.join( remote_dti1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DTI_MD.nii.gz') fs.upload(lpath, rpath) ### DKI 1000 + 2000 last_result = op.join( remote_dki1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_MD.nii.gz') if not fs.exists(last_result): lpath = "dki1000_2000_params.nii.gz" rpath = op.join( remote_dki1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_diffmodel.nii.gz') dwi1000_2000 = dwi_data[..., gtab.bvals < 2100] gtab1000_2000 = gradient_table(gtab.bvals[gtab.bvals < 2100], gtab.bvecs[gtab.bvals < 2100]) if not fs.exists(rpath): log.info("Fitting DKI with b=1000 + 2000") t1 = time.time() dkim = dki.DiffusionKurtosisModel(gtab1000_2000) dkif = dkim.fit(dwi1000_2000, mask=np.ones(dwi_data.shape[:3])) nib.save(nib.Nifti1Image(dkif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) log.info(f"That took {time.time() - t1} seconds") else: log.info("Looks like I've already fit DKI with b=1000 and b=2000") log.info("Downloading DKI params from S3") fs.download(rpath, lpath) dkim = dki.DiffusionKurtosisModel(gtab1000_2000) dki_params = nib.load(lpath).get_fdata() dkif = dki.DiffusionKurtosisFit(dkim, dki_params) lpath = "dki1000_2000_fa.nii.gz" nib.save(nib.Nifti1Image(dkif.fa, dwi_img.affine), lpath) rpath = op.join( remote_dki1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_FA.nii.gz') fs.upload(lpath, rpath) lpath = "dki1000_2000_md.nii.gz" nib.save(nib.Nifti1Image(dkif.md, dwi_img.affine), lpath) rpath = op.join( remote_dki1000_2000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_MD.nii.gz') fs.upload(lpath, rpath) ### DKI 2000 + 3000 last_result = op.join( remote_dki2000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_MD.nii.gz') if not fs.exists(last_result): lpath = "dki2000_3000_params.nii.gz" rpath = op.join( remote_dki2000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_diffmodel.nii.gz') dwi2000_3000 = dwi_data[..., (gtab.bvals > 1985) | (gtab.bvals < 50)] gtab2000_3000 = gradient_table( gtab.bvals[(gtab.bvals > 1985) | (gtab.bvals < 50)], gtab.bvecs[(gtab.bvals > 1985) | (gtab.bvals < 50)]) if not fs.exists(rpath): log.info("Fitting DKI with b=2000 + 3000") t1 = time.time() dkim = dki.DiffusionKurtosisModel(gtab2000_3000) dkif = dkim.fit(dwi2000_3000, mask=np.ones(dwi_data.shape[:3])) nib.save(nib.Nifti1Image(dkif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) log.info(f"That took {time.time() - t1} seconds") else: log.info("Looks like I've already fit DKI with b=2000 and b=3000") log.info("Downloading DKI params from S3") fs.download(rpath, lpath) dkim = dki.DiffusionKurtosisModel(gtab2000_3000) dki_params = nib.load(lpath).get_fdata() dkif = dki.DiffusionKurtosisFit(dkim, dki_params) lpath = "dki2000_3000_fa.nii.gz" nib.save(nib.Nifti1Image(dkif.fa, dwi_img.affine), lpath) rpath = op.join( remote_dki2000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_FA.nii.gz') fs.upload(lpath, rpath) lpath = "dki2000_3000_md.nii.gz" nib.save(nib.Nifti1Image(dkif.md, dwi_img.affine), lpath) rpath = op.join( remote_dki2000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_MD.nii.gz') fs.upload(lpath, rpath) ### DKI 1000 + 3000 last_result = op.join( remote_dki1000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_MD.nii.gz') if not fs.exists(last_result): lpath = "dki1000_3000_params.nii.gz" rpath = op.join( remote_dki1000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_diffmodel.nii.gz') dwi1000_3000 = dwi_data[..., (gtab.bvals > 2500) | (gtab.bvals < 1500)] gtab1000_3000 = gradient_table( gtab.bvals[(gtab.bvals > 2500) | (gtab.bvals < 1500)], gtab.bvecs[(gtab.bvals > 2500) | (gtab.bvals < 1500)]) if not fs.exists(rpath): log.info("Fitting DKI with b=1000 + 3000") t1 = time.time() dkim = dki.DiffusionKurtosisModel(gtab1000_3000) dkif = dkim.fit(dwi1000_3000, mask=np.ones(dwi_data.shape[:3])) nib.save(nib.Nifti1Image(dkif.model_params, dwi_img.affine), lpath) fs.upload(lpath, rpath) log.info(f"That took {time.time() - t1} seconds") else: log.info("Looks like I've already fit DKI with b=1000 and b=3000") log.info("Downloading DKI params from S3") fs.download(rpath, lpath) dkim = dki.DiffusionKurtosisModel(gtab1000_3000) dki_params = nib.load(lpath).get_fdata() dkif = dki.DiffusionKurtosisFit(dkim, dki_params) lpath = "dki1000_3000_fa.nii.gz" nib.save(nib.Nifti1Image(dkif.fa, dwi_img.affine), lpath) rpath = op.join( remote_dki1000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_FA.nii.gz') fs.upload(lpath, rpath) lpath = "dki1000_3000_md.nii.gz" nib.save(nib.Nifti1Image(dkif.md, dwi_img.affine), lpath) rpath = op.join( remote_dki1000_3000_path, f'sub-{subject}', 'ses-01', 'dwi', f'sub-{subject}_dwi_model-DKI_MD.nii.gz') fs.upload(lpath, rpath)