def test_MultiShellDeconvModel(): gtab = get_3shell_gtab() S0 = 1. evals = np.array([.992, .254, .254]) * 1e-3 mevals = np.array([evals, evals]) angles = [(0, 0), (60, 0)] S_wm, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[30., 70.], snr=None) S_gm = np.exp(-gtab.bvals * gm_md) S_csf = np.exp(-gtab.bvals * csf_md) sh_order = 8 response = sim_response(sh_order, [0, 1000, 2000, 3500]) model = MultiShellDeconvModel(gtab, response) vf = [1.3, .8, 1.9] signal = sum(i * j for i, j in zip(vf, [S_csf, S_gm, S_wm])) fit = model.fit(signal) npt.assert_array_almost_equal(fit.volume_fractions, vf, 0) S_pred = fit.predict() npt.assert_array_almost_equal(S_pred, signal, 0)
def test_MSDeconvFit(): gtab = get_3shell_gtab() mevals = np.array([wm_response[0, :3], wm_response[0, :3]]) angles = [(0, 0), (60, 0)] S_wm, sticks = multi_tensor(gtab, mevals, wm_response[0, 3], angles=angles, fractions=[30., 70.], snr=None) S_gm = gm_response[0, 3] * np.exp(-gtab.bvals * gm_response[0, 0]) S_csf = csf_response[0, 3] * np.exp(-gtab.bvals * csf_response[0, 0]) sh_order = 8 response = multi_shell_fiber_response(sh_order, [0, 1000, 2000, 3500], wm_response, gm_response, csf_response) model = MultiShellDeconvModel(gtab, response) vf = [0.325, 0.2, 0.475] signal = sum(i * j for i, j in zip(vf, [S_csf, S_gm, S_wm])) fit = model.fit(signal) # Testing volume fractions npt.assert_array_almost_equal(fit.volume_fractions, vf, 1)
def test_mcsd_model_delta(): sh_order = 8 gtab = get_3shell_gtab() shells = np.unique(gtab.bvals // 100.) * 100. response = sim_response(sh_order, shells, evals_d) model = MultiShellDeconvModel(gtab, response) iso = response.iso theta, phi = default_sphere.theta, default_sphere.phi B = shm.real_sph_harm(response.m, response.n, theta[:, None], phi[:, None]) wm_delta = model.delta.copy() # set isotropic components to zero wm_delta[:iso] = 0. wm_delta = _expand(model.m, iso, wm_delta) for i, s in enumerate(shells): g = GradientTable(default_sphere.vertices * s) signal = model.predict(wm_delta, g) expected = np.dot(response.response[i, iso:], B.T) npt.assert_array_almost_equal(signal, expected) signal = model.predict(wm_delta, gtab) fit = model.fit(signal) m = model.m npt.assert_array_almost_equal(fit.shm_coeff[m != 0], 0., 2)
def test_mcsd_model_delta(): sh_order = 8 gtab = get_3shell_gtab() response = multi_shell_fiber_response(sh_order, [0, 1000, 2000, 3500], wm_response, gm_response, csf_response) model = MultiShellDeconvModel(gtab, response) iso = response.iso theta, phi = default_sphere.theta, default_sphere.phi B = shm.real_sh_descoteaux_from_index( response.m, response.n, theta[:, None], phi[:, None]) wm_delta = model.delta.copy() # set isotropic components to zero wm_delta[:iso] = 0. wm_delta = _expand(model.m, iso, wm_delta) for i, s in enumerate([0, 1000, 2000, 3500]): g = GradientTable(default_sphere.vertices * s) signal = model.predict(wm_delta, g) expected = np.dot(response.response[i, iso:], B.T) npt.assert_array_almost_equal(signal, expected) signal = model.predict(wm_delta, gtab) fit = model.fit(signal) m = model.m npt.assert_array_almost_equal(fit.shm_coeff[m != 0], 0., 2)
def test_MSDeconvFit(): gtab = get_3shell_gtab() mevals = np.array([wm_response[0, :3], wm_response[0, :3]]) angles = [(0, 0), (60, 0)] S_wm, sticks = multi_tensor(gtab, mevals, wm_response[0, 3], angles=angles, fractions=[30., 70.], snr=None) S_gm = gm_response[0, 3] * np.exp(-gtab.bvals * gm_response[0, 0]) S_csf = csf_response[0, 3] * np.exp(-gtab.bvals * csf_response[0, 0]) sh_order = 8 with warnings.catch_warnings(): warnings.filterwarnings( "ignore", message=shm.descoteaux07_legacy_msg, category=PendingDeprecationWarning) response = multi_shell_fiber_response(sh_order, [0, 1000, 2000, 3500], wm_response, gm_response, csf_response) model = MultiShellDeconvModel(gtab, response) vf = [0.325, 0.2, 0.475] signal = sum(i * j for i, j in zip(vf, [S_csf, S_gm, S_wm])) fit = model.fit(signal) # Testing volume fractions npt.assert_array_almost_equal(fit.volume_fractions, vf, 1)
def create_mcsd_model(folder_name, data, gtab, labels, sh_order=8): from dipy.reconst.mcsd import response_from_mask_msmt from dipy.reconst.mcsd import MultiShellDeconvModel, multi_shell_fiber_response, MSDeconvFit from dipy.core.gradients import unique_bvals_tolerance bvals = gtab.bvals wm = labels == 3 gm = labels == 2 csf = labels == 1 mask_wm = wm.astype(float) mask_gm = gm.astype(float) mask_csf = csf.astype(float) response_wm, response_gm, response_csf = response_from_mask_msmt( gtab, data, mask_wm, mask_gm, mask_csf) ubvals = unique_bvals_tolerance(bvals) response_mcsd = multi_shell_fiber_response(sh_order, bvals=ubvals, wm_rf=response_wm, csf_rf=response_csf, gm_rf=response_gm) mcsd_model = MultiShellDeconvModel(gtab, response_mcsd) mcsd_fit = mcsd_model.fit(data) sh_coeff = mcsd_fit.all_shm_coeff nan_count = len(np.argwhere(np.isnan(sh_coeff[..., 0]))) coeff = mcsd_fit.all_shm_coeff n_vox = coeff.shape[0] * coeff.shape[1] * coeff.shape[2] if nan_count > 0: print( f'{nan_count / n_vox} of the voxels did not complete fodf calculation, NaN values replaced with 0' ) coeff = np.where(np.isnan(coeff), 0, coeff) mcsd_fit = MSDeconvFit(mcsd_model, coeff, None) np.save(folder_name + r'\coeff.npy', coeff) return mcsd_fit
def _msmt_ft(self): from dipy.reconst.mcsd import response_from_mask_msmt from dipy.reconst.mcsd import MultiShellDeconvModel, multi_shell_fiber_response, MSDeconvFit from dipy.core.gradients import unique_bvals_tolerance bvals = self.gtab.bvals wm = self.tissue_labels == 2 gm = self.tissue_labels == 1 csf = self.tissue_labels == 3 mask_wm = wm.astype(float) mask_gm = gm.astype(float) mask_csf = csf.astype(float) response_wm, response_gm, response_csf = response_from_mask_msmt( self.gtab, self.data, mask_wm, mask_gm, mask_csf) ubvals = unique_bvals_tolerance(bvals) response_mcsd = multi_shell_fiber_response( self.parameters_dict['sh_order'], bvals=ubvals, wm_rf=response_wm, csf_rf=response_csf, gm_rf=response_gm) mcsd_model = MultiShellDeconvModel(self.gtab, response_mcsd) mcsd_fit = mcsd_model.fit(self.data) sh_coeff = mcsd_fit.all_shm_coeff nan_count = len(np.argwhere(np.isnan(sh_coeff[..., 0]))) coeff = mcsd_fit.all_shm_coeff n_vox = coeff.shape[0] * coeff.shape[1] * coeff.shape[2] if nan_count > 0: print( f'{nan_count / n_vox} of the voxels did not complete fodf calculation, NaN values replaced with 0' ) coeff = np.where(np.isnan(coeff), 0, coeff) mcsd_fit = MSDeconvFit(mcsd_model, coeff, None) self.model_fit = mcsd_fit
mask_wm = wm.astype(float) mask_gm = gm.astype(float) mask_csf = csf.astype(float) response_wm, response_gm, response_csf = response_from_mask_msmt( gtab, data, mask_wm, mask_gm, mask_csf) ubvals = unique_bvals_tolerance(bvals) response_mcsd = multi_shell_fiber_response(sh_order=8, bvals=ubvals, wm_rf=response_wm, csf_rf=response_csf, gm_rf=response_gm) mcsd_model = MultiShellDeconvModel(gtab, response_mcsd) mcsd_fit = mcsd_model.fit(denoised_arr) sh_coeff = mcsd_fit.all_shm_coeff nan_count = len(np.argwhere(np.isnan(sh_coeff[..., 0]))) coeff = mcsd_fit.all_shm_coeff n_vox = coeff.shape[0] * coeff.shape[1] * coeff.shape[2] print( f'{nan_count/n_vox} of the voxels did not complete fodf calculation, NaN values replaced with 0' ) coeff = np.where(np.isnan(coeff), 0, coeff) mcsd_fit = MSDeconvFit(mcsd_model, coeff, None) np.save(folder_name + r'\coeff.npy', coeff) gtab, data, affine, labels, white_matter, nii_file, bvec_file = load_dwi_files( folder_name) fa, classifier = create_fa_classifier(gtab, data, white_matter) lab_labels_index = nodes_by_index_general(folder_name, atlas='yeo7_200')[0]
def mcsd_mod_est(gtab, data, B0_mask, wm_in_dwi, gm_in_dwi, vent_csf_in_dwi, sh_order=8, roi_radii=10): """ Estimate a Constrained Spherical Deconvolution (CSD) model from dwi data. Parameters ---------- gtab : Obj DiPy object storing diffusion gradient information. data : array 4D numpy array of diffusion image data. B0_mask : str File path to B0 brain mask. sh_order : int The order of the SH model. Default is 8. Returns ------- csd_mod : ndarray Coefficients of the csd reconstruction. model : obj Fitted csd model. References ---------- .. [1] Tournier, J.D., et al. NeuroImage 2007. Robust determination of the fibre orientation distribution in diffusion MRI: Non-negativity constrained super-resolved spherical deconvolution .. [2] Descoteaux, M., et al. IEEE TMI 2009. Deterministic and Probabilistic Tractography Based on Complex Fibre Orientation Distributions .. [3] Côté, M-A., et al. Medical Image Analysis 2013. Tractometer: Towards validation of tractography pipelines .. [4] Tournier, J.D, et al. Imaging Systems and Technology 2012. MRtrix: Diffusion Tractography in Crossing Fiber Regions """ import dipy.reconst.dti as dti from nilearn.image import math_img from dipy.core.gradients import unique_bvals_tolerance from dipy.reconst.mcsd import (mask_for_response_msmt, response_from_mask_msmt, multi_shell_fiber_response, MultiShellDeconvModel) print("Reconstructing using MCSD...") B0_mask_data = np.nan_to_num(np.asarray( nib.load(B0_mask).dataobj)).astype("bool") # Load tissue maps and prepare tissue classifier gm_mask_img = math_img("img > 0.10", img=gm_in_dwi) gm_data = np.asarray(gm_mask_img.dataobj, dtype=np.float32) wm_mask_img = math_img("img > 0.15", img=wm_in_dwi) wm_data = np.asarray(wm_mask_img.dataobj, dtype=np.float32) vent_csf_in_dwi_img = math_img("img > 0.50", img=vent_csf_in_dwi) vent_csf_in_dwi_data = np.asarray(vent_csf_in_dwi_img.dataobj, dtype=np.float32) # Fit a simple DTI model tenfit = dti.TensorModel(gtab).fit(data) # Obtain the FA and MD metrics FA = tenfit.fa MD = tenfit.md indices_csf = np.where(((FA < 0.2) & (vent_csf_in_dwi_data > 0.50))) indices_gm = np.where(((FA < 0.2) & (gm_data > 0.10))) indices_wm = np.where(((FA >= 0.2) & (wm_data > 0.15))) selected_csf = np.zeros(FA.shape, dtype='bool') selected_gm = np.zeros(FA.shape, dtype='bool') selected_wm = np.zeros(FA.shape, dtype='bool') selected_csf[indices_csf] = True selected_gm[indices_gm] = True selected_wm[indices_wm] = True mask_wm, mask_gm, mask_csf = mask_for_response_msmt( gtab, data, roi_radii=roi_radii, wm_fa_thr=np.nanmean(FA[selected_wm]), gm_fa_thr=np.nanmean(FA[selected_gm]), csf_fa_thr=np.nanmean(FA[selected_csf]), gm_md_thr=np.nanmean(MD[selected_gm]), csf_md_thr=np.nanmean(MD[selected_csf])) mask_wm *= wm_data.astype('int64') mask_gm *= gm_data.astype('int64') mask_csf *= vent_csf_in_dwi_data.astype('int64') # nvoxels_wm = np.sum(mask_wm) # nvoxels_gm = np.sum(mask_gm) # nvoxels_csf = np.sum(mask_csf) response_wm, response_gm, response_csf = response_from_mask_msmt( gtab, data, mask_wm, mask_gm, mask_csf) response_mcsd = multi_shell_fiber_response(sh_order=8, bvals=unique_bvals_tolerance( gtab.bvals), wm_rf=response_wm, gm_rf=response_gm, csf_rf=response_csf) model = MultiShellDeconvModel(gtab, response_mcsd, sh_order=sh_order) mcsd_mod = model.fit(data, B0_mask_data).shm_coeff mcsd_mod = np.clip(mcsd_mod, 0, np.max(mcsd_mod, -1)[..., None]) del response_mcsd, B0_mask_data return mcsd_mod.astype("float32"), model
""" response = np.array([response_wm, response_gm, response_csf]) mcsd_model_simple_response = MultiShellDeconvModel(gtab, response, sh_order=8) """ Note that this technique only works for a 3 compartments model (wm, gm, csf). If one wants more compartments, a custom MultiShellResponse object must be used. It can be inspired by the ``multi_shell_fiber_response`` method. """ """ Now we build the MSMT-CSD model with the ``response_mcsd`` as input. We then call the ``fit`` function to fit one slice of the 3D data and visualize it. """ mcsd_model = MultiShellDeconvModel(gtab, response_mcsd) mcsd_fit = mcsd_model.fit(denoised_arr[:, :, 10:11]) """ The volume fractions of tissues for each voxel are also accessible, as well as the sh coefficients for all tissues. One can also get each sh tissue separately using ``all_shm_coeff`` for each compartment (isotropic) and ``shm_coeff`` for white matter. """ vf = mcsd_fit.volume_fractions sh_coeff = mcsd_fit.all_shm_coeff csf_sh_coeff = sh_coeff[..., 0] gm_sh_coeff = sh_coeff[..., 1] wm_sh_coeff = mcsd_fit.shm_coeff """ The model allows to predict a signal from sh coefficients. There are two ways of doing this.