def test_dki_micro_predict_single_voxel(): # single fiber simulate (which is the assumption of our model) fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # 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) signal_gt, da = multi_tensor(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # Defined DKI microstrutural model dkiM = dki_micro.KurtosisMicrostructureModel(gtab_2s) # Fit single voxel signal dkiF = dkiM.fit(signal) # Check predict of KurtosisMicrostruturalModel pred = dkiM.predict(dkiF.model_params) assert_array_almost_equal(pred, signal_gt, decimal=4) pred = dkiM.predict(dkiF.model_params, S0=100) assert_array_almost_equal(pred, signal_gt * 100, decimal=4) # Check predict of KurtosisMicrostruturalFit pred = dkiF.predict(gtab_2s, S0=100) assert_array_almost_equal(pred, signal_gt * 100, decimal=4)
def test_dki_micro_predict_multi_voxel(): dkiM = dki_micro.KurtosisMicrostructureModel(gtab_2s) dkiF = dkiM.fit(DWIsim) # Check predict of KurtosisMicrostruturalModel pred = dkiM.predict(dkiF.model_params) assert_array_almost_equal(pred, DWIsim_all_taylor, decimal=3) pred = dkiM.predict(dkiF.model_params, S0=100) assert_array_almost_equal(pred, DWIsim_all_taylor * 100, decimal=3) # Check predict of KurtosisMicrostruturalFit pred = dkiF.predict(gtab_2s, S0=100) assert_array_almost_equal(pred, DWIsim_all_taylor * 100, decimal=3)
def test_dki_micro_awf_only(): dkiM = dki_micro.KurtosisMicrostructureModel(gtab_2s) dkiF = dkiM.fit(DWIsim, awf_only=True) awf = dkiF.awf assert_almost_equal(awf, FIE, decimal=3) # assert_raises(dkiF.hindered_evals) assert_raises(ValueError, _help_test_awf_only, dkiF, 'dkimicrofit.hindered_evals') assert_raises(ValueError, _help_test_awf_only, dkiF, 'dkimicrofit.restricted_evals') assert_raises(ValueError, _help_test_awf_only, dkiF, 'dkimicrofit.axonal_diffusivity') assert_raises(ValueError, _help_test_awf_only, dkiF, 'dkimicrofit.hindered_ad') assert_raises(ValueError, _help_test_awf_only, dkiF, 'dkimicrofit.hindered_rd') assert_raises(ValueError, _help_test_awf_only, dkiF, 'dkimicrofit.tortuosity')
As mentioned above, DKI can also be used to derive concrete biophysical parameters by applying microstructural models to DT and KT estimated from DKI. For instance, Fieremans et al. [Fieremans2011]_ showed that DKI can be used to estimate the contribution of hindered and restricted diffusion for well-aligned fibers. These tensors can be also interpreted as the influences of intra- and extra-cellular compartments and can be used to estimate the axonal volume fraction and diffusion extra-cellular tortuosity. According to recent studies, these latter measures can be used to distinguish processes of axonal loss from processes of myelin degeneration [Fieremans2012]_. The model proposed by Fieremans and colleagues can be defined in DIPY by instantiating the 'KurtosisMicrostructureModel' object in the following way: """ dki_micro_model = dki_micro.KurtosisMicrostructureModel(gtab) """ Before fitting this microstructural model, it is useful to indicate the regions in which this model provides meaningful information (i.e. voxels of well-aligned fibers). Following Fieremans et al. [Fieremans2011]_, a simple way to select this region is to generate a well-aligned fiber mask based on the values of diffusion sphericity, planarity and linearity. Here we will follow these selection criteria for a better comparision of our figures with the original article published by Fieremans et al. [Fieremans2011]_. Nevertheless, it is important to note that voxels with well-aligned fibers can be selected based on other approaches such as using predefined regions of interest. """ well_aligned_mask = np.ones(data.shape[:-1], dtype='bool') # Diffusion coefficient of linearity (cl) has to be larger than 0.4, thus
def fit_dkimicro(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_micro.KurtosisMicrostructureModel(gtab) dkifit = dkimodel.fit(data, mask=mask) AWF = dkifit.awf T = dkifit.tortuosity Da = dkifit.axonal_diffusivity hRD = dkifit.hindered_rd hAD = dkifit.hindered_ad evals = dkifit.hindered_evals hMD = (evals[..., 0] + evals[..., 1] + evals[..., 2]) / 3.0 params = dkifit.model_params maps = [AWF, T, hAD, hRD, hMD, Da, params] names = ['AWF', 'T', 'hAD', 'hRD', 'hMD', 'Da', '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, 'dkimicro_%s.nii.gz' % n) nib.save(nib.Nifti1Image(m, aff), file_paths[n]) return file_paths
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 test_single_fiber_model(): # single fiber simulate (which is the assumption of our model) fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # 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) # DKI fit dkiM = dki_micro.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(signal) # Axonal Water Fraction sphere = get_sphere('symmetric724') AWF = dki_micro.axonal_water_fraction(dkiF.model_params, sphere, mask=None, gtol=1e-5) assert_almost_equal(AWF, fie) # Extra-cellular and intra-cellular components edt, idt = dki_micro.diffusion_components(dkiF.model_params, sphere) EDT = eig_from_lo_tri(edt) IDT = eig_from_lo_tri(idt) # check eigenvalues assert_array_almost_equal(EDT[0:3], np.array([ADe, RDe, RDe])) assert_array_almost_equal(IDT[0:3], np.array([ADi, RDi, RDi])) # first eigenvalue should be the direction of the fibers fiber_direction = _check_directions([(theta, phi)]) f_norm = abs(np.dot(fiber_direction, np.array((EDT[3], EDT[6], EDT[9])))) assert_almost_equal(f_norm, 1.) f_norm = abs(np.dot(fiber_direction, np.array((IDT[3], IDT[6], IDT[9])))) assert_almost_equal(f_norm, 1.) # Test model and fit objects wmtiM = dki_micro.KurtosisMicrostructureModel(gtab_2s, fit_method="WLS") wmtiF = wmtiM.fit(signal) assert_almost_equal(wmtiF.awf, AWF) assert_array_almost_equal(wmtiF.hindered_evals, np.array([ADe, RDe, RDe])) assert_array_almost_equal(wmtiF.restricted_evals, np.array([ADi, RDi, RDi])) assert_almost_equal(wmtiF.hindered_ad, ADe) assert_almost_equal(wmtiF.hindered_rd, RDe) assert_almost_equal(wmtiF.axonal_diffusivity, ADi) assert_almost_equal(wmtiF.tortuosity, ADe / RDe, decimal=4) # Test diffusion_components when a kurtosis tensors is associated with # negative kurtosis values. E.g of this cases is given below: dkiparams = np.array([ 1.67135726e-03, 5.03651205e-04, 9.35365328e-05, -7.11167583e-01, 6.23186820e-01, -3.25390313e-01, -1.75247376e-02, -4.78415563e-01, -8.77958674e-01, 7.02804064e-01, 6.18673368e-01, -3.51154825e-01, 2.18384153, -2.76378153e-02, 2.22893297, -2.68306546e-01, -1.28411610, -1.56557645e-01, -1.80850619e-01, -8.33152110e-01, -3.62410766e-01, 1.57775442e-01, 8.73775381e-01, 2.77188975e-01, -3.67415502e-02, -1.56330984e-01, -1.62295407e-02 ]) edt, idt = dki_micro.diffusion_components(dkiparams) assert_(np.all(np.isfinite(edt)))
def test_wmti_model_multi_voxel(): # DKI fit dkiM = dki_micro.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(DWIsim) # Axonal Water Fraction sphere = get_sphere() AWF = dki_micro.axonal_water_fraction(dkiF.model_params, sphere, mask=None, gtol=1e-5) assert_almost_equal(AWF, FIE) # Extra-cellular and intra-cellular components edt, idt = dki_micro.diffusion_components(dkiF.model_params, sphere) EDT = eig_from_lo_tri(edt) IDT = eig_from_lo_tri(idt) # check eigenvalues assert_array_almost_equal(EDT[..., 0], ADE, decimal=3) assert_array_almost_equal(EDT[..., 1], RDE, decimal=3) assert_array_almost_equal(EDT[..., 2], RDE, decimal=3) assert_array_almost_equal(IDT[..., 0], ADI, decimal=3) assert_array_almost_equal(IDT[..., 1], RDI, decimal=3) assert_array_almost_equal(IDT[..., 2], RDI, decimal=3) # Test methods performance when a signal with all zeros is present FIEc = FIE.copy() RDIc = RDI.copy() ADIc = ADI.copy() ADEc = ADE.copy() Torc = Tor.copy() RDEc = RDE.copy() DWIsimc = DWIsim.copy() FIEc[0, 0, 0] = 0 RDIc[0, 0, 0] = 0 ADIc[0, 0, 0] = 0 ADEc[0, 0, 0] = 0 Torc[0, 0, 0] = 0 RDEc[0, 0, 0] = 0 DWIsimc[0, 0, 0, :] = 0 mask = np.ones((2, 2, 2)) mask[0, 0, 0] = 0 dkiF = dkiM.fit(DWIsimc) awf = dki_micro.axonal_water_fraction(dkiF.model_params, sphere, gtol=1e-5) assert_almost_equal(awf, FIEc) # Extra-cellular and intra-cellular components edt, idt = dki_micro.diffusion_components(dkiF.model_params, sphere, awf=awf) EDT = eig_from_lo_tri(edt) IDT = eig_from_lo_tri(idt) assert_array_almost_equal(EDT[..., 0], ADEc, decimal=3) assert_array_almost_equal(EDT[..., 1], RDEc, decimal=3) assert_array_almost_equal(EDT[..., 2], RDEc, decimal=3) assert_array_almost_equal(IDT[..., 0], ADIc, decimal=3) assert_array_almost_equal(IDT[..., 1], RDIc, decimal=3) assert_array_almost_equal(IDT[..., 2], RDIc, decimal=3) # Check when mask is given dkiF = dkiM.fit(DWIsim) awf = dki_micro.axonal_water_fraction(dkiF.model_params, sphere, gtol=1e-5, mask=mask) assert_almost_equal(awf, FIEc, decimal=3) # Extra-cellular and intra-cellular components edt, idt = dki_micro.diffusion_components(dkiF.model_params, sphere, awf=awf, mask=mask) EDT = eig_from_lo_tri(edt) IDT = eig_from_lo_tri(idt) assert_array_almost_equal(EDT[..., 0], ADEc, decimal=3) assert_array_almost_equal(EDT[..., 1], RDEc, decimal=3) assert_array_almost_equal(EDT[..., 2], RDEc, decimal=3) assert_array_almost_equal(IDT[..., 0], ADIc, decimal=3) assert_array_almost_equal(IDT[..., 1], RDIc, decimal=3) assert_array_almost_equal(IDT[..., 2], RDIc, decimal=3) # Check class object wmtiM = dki_micro.KurtosisMicrostructureModel(gtab_2s, fit_method="WLS") wmtiF = wmtiM.fit(DWIsim, mask=mask) assert_almost_equal(wmtiF.awf, FIEc, decimal=3) assert_almost_equal(wmtiF.axonal_diffusivity, ADIc, decimal=3) assert_almost_equal(wmtiF.hindered_ad, ADEc, decimal=3) assert_almost_equal(wmtiF.hindered_rd, RDEc, decimal=3) assert_almost_equal(wmtiF.tortuosity, Torc, decimal=3)
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)