def test_dti_xval(): data = load_nifti_data(fdata) gtab = gt.gradient_table(fbval, fbvec) dm = dti.TensorModel(gtab, 'LS') # The data has 102 directions, so will not divide neatly into 10 bits npt.assert_raises(ValueError, xval.kfold_xval, dm, data, 10) # In simulation with no noise, COD should be perfect: psphere = dpd.get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = gt.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ] S = sims.single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') kf_xval = xval.kfold_xval(dm, S, 2) cod = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(cod, np.ones(kf_xval.shape[:-1]) * 100) # Test with 2D data for use of a mask S = np.array([[S, S], [S, S]]) mask = np.ones(S.shape[:-1], dtype=bool) mask[1, 1] = 0 kf_xval = xval.kfold_xval(dm, S, 2, mask=mask) cod2d = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(np.round(cod2d[0, 0]), cod)
def test_predict(): """ Test model prediction API """ psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[1, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]])] S = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) assert_array_almost_equal(dmfit.predict(gtab, S0=100), S) assert_array_almost_equal(dm.predict(dmfit.model_params, S0=100), S) fdata, fbvals, fbvecs = get_data() data = nib.load(fdata).get_data() # Make the data cube a bit larger: data = np.tile(data.T, 2).T gtab = grad.gradient_table(fbvals, fbvecs) dtim = dti.TensorModel(gtab) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0) assert_equal(p.shape, data.shape)
def test_dti_xval(): """ Test k-fold cross-validation """ data = nib.load(fdata).get_data() gtab = gt.gradient_table(fbval, fbvec) dm = dti.TensorModel(gtab, 'LS') # The data has 102 directions, so will not divide neatly into 10 bits npt.assert_raises(ValueError, xval.kfold_xval, dm, data, 10) # But we can do this with 2 folds: kf_xval = xval.kfold_xval(dm, data, 2) # In simulation with no noise, COD should be perfect: psphere = dpd.get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = gt.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ] S = sims.single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) kf_xval = xval.kfold_xval(dm, S, 2) cod = xval.coeff_of_determination(S, kf_xval) npt.assert_array_almost_equal(cod, np.ones(kf_xval.shape[:-1]) * 100)
def test_mask(): data, gtab = dsi_voxels() dm = dti.TensorModel(gtab, 'LS') mask = np.zeros(data.shape[:-1], dtype=bool) mask[0, 0, 0] = True dtifit = dm.fit(data) dtifit_w_mask = dm.fit(data, mask=mask) # Without a mask it has some value assert_(not np.isnan(dtifit.fa[0, 0, 0])) # Where mask is False, evals, evecs and fa should all be 0 assert_array_equal(dtifit_w_mask.evals[~mask], 0) assert_array_equal(dtifit_w_mask.evecs[~mask], 0) assert_array_equal(dtifit_w_mask.fa[~mask], 0) # Except for the one voxel that was selected by the mask: assert_almost_equal(dtifit_w_mask.fa[0, 0, 0], dtifit.fa[0, 0, 0]) # Test with returning S0_hat dm = dti.TensorModel(gtab, 'LS', return_S0_hat=True) mask = np.zeros(data.shape[:-1], dtype=bool) mask[0, 0, 0] = True dtifit = dm.fit(data) dtifit_w_mask = dm.fit(data, mask=mask) # Without a mask it has some value assert_(not np.isnan(dtifit.fa[0, 0, 0])) # Where mask is False, evals, evecs and fa should all be 0 assert_array_equal(dtifit_w_mask.evals[~mask], 0) assert_array_equal(dtifit_w_mask.evecs[~mask], 0) assert_array_equal(dtifit_w_mask.fa[~mask], 0) assert_array_equal(dtifit_w_mask.S0_hat[~mask], 0) # Except for the one voxel that was selected by the mask: assert_almost_equal(dtifit_w_mask.fa[0, 0, 0], dtifit.fa[0, 0, 0]) assert_almost_equal(dtifit_w_mask.S0_hat[0, 0, 0], dtifit.S0_hat[0, 0, 0])
def test_predict(): """ Test model prediction API """ psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[1, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ] S = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) assert_array_almost_equal(dmfit.predict(gtab, S0=100), S) assert_array_almost_equal(dm.predict(dmfit.model_params, S0=100), S) data, gtab = dsi_voxels() dtim = dti.TensorModel(gtab) dtif = dtim.fit(data) S0 = np.mean(data[..., gtab.b0s_mask], -1) p = dtif.predict(gtab, S0)
def test_restore(): """ Test the implementation of the RESTORE algorithm """ b0 = 1000. bvecs, bval = read_bvec_file(get_data('55dir_grad.bvec')) gtab = grad.gradient_table(bval, bvecs) B = bval[1] # Scale the eigenvalues and tensor by the B value so the units match D = np.array([1., 1., 1., 0., 0., 1., -np.log(b0) * B]) / B evals = np.array([2., 1., 0.]) / B tensor = from_lower_triangular(D) # Design Matrix X = dti.design_matrix(gtab) # Signals Y = np.exp(np.dot(X, D)) Y.shape = (-1, ) + Y.shape for drop_this in range(1, Y.shape[-1]): for jac in [True, False]: # RESTORE estimates should be robust to dropping this_y = Y.copy() this_y[:, drop_this] = 1.0 for sigma in [67.0, np.ones(this_y.shape[-1]) * 67.0]: tensor_model = dti.TensorModel(gtab, fit_method='restore', jac=jac, sigma=67.0) tensor_est = tensor_model.fit(this_y) assert_array_almost_equal(tensor_est.evals[0], evals, decimal=3) assert_array_almost_equal(tensor_est.quadratic_form[0], tensor, decimal=3) # If sigma is very small, it still needs to work: tensor_model = dti.TensorModel(gtab, fit_method='restore', sigma=0.0001) tensor_model.fit(Y.copy()) # Test return_S0_hat tensor_model = dti.TensorModel(gtab, fit_method='restore', sigma=0.0001, return_S0_hat=True) tmf = tensor_model.fit(Y.copy()) assert_almost_equal(tmf[0].S0_hat, b0)
def test_nlls_fit_tensor(): """ Test the implementation of NLLS and RESTORE """ b0 = 1000. bvecs, bval = read_bvec_file(get_data('55dir_grad.bvec')) gtab = grad.gradient_table(bval, bvecs) B = bval[1] #Scale the eigenvalues and tensor by the B value so the units match D = np.array([1., 1., 1., 0., 0., 1., -np.log(b0) * B]) / B evals = np.array([2., 1., 0.]) / B md = evals.mean() tensor = from_lower_triangular(D) #Design Matrix X = dti.design_matrix(bvecs, bval) #Signals Y = np.exp(np.dot(X,D)) Y.shape = (-1,) + Y.shape #Estimate tensor from test signals and compare against expected result #using non-linear least squares: tensor_model = dti.TensorModel(gtab, fit_method='NLLS') tensor_est = tensor_model.fit(Y) assert_equal(tensor_est.shape, Y.shape[:-1]) assert_array_almost_equal(tensor_est.evals[0], evals) assert_array_almost_equal(tensor_est.quadratic_form[0], tensor) assert_almost_equal(tensor_est.md[0], md) # Using the gmm weighting scheme: tensor_model = dti.TensorModel(gtab, fit_method='NLLS', weighting='gmm') assert_equal(tensor_est.shape, Y.shape[:-1]) assert_array_almost_equal(tensor_est.evals[0], evals) assert_array_almost_equal(tensor_est.quadratic_form[0], tensor) assert_almost_equal(tensor_est.md[0], md) # Use NLLS with some actual 4D data: data, bvals, bvecs = get_data('small_25') gtab = grad.gradient_table(bvals, bvecs) tm1 = dti.TensorModel(gtab, fit_method='NLLS') dd = nib.load(data).get_data() tf1 = tm1.fit(dd) tm2 = dti.TensorModel(gtab) tf2 = tm2.fit(dd) assert_array_almost_equal(tf1.fa, tf2.fa, decimal=1)
def test_all_zeros(): bvecs, bvals = read_bvec_file(get_data('55dir_grad.bvec')) gtab = grad.gradient_table_from_bvals_bvecs(bvals, bvecs.T) fit_methods = ['LS', 'OLS', 'NNLS', 'RESTORE'] for fit_method in fit_methods: dm = dti.TensorModel(gtab) assert_raises(ValueError, dm.fit, np.zeros(bvals.shape[0]))
def tensor_fitting(data, bvals, bvecs, mask_file=None): """ Use dipy to fit DTI Parameters ---------- in_file : str Full path to a DWI data file. bvals : str Full path to a file containing gradient magnitude information (b-values). bvecs : str Full path to a file containing gradient direction information (b-vectors). mask_file : str, optional Full path to a file containing a binary mask. Defaults to use the entire volume. Returns ------- TensorFit object, affine """ img = nb.load(in_file).get_data() data = img.get_data() affine = img.get_affine() if mask_file is not None: mask = nb.load(self.inputs.mask_file).get_data() else: mask = None # Load information about the gradients: gtab = grad.gradient_table(self.inputs.bvals, self.inputs.bvecs) # Fit it tenmodel = dti.TensorModel(gtab) return tenmodel.fit(data, mask), affine
def D_init(Sk, S0, bval, bvecs, f0, Diso): """ initializes the tensor components with regular DTI """ # Correcting Sk for fwater A_water = np.exp(-bval * Diso) C_water = (1 - f0) * A_water # At = (Ak - C_water[..., np.newaxis]) / f0[..., np.newaxis] # At = np.clip(At, 0.0001, 1 - 0.0001) St = Sk - S0 * C_water[..., np.newaxis] # using alternative init # creating new gtab and data x, y, z, k = St.shape bvals = bval * np.ones(k) bvals = np.insert(bvals, 0, 0) bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) gtab = gradient_table(bvals, bvecs) init_data = np.zeros((x, y, z, k + 1)) init_data[..., 0] = S0[..., 0] init_data[..., 1:] = St # fitting model = dti.TensorModel(gtab) fit = model.fit(init_data) qform = fit.quadratic_form Dxx = qform[..., 0, 0] Dyy = qform[..., 1, 1] Dzz = qform[..., 2, 2] Dxy = qform[..., 0, 1] Dxz = qform[..., 0, 2] Dyz = qform[..., 1, 2] return (Dxx, Dyy, Dzz, Dxy, Dxz, Dyz)
def get_FA_MD(): time0 = time.time() data, affine = load_nifti('normalized_pDWI.nii.gz') bvals, bvecs = read_bvals_bvecs('DWI.bval', 'DWI.bvec') gtab = gradient_table(bvals, bvecs) #head_mask = load_nifti_data(data_path + '/' + brain_mask) print(data.shape) print('begin modeling!, time:', time.time() - time0) tenmodel = dti.TensorModel(gtab) tenfit = tenmodel.fit(data) from dipy.reconst.dti import fractional_anisotropy print('begin calculating FA!, time:', time.time() - time0) FA = fractional_anisotropy(tenfit.evals) FA[np.isnan(FA)] = 0 #FA = FA * head_mask save_nifti('FA.nii.gz', FA.astype(np.float32), affine) # print('begin calculating MD!, time:', time.time() - time0) MD1 = dti.mean_diffusivity(tenfit.evals) #MD1 = MD1*head_mask save_nifti('MD.nii.gz', MD1.astype(np.float32), affine) print('Over!, time:', time.time() - time0) return FA, MD1
def test_adc(): """ Test the implementation of the calculation of apparent diffusion coefficient """ data, gtab = dsi_voxels() dm = dti.TensorModel(gtab, 'LS') mask = np.zeros(data.shape[:-1], dtype=bool) mask[0, 0, 0] = True dtifit = dm.fit(data) # The ADC in the principal diffusion direction should be equal to the AD in # each voxel: pdd0 = dtifit.evecs[0, 0, 0, 0] sphere_pdd0 = dps.Sphere(x=pdd0[0], y=pdd0[1], z=pdd0[2]) npt.assert_array_almost_equal(dtifit.adc(sphere_pdd0)[0, 0, 0], dtifit.ad[0, 0, 0], decimal=5) # Test that it works for cases in which the data is 1D dtifit = dm.fit(data[0, 0, 0]) sphere_pdd0 = dps.Sphere(x=pdd0[0], y=pdd0[1], z=pdd0[2]) npt.assert_array_almost_equal(dtifit.adc(sphere_pdd0), dtifit.ad, decimal=5)
def fit_dti(dwi): """Fit a DTI 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 : TensorFit A fit from which parameter maps can be generated """ dtimodel = dti.TensorModel(dwi.gtab) data = dwi.get_image() try: mask = dwi.mask except AttributeError: mask = np.ones(data.shape[:3]) return dtimodel.fit(data, mask)
def main(dti_file, bvals_file, bvecs_file, b_ss=1000): # Load the image data nii = nib.load(dti_file) img_data = nii.get_data() # Read in the b-shell values and gradient directions bvals, bvecs = read_bvals_bvecs(bvals_file, bvecs_file) # Boolean array to identify entries with either b = 0 or b = b_ss bvals_eq_0_b_ss = (bvals == 0) | (bvals == b_ss) # Extract info needed to run single-compartment dti model dti_bvals = bvals[bvals_eq_0_b_ss].copy() dti_bvecs = bvecs[bvals_eq_0_b_ss].copy() dti_img_data = img_data[:, :, :, bvals_eq_0_b_ss].copy() # Compute gradient table grad_table = gradient_table(dti_bvals, dti_bvecs) # Extract brain so we don't fit the background brain_img_data, brain_mask = median_otsu(dti_img_data, 2, 1) # Run the dti model and fit it to the brain extracted image data ten_model = dti.TensorModel(grad_table) ten_fit = ten_model.fit(brain_img_data)
def model_params(self): """ The diffusion tensor parameters estimated from the data, using dipy. If this calculation has already occurred, just load the data from a nifti file, which has shape x by y by z by 12, where the last dimension is the model params: evecs (9) + evals (3) """ out = ozu.nans((self.data.shape[:3] + (12, ))) flat_params = np.empty((self._flat_S0.shape[0], 12)) # The file already exists: if os.path.isfile(self.params_file): if self.verbose: print("Loading TensorModel params from: %s" % self.params_file) out[self.mask] = ni.load(self.params_file).get_data()[self.mask] else: if self.verbose: print("Fitting TensorModel params using dipy") tensor_model = dti.TensorModel(self.gtab, fit_method=self.fit_method) for vox, vox_data in enumerate(self.data[self.mask]): flat_params[vox] = tensor_model.fit(vox_data).model_params out[self.mask] = flat_params # Save the params for future use: params_ni = ni.Nifti1Image(out, self.affine) # If we asked it to be temporary, no need to save anywhere: if self.params_file != 'temp': params_ni.to_filename(self.params_file) # And return the params for current use: return out
def _run_interface(self, runtime): ## Load the 4D image files img = nb.load(self.inputs.in_file) data = img.get_data() affine = img.get_affine() ## Load the gradient strengths and directions bvals = np.loadtxt(self.inputs.bvals) gradients = np.loadtxt(self.inputs.bvecs).T ## Place in Dipy's preferred format gtab = GradientTable(gradients) gtab.bvals = bvals ## Mask the data so that tensors are not fit for ## unnecessary voxels mask = data[..., 0] > 50 ## Fit the tensors to the data tenmodel = dti.TensorModel(gtab) tenfit = tenmodel.fit(data, mask) ## Calculate the mode of each voxel's tensor mode_data = tenfit.mode ## Write as a 3D Nifti image with the original affine img = nb.Nifti1Image(mode_data, affine) out_file = op.abspath(self._gen_outfilename()) nb.save(img, out_file) iflogger.info('Tensor mode image saved as {i}'.format(i=out_file)) return runtime
def model_building_stand_alone_tf(path): img = nib.load(path + "/100307_data_tiny.nii.gz") data = img.get_data() img_mask = nib.load(path + "/100307_mask.nii.gz") mask = img_mask.get_data().astype(np.bool) gtab = dpg.gradient_table(path + '/100307_bvals_tiny', path + '/100307_bvecs_tiny', b0_threshold=10) data_in_mask = np.reshape(data[mask], (-1, data.shape[-1])) data_in_mask = np.maximum(data_in_mask, MIN_POSITIVE_SIGNAL) ten_model = dti.TensorModel(gtab) design_matrix = ten_model.design_matrix print(data_in_mask.shape, design_matrix.shape) sess = tf.InteractiveSession() params_in_mask = model_building(data_in_mask, design_matrix).eval() params_in_mask = params_in_mask.reshape(params_in_mask.shape[0], 12) dti_params = np.zeros(data.shape[:-1] + (12, )) dti_params[mask, :] = params_in_mask evals = dti_params[..., :3] evals = _roll_evals(evals, -1) all_zero = (evals == 0).all(axis=0) ev1, ev2, ev3 = evals fa = np.sqrt(0.5 * ((ev1 - ev2)**2 + (ev2 - ev3)**2 + (ev3 - ev1)**2) / ((evals * evals).sum(0) + all_zero)) return fa
def _init_odf(self, odf_mode): print("Initialising ODF") # fit DTI model to data if odf_mode == "DTI": print("DTI-based ODF computation") dti_model = dti.TensorModel(self.dataset.gtab, fit_method='LS') dti_fit = dti_model.fit(self.dataset.dwi, mask=self.dataset.binary_mask) # compute ODF odf = dti_fit.odf(self.sphere) elif odf_mode == "CSD": print("CSD-based ODF computation") mask = mask_for_response_ssst(self.dataset.gtab, self.dataset.dwi, roi_radii=10, fa_thr=0.7) response, ratio = response_from_mask_ssst(self.dataset.gtab, self.dataset.dwi, mask) dti_model = ConstrainedSphericalDeconvModel( self.dataset.gtab, response) dti_fit = dti_model.fit(self.dataset.dwi) odf = dti_fit.odf(self.sphere) else: raise NotImplementedError("ODF mode not found") # -- set up interpolator for odf evaluation odf = torch.from_numpy(odf).to(device=self.device).float() self.odf_interpolator = TorchGridInterpolator(odf)
def to_estimate_dti(file_in, file_inMask, outPath, fbval, fbvec): print(d.separador + 'building DTI Model...') ref_name = utils.to_extract_filename(file_in) if ( not (os.path.exists(outPath + ref_name + d.id_evecs + d.extension)) ) | (not (os.path.exists(outPath + ref_name + d.id_evals + d.extension))): try: os.remove(outPath + ref_name + d.id_evecs + d.extension) os.remove(outPath + ref_name + d.id_evals + d.extension) except: print("Unexpected error:", sys.exc_info()[0]) img = nib.load(file_in) data = img.get_data() mask = nib.load(file_inMask) mask = mask.get_data() bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) tensor_model = dti.TensorModel(gtab) tensor_fitted = tensor_model.fit(data, mask) nib.save( nib.Nifti1Image(tensor_fitted.evecs.astype(np.float32), img.affine), outPath + ref_name + d.id_evecs + d.extension) nib.save( nib.Nifti1Image(tensor_fitted.evals.astype(np.float32), img.affine), outPath + ref_name + d.id_evals + d.extension) return outPath + ref_name + d.id_evecs + d.extension, outPath + ref_name + d.id_evals + d.extension
def _init_odf(self): print("Initialising ODF") # fit DTI model to data if self.odf_mode == "DTI": print("DTI-based ODF computation") self.dti_model = dti.TensorModel(self.dataset.gtab, fit_method='LS') self.dti_fit = self.dti_model.fit(self.dataset.dwi, mask=self.dataset.binary_mask) # compute ODF odf = self.dti_fit.odf(self.sphere_odf) elif self.odf_mode == "CSD": print("CSD-based ODF computation") mask = mask_for_response_ssst(self.dataset.gtab, self.dataset.dwi, roi_radii=10, fa_thr=0.7) num_voxels = np.sum(mask) print(num_voxels) response, ratio = response_from_mask_ssst(self.dataset.gtab, self.dataset.dwi, mask) print(response) self.dti_model = ConstrainedSphericalDeconvModel( self.dataset.gtab, response) self.dti_fit = self.dti_model.fit(self.dataset.dwi) odf = self.dti_fit.odf(self.sphere_odf) # -- set up interpolator for odf evaluation x_range = np.arange(odf.shape[0]) y_range = np.arange(odf.shape[1]) z_range = np.arange(odf.shape[2]) self.odf_interpolator = RegularGridInterpolator( (x_range, y_range, z_range), odf)
def test_bdg_initial_direction(): """This test the number of inital direction." """ hsph_updated = HemiSphere.from_sphere(unit_icosahedron).subdivide(2) vertices = hsph_updated.vertices bvecs = vertices bvals = np.ones(len(vertices)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) # test that we get one direction when we have a single tensor voxel = single_tensor(gtab).reshape([1, 1, 1, -1]) dti_model = dti.TensorModel(gtab) boot_dg = BootDirectionGetter.from_data(voxel, dti_model, 30, sh_order=6) initial_direction = boot_dg.initial_direction(np.zeros(3)) npt.assert_equal(len(initial_direction), 1) npt.assert_allclose(initial_direction[0], [1, 0, 0], atol=0.1) # test that we get multiple directions when we have a multi-tensor mevals = np.array([[1.5, 0.4, 0.4], [1.5, 0.4, 0.4]]) * 1e-3 fracs = [60, 40] voxel, primary_evecs = multi_tensor(gtab, mevals, fractions=fracs, snr=None) voxel = voxel.reshape([1, 1, 1, -1]) response = (np.array([0.0015, 0.0004, 0.0004]), 1) csd_model = ConstrainedSphericalDeconvModel(gtab, response=response, sh_order=4) boot_dg = BootDirectionGetter.from_data(voxel, csd_model, 30) initial_direction = boot_dg.initial_direction(np.zeros(3)) npt.assert_equal(len(initial_direction), 2) npt.assert_allclose(initial_direction, primary_evecs, atol=0.1)
def _run_interface(self, runtime): gtab = self._get_gtab() dwi_img = nb.load(self.inputs.dwi_file) dwi_data = dwi_img.get_fdata(dtype=np.float32) mask_img, mask_array = self._get_mask(dwi_img, gtab) # Fit it tenmodel = dti.TensorModel(gtab) ten_fit = tenmodel.fit(dwi_data, mask_array) lower_triangular = ten_fit.lower_triangular() tensor_img = nifti1_symmat(lower_triangular, dwi_img.affine) output_tensor_file = fname_presuffix(self.inputs.dwi_file, suffix='tensor', newpath=runtime.cwd, use_ext=True) tensor_img.to_filename(output_tensor_file) # FA MD RD and AD for metric in ["fa", "md", "rd", "ad", "color_fa"]: data = getattr(ten_fit, metric).astype("float32") out_name = fname_presuffix(self.inputs.dwi_file, suffix=metric, newpath=runtime.cwd, use_ext=True) nb.Nifti1Image(data, dwi_img.affine).to_filename(out_name) self._results[metric + "_image"] = out_name return runtime
def _init_odf(self): print("Initialising ODF") # fit DTI model to data if self.odf_mode == "DTI": print("DTI-based ODF computation") self.dti_model = dti.TensorModel(self.dataset.gtab, fit_method='LS') self.dti_fit = self.dti_model.fit(self.dataset.dwi, mask=self.dataset.binary_mask) # compute ODF odf = self.dti_fit.odf(self.sphere_odf) elif self.odf_mode == "CSD": print("CSD-based ODF computation") mask = mask_for_response_ssst(self.dataset.gtab, self.dataset.dwi, roi_radii=10, fa_thr=0.7) num_voxels = np.sum(mask) print(num_voxels) response, ratio = response_from_mask_ssst(self.dataset.gtab, self.dataset.dwi, mask) print(response) self.dti_model = ConstrainedSphericalDeconvModel( self.dataset.gtab, response) self.dti_fit = self.dti_model.fit(self.dataset.dwi) odf = self.dti_fit.odf(self.sphere_odf) # -- set up interpolator for odf evaluation odf = torch.from_numpy(odf).to(device=self.device).float() self.odf_interpolator = TorchGridInterpolator(odf) print("..done!")
def test_all_zeros(): bvecs, bvals = read_bvec_file(get_data('55dir_grad.bvec')) gtab = grad.gradient_table_from_bvals_bvecs(bvals, bvecs.T) fit_methods = ['LS', 'OLS', 'NNLS', 'RESTORE'] for fit_method in fit_methods: dm = dti.TensorModel(gtab) assert_array_almost_equal(dm.fit(np.zeros(bvals.shape[0])).evals, 0)
def track(self): SeedBasedTracker.track(self) if self.streamlines is not None: return roi_r = Config.get_config().getint("CSDTracking", "autoResponseRoiRadius", fallback="10") fa_thr = Config.get_config().getfloat("CSDTracking", "autoResponseFaThreshold", fallback="0.7") response, _ = auto_response_ssst(self.data.gtab, self.data.dwi, roi_radii=roi_r, fa_thr=fa_thr) csd_model = ConstrainedSphericalDeconvModel(self.data.gtab, response) relative_peak_thr = Config.get_config().getfloat("CSDTracking", "relativePeakTreshold", fallback="0.5") min_separation_angle = Config.get_config().getfloat("CSDTracking", "minimumSeparationAngle", fallback="25") direction_getter = peaks_from_model(model=csd_model, data=self.data.dwi, sphere=get_sphere('symmetric724'), mask=self.data.binarymask, relative_peak_threshold=relative_peak_thr, min_separation_angle=min_separation_angle, parallel=False) dti_fit = dti.TensorModel(self.data.gtab, fit_method='LS') dti_fit = dti_fit.fit(self.data.dwi, mask=self.data.binarymask) self._track(ThresholdStoppingCriterion(dti_fit.fa, self.options.fa_threshold), direction_getter) Cache.get_cache().set(self.id, self.streamlines)
def test_diffusivities(): psphere = get_sphere('symmetric362') bvecs = np.concatenate(([[0, 0, 0]], psphere.vertices)) bvals = np.zeros(len(bvecs)) + 1000 bvals[0] = 0 gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0001], [0.0015, 0.0003, 0.0003])) mevecs = [np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]])] S = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) dm = dti.TensorModel(gtab, 'LS') dmfit = dm.fit(S) md = mean_diffusivity(dmfit.evals) Trace = trace(dmfit.evals) rd = radial_diffusivity(dmfit.evals) ad = axial_diffusivity(dmfit.evals) lin = linearity(dmfit.evals) plan = planarity(dmfit.evals) spher = sphericity(dmfit.evals) assert_almost_equal(md, (0.0015 + 0.0003 + 0.0001) / 3) assert_almost_equal(Trace, (0.0015 + 0.0003 + 0.0001)) assert_almost_equal(ad, 0.0015) assert_almost_equal(rd, (0.0003 + 0.0001) / 2) assert_almost_equal(lin, (0.0015 - 0.0003)/Trace) assert_almost_equal(plan, 2 * (0.0003 - 0.0001)/Trace) assert_almost_equal(spher, (3 * 0.0001)/Trace)
def _run_interface(self, runtime): from dipy.reconst import dti from dipy.io.utils import nifti1_symmat gtab = self._get_gradient_table() img = nb.load(self.inputs.in_file) data = img.get_data() affine = img.affine mask = None if isdefined(self.inputs.mask_file): mask = nb.load(self.inputs.mask_file).get_data() # Fit it tenmodel = dti.TensorModel(gtab) ten_fit = tenmodel.fit(data, mask) lower_triangular = ten_fit.lower_triangular() img = nifti1_symmat(lower_triangular, affine) out_file = self._gen_filename('dti') nb.save(img, out_file) IFLOGGER.info('DTI parameters image saved as %s', out_file) # FA MD RD and AD for metric in ["fa", "md", "rd", "ad", "color_fa"]: data = getattr(ten_fit, metric).astype("float32") out_name = self._gen_filename(metric) nb.Nifti1Image(data, affine).to_filename(out_name) IFLOGGER.info('DTI %s image saved as %s', metric, out_name) return runtime
def _run_interface(self, runtime): from dipy.reconst import dti # Load the 4D image files img = nb.load(self.inputs.in_file) data = img.get_data() affine = img.affine # Load the gradient strengths and directions gtab = self._get_gradient_table() # Mask the data so that tensors are not fit for # unnecessary voxels mask = data[..., 0] > 50 # Fit the tensors to the data tenmodel = dti.TensorModel(gtab) tenfit = tenmodel.fit(data, mask) # Calculate the mode of each voxel's tensor mode_data = tenfit.mode # Write as a 3D Nifti image with the original affine img = nb.Nifti1Image(mode_data, affine) out_file = self._gen_filename('mode') nb.save(img, out_file) IFLOGGER.info('Tensor mode image saved as %s', out_file) return runtime
def dMRI2ODF_DTI(PATH): ''' Input the dMRI data return the ODF ''' print(PATH) if os.path.exists(PATH + 'processed_data.npz'): return None dMRI_path = PATH + 'data.nii.gz' mask_path = PATH + 'nodif_brain_mask.nii.gz' dMRI_img = nib.load(dMRI_path) dMRI_data = dMRI_img.get_fdata() mask_img = nib.load(mask_path) mask = mask_img.get_fdata() ########## subsample ########## # in the main paper, to train the full 3D brain # We downsample the data into around 32x32x32 # If not downsample, it can process the full-size brain image # but cannot fit into GPU memory dMRI_data = dMRI_data[::4, ::4, ::4, ...] mask = mask[::4, ::4, ::4, ...] bval = PATH + "bvals" bvec = PATH + "bvecs" radial_order = 6 zeta = 700 lambdaN = 1e-8 lambdaL = 1e-8 ###### process the ODF data ###### # size is 32x32x32x(362) gtab = gradient_table(bvals=bval, bvecs=bvec) asm = ShoreModel(gtab, radial_order=radial_order, zeta=zeta, lambdaN=lambdaN, lambdaL=lambdaL) asmfit = asm.fit(dMRI_data, mask=mask) sphere = get_sphere('symmetric362') dMRI_odf = asmfit.odf(sphere) dMRI_odf[dMRI_odf <= 0] = 0 # remove the numerical issue ###### process the DTI data ###### # size is 32x32x32x(3x3) tenmodel = dti.TensorModel(gtab) dMRI_dti = tenmodel.fit(dMRI_data, mask) dMRI_dti = dMRI_dti.quadratic_form name = PATH.split('/')[2] # here, might be affected by the path # change the [2] here for the correct index np.savez(PATH + 'processed_data.npz', DTI=dMRI_dti, ODF=dMRI_odf, mask=mask, name=name) return None
def _init_odf(self): print("Initialising ODF") # fit DTI model to data if self.odf_mode == "DTI" or self.odf_mode == "CSD": if self.odf_mode == "DTI": print("DTI-based ODF computation") self.dti_model = dti.TensorModel(self.dataset.gtab, fit_method='LS') self.dti_fit = self.dti_model.fit( self.dataset.dwi, mask=self.dataset.binary_mask) # compute ODF odf = self.dti_fit.odf(self.sphere_odf) elif self.odf_mode == "CSD": print("CSD-based ODF computation") mask = mask_for_response_ssst(self.dataset.gtab, self.dataset.dwi, roi_radii=10, fa_thr=0.7) num_voxels = np.sum(mask) print(num_voxels) response, ratio = response_from_mask_ssst( self.dataset.gtab, self.dataset.dwi, mask) print(response) self.dti_model = ConstrainedSphericalDeconvModel( self.dataset.gtab, response) self.dti_fit = self.dti_model.fit(self.dataset.dwi) odf = self.dti_fit.odf(self.sphere_odf) # -- set up interpolator for odf evaluation x_range = np.arange(odf.shape[0]) y_range = np.arange(odf.shape[1]) z_range = np.arange(odf.shape[2]) self.odf_interpolator = RegularGridInterpolator( (x_range, y_range, z_range), odf) elif self.odf_mode == "NN": print("Neural-Network-based ODF computation") print( "Warning: The currently used model was trained with 1x1x1 normalised and cropped DWI data from HCP." ) print( "Only use this mode if you know that the model is compatible with the DWI data you are using" ) script = torch.jit.load("1x1x1_model3.pt", map_location=self.device) def interpolate(coords_ijk): with torch.no_grad(): new_shape = (*coords_ijk.shape[:-1], -1) dwi = torch.from_numpy(self.dataset.get_interpolated_dwi(self.dataset.to_ras(coords_ijk), postprocessing=Resample100()))\ .float().to(self.device) odf_value = script(dwi).reshape(new_shape) return odf_value.numpy() self.odf_interpolator = interpolate