def csd(training, category, snr, denoised, odeconv, tv, method, weight=0.1): data, affine, gtab, mask, evals, S0, prefix = prepare(training, category, snr, denoised, odeconv, tv, method) if category == 'dti': csd_model = ConstrainedSphericalDeconvModel(gtab, (evals, S0), sh_order=6) if category == 'hardi': csd_model = ConstrainedSphericalDeconvModel(gtab, (evals, S0), sh_order=8) csd_fit = csd_model.fit(data, mask) sphere = get_sphere('symmetric724') odf = csd_fit.odf(sphere) if tv == True: odf = tv_denoise_4d(odf, weight=0.1) save_odfs_peaks(training, odf, affine, sphere, dres, prefix)
def test_csd_superres(): """ Check the quality of csdfit with high SH order. """ _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) # img, gtab = read_stanford_hardi() evals = np.array([[1.5, .3, .3]]) * [[1.], [1.]] / 1000. S, sticks = multi_tensor(gtab, evals, snr=None, fractions=[55., 45.]) model16 = ConstrainedSphericalDeconvModel(gtab, (evals[0], 3.), sh_order=16) fit16 = model16.fit(S) # print local_maxima(fit16.odf(default_sphere), default_sphere.edges) d, v, ind = peak_directions(fit16.odf(default_sphere), default_sphere, relative_peak_threshold=.2, min_separation_angle=0) # Check that there are two peaks assert_equal(len(d), 2) # Check that peaks line up with sticks cos_sim = abs((d * sticks).sum(1)) ** .5 assert_(all(cos_sim > .99))
def constrained_spherical_deconvolution(dir_src, dir_out, verbose=False): # Load data fbval = pjoin(dir_src, 'bvals_' + par_b_tag) fbvec = pjoin(dir_src, 'bvecs_' + par_b_tag) fdwi = pjoin(dir_src, 'data_' + par_b_tag + '_' + par_dim_tag + '.nii.gz') #fmask = pjoin(dir_src, 'nodif_brain_mask_' + par_dim_tag + '.nii.gz') fmask = pjoin(dir_src, 'wm_mask_' + par_b_tag + '_' + par_dim_tag + '.nii.gz') bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs, b0_threshold=par_b0_threshold) data, affine = load_nifti(fdwi, verbose) mask, _ = load_nifti(fmask, verbose) sphere = get_sphere('symmetric724') response, ratio = auto_response(gtab, data, roi_radius=par_ar_radius, fa_thr=par_ar_fa_th) # print('Response function', response) # Model fitting csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd_model.fit(data, mask=mask) # Saving Spherical Harmonic Coefficient out_peaks = 'sh_' + par_b_tag + '_' + par_dim_tag + '.nii.gz' save_nifti(pjoin(dir_out, out_peaks), csd_fit.shm_coeff, affine)
def get_csd_gfa(nii_data,gtab): from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel csd_model = ConstrainedSphericalDeconvModel(gtab, None, sh_order=6) GFA=csd_model.fit(data,mask).gfa print ('csd_gfa ok')
def test_csd_predict(): """ """ SNR = 100 S0 = 1 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric362') odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) prediction = csd_predict(csd_fit.shm_coeff, gtab, response=response, S0=S0) npt.assert_equal(prediction.shape[0], S.shape[0]) model_prediction = csd.predict(csd_fit.shm_coeff) assert_array_almost_equal(prediction, model_prediction) # Roundtrip tests (quite inaccurate, because of regularization): assert_array_almost_equal(csd_fit.predict(gtab, S0=S0),S,decimal=1) assert_array_almost_equal(csd.predict(csd_fit.shm_coeff, S0=S0),S,decimal=1)
def test_sphere_scaling_csdmodel(): """Check that mirroring regularization sphere does not change the result of the model""" _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, 100., angles=angles, fractions=[50, 50], snr=None) hemi = small_sphere sphere = hemi.mirror() response = (np.array([0.0015, 0.0003, 0.0003]), 100) model_full = ConstrainedSphericalDeconvModel(gtab, response, reg_sphere=sphere) model_hemi = ConstrainedSphericalDeconvModel(gtab, response, reg_sphere=hemi) csd_fit_full = model_full.fit(S) csd_fit_hemi = model_hemi.fit(S) assert_array_almost_equal(csd_fit_full.shm_coeff, csd_fit_hemi.shm_coeff)
def test_csdeconv(): SNR = 100 S0 = 1 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) S, sticks = multi_tensor(gtab, mevals, S0, angles=[(0, 0), (60, 0)], fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric724') mevecs = [all_tensor_evecs(sticks[0]).T, all_tensor_evecs(sticks[1]).T] odf_gt = multi_tensor_odf(sphere.vertices, [0.5, 0.5], mevals, mevecs) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) assert_equal(csd_fit.shm_coeff[0] > 0, True) fodf = csd_fit.odf(sphere) directions, _, _ = peak_directions(odf_gt, sphere) directions2, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions, directions2) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) assert_equal(directions2.shape[0], 2) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=10) assert_equal(len(w) > 0, True) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) assert_equal(len(w) > 0, False)
def _run_interface(self, runtime): from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel from dipy.data import get_sphere # import marshal as pickle import pickle as pickle import gzip img = nb.load(self.inputs.in_file) imref = nb.four_to_three(img)[0] affine = img.get_affine() if isdefined(self.inputs.in_mask): msk = nb.load(self.inputs.in_mask).get_data() else: msk = np.ones(imref.get_shape()) data = img.get_data().astype(np.float32) hdr = imref.get_header().copy() gtab = self._get_gradient_table() resp_file = np.loadtxt(self.inputs.response) response = (np.array(resp_file[0:3]), resp_file[-1]) ratio = response[0][1] / response[0][0] if abs(ratio - 0.2) > 0.1: IFLOGGER.warn(('Estimated response is not prolate enough. ' 'Ratio=%0.3f.') % ratio) csd_model = ConstrainedSphericalDeconvModel( gtab, response, sh_order=self.inputs.sh_order) IFLOGGER.info('Fitting CSD model') csd_fit = csd_model.fit(data, msk) f = gzip.open(self._gen_filename('csdmodel', ext='.pklz'), 'wb') pickle.dump(csd_model, f, -1) f.close() if self.inputs.save_fods: sphere = get_sphere('symmetric724') fods = csd_fit.odf(sphere) nb.Nifti1Image(fods.astype(np.float32), img.get_affine(), None).to_filename(self._gen_filename('fods')) return runtime
def test_csd_predict_multi(): """ Check that we can predict reasonably from multi-voxel fits: """ S0 = 123. _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) coeff = np.random.random(45) - .5 coeff[..., 0] = 10. S = csd.predict(coeff, S0=123.) multi_S = np.array([[S, S], [S, S]]) csd_fit_multi = csd.fit(multi_S) S0_multi = np.mean(multi_S[..., gtab.b0s_mask], -1) pred_multi = csd_fit_multi.predict(S0=S0_multi) npt.assert_array_almost_equal(pred_multi, multi_S)
def test_csd_predict(): """ Test prediction API """ SNR = 100 S0 = 1 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) sphere = small_sphere odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) # Predicting from a fit should give the same result as predicting from a # model, S0 is 1 by default prediction1 = csd_fit.predict() prediction2 = csd.predict(csd_fit.shm_coeff) npt.assert_array_equal(prediction1, prediction2) npt.assert_array_equal(prediction1[..., gtab.b0s_mask], 1.) # Same with a different S0 prediction1 = csd_fit.predict(S0=123.) prediction2 = csd.predict(csd_fit.shm_coeff, S0=123.) npt.assert_array_equal(prediction1, prediction2) npt.assert_array_equal(prediction1[..., gtab.b0s_mask], 123.) # For "well behaved" coefficients, the model should be able to find the # coefficients from the predicted signal. coeff = np.random.random(csd_fit.shm_coeff.shape) - .5 coeff[..., 0] = 10. S = csd.predict(coeff) csd_fit = csd.fit(S) npt.assert_array_almost_equal(coeff, csd_fit.shm_coeff) # Test predict on nd-data set S_nd = np.zeros((2, 3, 4, S.size)) S_nd[:] = S fit = csd.fit(S_nd) predict1 = fit.predict() predict2 = csd.predict(fit.shm_coeff) npt.assert_array_almost_equal(predict1, predict2)
def test_num_sls(): toydict = uniform_toy_data() csd_model = ConstrainedSphericalDeconvModel(toydict['gtab'], None, sh_order=6) csd_fit = csd_model.fit(toydict['toy_data']) sltest_list = [('toy_roi_long_plane', 121), ('toy_roi_radial_plane', 121), ('toy_roi_center_vox', 1)] classifier = ThresholdTissueClassifier(toydict['toy_tissue_classifier'], .1) detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) expected_sl_length = 11 for roi, num_sl in sltest_list: seed = utils.seeds_from_mask(toydict[roi]) streamlines = LocalTracking(detmax_dg, classifier, seed, toydict['toy_affine'], step_size=1) streamlines = list(streamlines) npt.assert_equal(len(streamlines), num_sl) for sl in streamlines: npt.assert_equal(len(sl), expected_sl_length)
def test_csdeconv(): SNR = 100 S0 = 1 _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs, b0_threshold=0) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric362') odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) assert_equal(csd_fit.shm_coeff[0] > 0, True) fodf = csd_fit.odf(sphere) directions, _, _ = peak_directions(odf_gt, sphere) directions2, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions, directions2) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) assert_equal(directions2.shape[0], 2) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", category=UserWarning) _ = ConstrainedSphericalDeconvModel(gtab, response, sh_order=10) assert_greater( len([lw for lw in w if issubclass(lw.category, UserWarning)]), 0) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", category=UserWarning) ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) assert_equal( len([lw for lw in w if issubclass(lw.category, UserWarning)]), 0) mevecs = [] for s in sticks: mevecs += [all_tensor_evecs(s).T] S2 = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) big_S = np.zeros((10, 10, 10, len(S2))) big_S[:] = S2 aresponse, aratio = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) assert_almost_equal(aresponse[1], 100) assert_almost_equal(aratio, response[0][1] / response[0][0]) auto_response(gtab, big_S, roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) _, _, nvoxels = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=30, fa_thr=0.5, return_number_of_voxels=True) assert_equal(nvoxels, 1000) with warnings.catch_warnings(record=True) as w: _, _, nvoxels = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=30, fa_thr=1, return_number_of_voxels=True) npt.assert_equal(len(w), 1) npt.assert_(issubclass(w[0].category, UserWarning)) npt.assert_( "No voxel with a FA higher than 1 were found" in str(w[0].message)) assert_equal(nvoxels, 0)
def compCsdPeaks(basename, output, mask=None, sh_only=False, invert=[1]): home = os.getcwd() fbase = basename fdwi = fbase+".nii.gz" fbval = fbase+".bvals" fbvec = fbase+".bvecs" print fdwi,fbval,fbvec img = nib.load(fdwi) data = img.get_data() zooms = img.get_header().get_zooms()[:3] affine = img.get_affine() # reslice image into 1x1x1 iso voxel # new_zooms = (1., 1., 1.) # data, affine = resample(data, affine, zooms, new_zooms) # img = nib.Nifti1Image(data, affine) # # print data.shape # print img.get_header().get_zooms() # print "###" # # nib.save(img, 'C5_iso.nii.gz') bval, bvec = dio.read_bvals_bvecs(fbval, fbvec) # invert bvec z for GE scanner for i in invert: bvec[:,i]*= -1 gtab = dgrad.gradient_table(bval, bvec) if mask is None: print 'generate mask' maskdata, mask = median_otsu(data, 3, 1, False, vol_idx=range(10, 50), dilate=2) else: mask = nib.load(mask).get_data() maskdata = applymask(data, mask) # tenmodel = dti.TensorModel(gtab) # tenfit = tenmodel.fit(data) # print('Computing anisotropy measures (FA, MD, RGB)') # # # FA = fractional_anisotropy(tenfit.evals) # FA[np.isnan(FA)] = 0 # # fa_img = nib.Nifti1Image(FA.astype(np.float32), img.get_affine()) # nib.save(fa_img, 'FA.nii.gz') # # return # estimate response function, ratio should be ~0.2 response, ratio = auto_response(gtab, maskdata, roi_radius=10, fa_thr=0.7) print response, ratio # reconstruct csd model print "estimate csd_model" csd_model = ConstrainedSphericalDeconvModel(gtab, response) #a_data = maskdata[40:80, 40:80, 60:61] #c_data = maskdata[40:80, 59:60, 50:80] #s_data = maskdata[59:60, 40:70, 30:80] data_small = maskdata # # evals = response[0] # evecs = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]).T #sphere = get_sphere('symmetric362') if sh_only: print 'fitting csd spherical harmonics to data' csd_fit = csd_model.fit(data_small) outfile = output+'_shfit.dipy' with open(outfile, 'wb') as fout: cPickle.dump(csd_fit, fout, -1) print "done writing to file %s"% (outfile) return csd_fit #csd_odf = csd_fit.odf(sphere) # # #fodf_spheres = fvtk.sphere_funcs(csd_odf, sphere, scale=1, norm=False) ##fodf_spheres.GetProperty().SetOpacity(0.4) ## #fvtk.add(ren, fodf_spheres) ##fvtk.add(ren, fodf_peaks) #fvtk.show(ren) # #sys.exit() # fit csd peaks print "fit csd peaks" proc_num = multiprocessing.cpu_count()-1 print "peaks_from_model using core# =" + str(proc_num) sphere = get_sphere('symmetric724') csd_peaks = peaks_from_model(model=csd_model, data=data, sphere=sphere, mask=mask, relative_peak_threshold=.5, min_separation_angle=25, parallel=True, nbr_processes=proc_num) #fodf_peaks = fvtk.peaks(csd_peaks.peak_dirs, csd_peaks.peak_values, scale=1) # fd, fname = mkstemp() # pickle.save_pickle(fname, csd_peaks) # # os.close(fd) #pickle.dump(csd_peaks, open("csd.p", "wb")) outfile = output+'_csdpeaks.dipy' print 'writing peaks to file...' with open(outfile, 'wb') as fout: cPickle.dump(csd_peaks, fout, -1) print "done writing to file %s"% (outfile) return (csd_peaks, outfile)
def dwi_probabilistic_tracing(image, bvecs, bvals, wm, seeds, fibers, rseed=42, prune_length=3, plot=False, verbose=False): # Pipeline transcribed from: # https://dipy.org/documentation/1.1.1./examples_built/tracking_probabilistic/ # Load Images dwi_loaded = nib.load(image) dwi_data = dwi_loaded.get_fdata() wm_loaded = nib.load(wm) wm_data = wm_loaded.get_fdata() seeds_loaded = nib.load(seeds) seeds_data = seeds_loaded.get_fdata() seeds = utils.seeds_from_mask(seeds_data, dwi_loaded.affine, density=1) # Load B-values & B-vectors # NB. Use aligned b-vecs if providing eddy-aligned data bvals, bvecs = read_bvals_bvecs(bvals, bvecs) gtab = gradient_table(bvals, bvecs) # Establish ODF model response, ratio = auto_response(gtab, dwi_data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(dwi_data, mask=wm_data) # Set stopping criterion csa_model = CsaOdfModel(gtab, sh_order=6) gfa = csa_model.fit(dwi_data, mask=wm_data).gfa stopping_criterion = ThresholdStoppingCriterion(gfa, .25) # Create Probabilisitic direction getter fod = csd_fit.odf(default_sphere) pmf = fod.clip(min=0) prob_dg = ProbabilisticDirectionGetter.from_pmf(pmf, max_angle=30., sphere=default_sphere) # Generate streamlines streamline_generator = LocalTracking(prob_dg, stopping_criterion, seeds, dwi_loaded.affine, 0.5, random_seed=rseed) streamlines = Streamlines(streamline_generator) # Prune streamlines streamlines = ArraySequence( [strline for strline in streamlines if len(strline) > prune_length]) sft = StatefulTractogram(streamlines, dwi_loaded, Space.RASMM) # Save streamlines save_trk(sft, fibers + ".trk") # Visualize fibers if plot and has_fury: from dipy.viz import window, actor, colormap as cmap # Create the 3D display. r = window.Renderer() r.add(actor.line(streamlines, cmap.line_colors(streamlines))) window.record(r, out_path=fibers + '.png', size=(800, 800))
numpass=1, autocrop=False, dilate=2) from dipy.reconst.csdeconv import auto_response response, ratio = auto_response(gtab, maskdata, roi_radius=10, fa_thr=0.7) data = maskdata[:, :, 33:37] mask = mask[:, :, 33:37] """ Now we are ready to import the CSD model and fit the datasets. """ from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel csd_model = ConstrainedSphericalDeconvModel(gtab, response) """ Compute the CSD-based ODFs using ``peaks_from_model``. This function has a parameter called ``parallel`` which allows for the voxels to be processed in parallel. If ``nbr_processes`` is None it will figure out automatically the number of CPUs available in your system. Alternatively, you can set ``nbr_processes`` manually. Here, we show an example where we compare the duration of execution with or without parallelism. """ import time from dipy.direction import peaks_from_model start_time = time.time() csd_peaks_parallel = peaks_from_model(model=csd_model,
def csd(dwi_file, bvals_file, bvecs_file, outfile_shm=None, roi_center=None, roi_radius=10, fa_threshold=0.75, outfile_peaks_dir=None, outfile_peaks_val=None, mibrain_file=None, peak_mask=None, npeaks=5, min_separation=30, normalize=0, verbose=0): if verbose: logging.basicConfig(level=logging.DEBUG) if roi_center is not None and len(roi_center) != 3: raise ValueError("roi_center should be a 3-D position") bvals, bvecs = read_bvals_bvecs(bvals_file, bvecs_file) gtab = gradient_table(bvals, bvecs, b0_threshold=bvals.min()) diffusion_img = nibabel.load(dwi_file) diffusion_data = diffusion_img.get_data() logging.debug("Fitting CSD model") response, ratio = auto_response(gtab, diffusion_data, roi_center, roi_radius, fa_threshold) logging.debug("Response: {}, ratio: {}".format(response, ratio)) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) if outfile_shm is not None: csd_fit = csd_model.fit(diffusion_data) logging.debug("Saving SHM Coefficients") citrix.save(outfile_shm, csd_fit.shm_coeff, affine=diffusion_img.affine, header=diffusion_img.header, version=1) if outfile_peaks_dir is None and outfile_peaks_val is None and mibrain_file is None: return logging.debug("Computing peaks") sphere = get_sphere() if peak_mask is not None: peak_mask = nibabel.load(peak_mask).get_data().astype(bool) peaks = peaks_from_model(csd_model, diffusion_data, sphere, 0.5, min_separation, peak_mask, normalize_peaks=normalize, npeaks=npeaks, sh_order=6) logging.debug("Saving peaks") if outfile_peaks_dir is not None: citrix.save(outfile_peaks_dir, peaks.peak_dirs, affine=diffusion_img.affine, header=diffusion_img.header, version=1) if outfile_peaks_val is not None: citrix.save(outfile_peaks_val, peaks.peak_values, affine=diffusion_img.affine, header=diffusion_img.header, version=1) if mibrain_file is not None: peaks = peaks.peak_dirs * peaks.peak_values[...,None] peaks = peaks.reshape(*peaks.shape[:-2], -1) citrix.save(mibrain_file, peaks, affine=diffusion_img.affine, header=diffusion_img.header, version=1)
def determine(name=None, data_path=None, output_path='.', Threshold=.20, data_list=None, seed='.', minus_ROI_mask='.', one_node=False, two_node=False): time0 = time.time() print("begin loading data, time:", time.time() - time0) if data_list == None: data, affine, img, labels, gtab, head_mask = get_data(name, data_path) else: data = data_list['DWI'] affine = data_list['affine'] img = data_list['img'] labels = data_list['labels'] gtab = data_list['gtab'] head_mask = data_list['head_mask'] print(type(seed)) if type(seed) != str: seed_mask = seed else: seed_mask = (labels == 2) * (head_mask == 1) white_matter = (labels == 2) * (head_mask == 1) seeds = utils.seeds_from_mask(seed_mask, affine, density=1) print("begin reconstruction, time:", time.time() - time0) response, ratio = auto_response_ssst(gtab, data, roi_radii=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) csa_model = CsaOdfModel(gtab, sh_order=6) gfa = csa_model.fit(data, mask=white_matter).gfa stopping_criterion = ThresholdStoppingCriterion(gfa, Threshold) #from dipy.data import small_sphere print("begin tracking, time:", time.time() - time0) detmax_dg = DeterministicMaximumDirectionGetter.from_shcoeff( csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) streamline_generator = LocalTracking(detmax_dg, stopping_criterion, seeds, affine, step_size=.5) streamlines = Streamlines(streamline_generator) sft = StatefulTractogram(streamlines, img, Space.RASMM) if one_node or two_node: sft.to_vox() streamlines = reduct_seed_ROI(sft.streamlines, seed_mask, one_node, two_node) if type(minus_ROI_mask) != str: streamlines = minus_ROI(streamlines=streamlines, ROI=minus_ROI_mask) sft = StatefulTractogram(streamlines, img, Space.VOX) sft._vox_to_rasmm() print("begin saving, time:", time.time() - time0) output = output_path + '/tractogram_deterministic_' + name + '.trk' save_trk(sft, output) print("finished, time:", time.time() - time0)
classifier = ThresholdTissueClassifier(csa_peaks.gfa, 0.25) """ In order to perform probabilistic fiber tracking we first fit the data to the Constrained Spherical Deconvolution (CSD) model in DIPY. This model represents each voxel in the data set as a collection of small white matter fibers with different orientations. The density of fibers along each orientation is known as the Fiber Orientation Distribution (FOD), used in the fiber tracking. """ # Perform CSD on the original data from dipy.reconst.csdeconv import auto_response from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd_model.fit(data_small) csd_fit_shm = np.lib.pad(csd_fit.shm_coeff, ((xa, dshape[0] - xb), (ya, dshape[1] - yb), (za, dshape[2] - zb), (0, 0)), 'constant') # Probabilistic direction getting for fiber tracking from dipy.direction import ProbabilisticDirectionGetter prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit_shm, max_angle=30., sphere=default_sphere) """ The optic radiation is reconstructed by tracking fibers from the calcarine sulcus (visual cortex V1) to the lateral geniculate nucleus (LGN). We seed from the calcarine sulcus by selecting a region-of-interest (ROI) cube of
def dwi_dipy_run(dwi_dir, node_size, dir_path, conn_model, parc, atlas_select, network, wm_mask=None): from dipy.reconst.dti import TensorModel, quantize_evecs from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel, recursive_response from dipy.tracking.local import LocalTracking, ActTissueClassifier from dipy.tracking import utils from dipy.direction import peaks_from_model from dipy.tracking.eudx import EuDX from dipy.data import get_sphere, default_sphere from dipy.core.gradients import gradient_table from dipy.io import read_bvals_bvecs from dipy.tracking.streamline import Streamlines from dipy.direction import ProbabilisticDirectionGetter, ClosestPeakDirectionGetter, BootDirectionGetter from nibabel.streamlines import save as save_trk from nibabel.streamlines import Tractogram ## dwi_dir = '/Users/PSYC-dap3463/Downloads/bedpostx_s002' img_pve_csf = nib.load( '/Users/PSYC-dap3463/Downloads/002_all/tmp/reg_a/t1w_vent_csf_diff_dwi.nii.gz' ) img_pve_wm = nib.load( '/Users/PSYC-dap3463/Downloads/002_all/tmp/reg_a/t1w_wm_in_dwi_bin.nii.gz' ) img_pve_gm = nib.load( '/Users/PSYC-dap3463/Downloads/002_all/tmp/reg_a/t1w_gm_mask_dwi.nii.gz' ) labels_img = nib.load( '/Users/PSYC-dap3463/Downloads/002_all/tmp/reg_a/dwi_aligned_atlas.nii.gz' ) num_total_samples = 10000 tracking_method = 'boot' # Options are 'boot', 'prob', 'peaks', 'closest' procmem = [2, 4] ## if parc is True: node_size = 'parc' dwi_img = "%s%s" % (dwi_dir, '/dwi.nii.gz') nodif_brain_mask_path = "%s%s" % (dwi_dir, '/nodif_brain_mask.nii.gz') bvals = "%s%s" % (dwi_dir, '/bval') bvecs = "%s%s" % (dwi_dir, '/bvec') dwi_img = nib.load(dwi_img) data = dwi_img.get_data() [bvals, bvecs] = read_bvals_bvecs(bvals, bvecs) gtab = gradient_table(bvals, bvecs) gtab.b0_threshold = min(bvals) sphere = get_sphere('symmetric724') # Loads mask and ensures it's a true binary mask mask_img = nib.load(nodif_brain_mask_path) mask = mask_img.get_data() mask = mask > 0 # Fit a basic tensor model first model = TensorModel(gtab) ten = model.fit(data, mask) fa = ten.fa # Tractography if conn_model == 'csd': print('Tracking with csd model...') elif conn_model == 'tensor': print('Tracking with tensor model...') else: raise RuntimeError("%s%s" % (conn_model, ' is not a valid model.')) # Combine seed counts from voxel with seed counts total wm_mask_data = img_pve_wm.get_data() wm_mask_data[0, :, :] = False wm_mask_data[:, 0, :] = False wm_mask_data[:, :, 0] = False seeds = utils.seeds_from_mask(wm_mask_data, density=1, affine=dwi_img.get_affine()) seeds_rnd = utils.random_seeds_from_mask(ten.fa > 0.02, seeds_count=num_total_samples, seed_count_per_voxel=True) seeds_all = np.vstack([seeds, seeds_rnd]) # Load tissue maps and prepare tissue classifier (Anatomically-Constrained Tractography (ACT)) background = np.ones(img_pve_gm.shape) background[(img_pve_gm.get_data() + img_pve_wm.get_data() + img_pve_csf.get_data()) > 0] = 0 include_map = img_pve_gm.get_data() include_map[background > 0] = 1 exclude_map = img_pve_csf.get_data() act_classifier = ActTissueClassifier(include_map, exclude_map) if conn_model == 'tensor': ind = quantize_evecs(ten.evecs, sphere.vertices) streamline_generator = EuDX(a=fa, ind=ind, seeds=seeds_all, odf_vertices=sphere.vertices, a_low=0.05, step_sz=.5) elif conn_model == 'csd': print('Tracking with CSD model...') response = recursive_response( gtab, data, mask=img_pve_wm.get_data().astype('bool'), sh_order=8, peak_thr=0.01, init_fa=0.05, init_trace=0.0021, iter=8, convergence=0.001, parallel=True) csd_model = ConstrainedSphericalDeconvModel(gtab, response) if tracking_method == 'boot': dg = BootDirectionGetter.from_data(data, csd_model, max_angle=30., sphere=default_sphere) elif tracking_method == 'prob': try: print( 'First attempting to build the direction getter directly from the spherical harmonic representation of the FOD...' ) csd_fit = csd_model.fit( data, mask=img_pve_wm.get_data().astype('bool')) dg = ProbabilisticDirectionGetter.from_shcoeff( csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) except: print( 'Sphereical harmonic not available for this model. Using peaks_from_model to represent the ODF of the model on a spherical harmonic basis instead...' ) peaks = peaks_from_model( csd_model, data, default_sphere, .5, 25, mask=img_pve_wm.get_data().astype('bool'), return_sh=True, parallel=True, nbr_processes=procmem[0]) dg = ProbabilisticDirectionGetter.from_shcoeff( peaks.shm_coeff, max_angle=30., sphere=default_sphere) elif tracking_method == 'peaks': dg = peaks_from_model(model=csd_model, data=data, sphere=default_sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=img_pve_wm.get_data().astype('bool'), parallel=True, nbr_processes=procmem[0]) elif tracking_method == 'closest': csd_fit = csd_model.fit(data, mask=img_pve_wm.get_data().astype('bool')) pmf = csd_fit.odf(default_sphere).clip(min=0) dg = ClosestPeakDirectionGetter.from_pmf(pmf, max_angle=30., sphere=default_sphere) streamline_generator = LocalTracking(dg, act_classifier, seeds_all, affine=dwi_img.affine, step_size=0.5) del dg try: del csd_fit except: pass try: del response except: pass try: del csd_model except: pass streamlines = Streamlines(streamline_generator, buffer_size=512) save_trk(Tractogram(streamlines, affine_to_rasmm=dwi_img.affine), 'prob_streamlines.trk') tracks = [sl for sl in streamlines if len(sl) > 1] labels_data = labels_img.get_data().astype('int') labels_affine = labels_img.affine conn_matrix, grouping = utils.connectivity_matrix( tracks, labels_data, affine=labels_affine, return_mapping=True, mapping_as_streamlines=True, symmetric=True) conn_matrix[:3, :] = 0 conn_matrix[:, :3] = 0 return conn_matrix
def test_bootstap_peak_tracker(): """This tests that the Bootstrat Peak Direction Getter plays nice LocalTracking and produces reasonable streamlines in a simple example. """ sphere = get_sphere('repulsion100') # A simple image with three possible configurations, a vertical tract, # a horizontal tract and a crossing simple_image = np.array([ [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [2, 3, 2, 2, 2, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], ]) simple_image = simple_image[..., None] bvecs = sphere.vertices bvals = np.ones(len(bvecs)) * 1000 bvecs = np.insert(bvecs, 0, np.array([0, 0, 0]), axis=0) bvals = np.insert(bvals, 0, 0) gtab = gradient_table(bvals, bvecs) angles = [(90, 90), (90, 0)] fracs = [50, 50] mevals = np.array([[1.5, 0.4, 0.4], [1.5, 0.4, 0.4]]) * 1e-3 mevecs = [ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) ] voxel1 = single_tensor(gtab, 1, mevals[0], mevecs[0], snr=None) voxel2 = single_tensor(gtab, 1, mevals[0], mevecs[1], snr=None) voxel3, _ = multi_tensor(gtab, mevals, fractions=fracs, angles=angles, snr=None) data = np.tile(voxel3, [5, 6, 1, 1]) data[simple_image == 1] = voxel1 data[simple_image == 2] = voxel2 response = (np.array(mevals[1]), 1) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) seeds = [np.array([0., 1., 0.]), np.array([2., 4., 0.])] sc = BinaryStoppingCriterion((simple_image > 0).astype(float)) sphere = HemiSphere.from_sphere(get_sphere('symmetric724')) boot_dg = BootDirectionGetter.from_data(data, csd_model, 60, sphere=sphere) streamlines_generator = LocalTracking(boot_dg, sc, seeds, np.eye(4), 1.) streamlines = Streamlines(streamlines_generator) expected = [ np.array([[0., 1., 0.], [1., 1., 0.], [2., 1., 0.], [3., 1., 0.], [4., 1., 0.]]), np.array([ [2., 4., 0.], [2., 3., 0.], [2., 2., 0.], [2., 1., 0.], [2., 0., 0.], ]) ] def allclose(x, y): return x.shape == y.shape and np.allclose(x, y, atol=0.5) if not allclose(streamlines[0], expected[0]): raise AssertionError() if not allclose(streamlines[1], expected[1]): raise AssertionError()
voxel_size = header.get_zooms()[:3]; # slice out b0 b0 = data[:,:,:,0]; img2 = nib.Nifti1Image(b0,affine); nib.save(img2, "b0.nii.gz"); # load bvals bvecs fbval = "dwi.bval"; fbvec = "dwi.bvec"; bvals, bvecs = read_bvals_bvecs(fbval, fbvec); gtab = gradient_table(bvals, bvecs); # fit constrained spherical deconvolution model response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7); csd_model = CsdModel(gtab, response); csd_fit = csd_model.fit(data); # init fiber odf sphere = get_sphere('symmetric724'); csd_odf = csd_fit.odf(sphere); stepper = FixedSizeStepper(1); # load in b0 and create mask b0_img = nib.load('b0.nii.gz'); b0_data = b0_img.get_data(); b0_mask, mask = median_otsu(b0_data, 2, 1); # save mask for b0 mask_img = nib.Nifti1Image(mask.astype(np.float32), b0_img.get_affine())
def main(): start = time.time() with open('config.json') as config_json: config = json.load(config_json) # Load the data dmri_image = nib.load(config['data_file']) dmri = dmri_image.get_data() affine = dmri_image.affine #aparc_im = nib.load(config['freesurfer']) aparc_im = nib.load('volume.nii.gz') aparc = aparc_im.get_data() end = time.time() print('Loaded Files: ' + str((end - start))) # Create the white matter and callosal masks start = time.time() wm_regions = [ 2, 41, 16, 17, 28, 60, 51, 53, 12, 52, 12, 52, 13, 18, 54, 50, 11, 251, 252, 253, 254, 255, 10, 49, 46, 7 ] wm_mask = np.zeros(aparc.shape) for l in wm_regions: wm_mask[aparc == l] = 1 # Create the gradient table from the bvals and bvecs bvals, bvecs = read_bvals_bvecs(config['data_bval'], config['data_bvec']) gtab = gradient_table(bvals, bvecs, b0_threshold=100) end = time.time() print('Created Gradient Table: ' + str((end - start))) ##The probabilistic model## # Use the Constant Solid Angle (CSA) to find the Orientation Dist. Function # Helps orient the wm tracts start = time.time() csa_model = CsaOdfModel(gtab, sh_order=6) csa_peaks = peaks_from_model(csa_model, dmri, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=wm_mask) print('Creating CSA Model: ' + str(time.time() - start)) # Begins the seed in the wm tracts seeds = utils.seeds_from_mask(wm_mask, density=[1, 1, 1], affine=affine) print('Created White Matter seeds: ' + str(time.time() - start)) # Create a CSD model to measure Fiber Orientation Dist print('Begin the probabilistic model') response, ratio = auto_response(gtab, dmri, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(dmri, mask=wm_mask) print('Created the CSD model: ' + str(time.time() - start)) # Set the Direction Getter to randomly choose directions prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) print('Created the Direction Getter: ' + str(time.time() - start)) # Restrict the white matter tracking classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) print('Created the Tissue Classifier: ' + str(time.time() - start)) # Create the probabilistic model streamlines = LocalTracking(prob_dg, tissue_classifier=classifier, seeds=seeds, step_size=.5, max_cross=1, affine=affine) print('Created the probabilistic model: ' + str(time.time() - start)) # Compute streamlines and store as a list. streamlines = list(streamlines) print('Computed streamlines: ' + str(time.time() - start)) #from dipy.tracking.streamline import transform_streamlines #streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) # Create a tractogram from the streamlines and save it tractogram = Tractogram(streamlines, affine_to_rasmm=affine) #tractogram.apply_affine(np.linalg.inv(affine)) save(tractogram, 'track.tck') end = time.time() print("Created the tck file: " + str((end - start)))
def track(dwi_file, bval, bvec, mask_file, stop_val=0.1): # """ # Tracking with basic tensors and basic eudx - experimental # We now force seeding at every voxel in the provided mask for # simplicity. Future functionality will extend these options. # **Positional Arguments:** # dwi_file: # - File (registered) to use for tensor/fiber tracking # mask_file: # - Brain mask to keep tensors inside the brain # gtab: # - dipy formatted bval/bvec Structure # **Optional Arguments:** # stop_val: # - Value to cutoff fiber track # """ #img = nb.load(dwi_file) #data = img.get_data() dwi = dipy.data.load(dwi_file) data = dwi.get_data() #img = nb.load(mask_file) #mask = img.get_data() dwi_mask = dipy.data.load(mask_file) mask = dwi_mask.get_data() gtab = gradient_table(bval, bvec) affine = dwi.affine seed_mask = mask seeds = utils.seeds_from_mask(seed_mask, density=1, affine=affine) # use all points in mask seedIdx = np.where(mask > 0) # seed everywhere not equal to zero seedIdx = np.transpose(seedIdx) sphere = get_sphere('symmetric724') csd_model = ConstrainedSphericalDeconvModel(gtab, None, sh_order=6) csd_fit = csd_model.fit(data, mask=mask) tensor_model = dti.TensorModel(gtab) tenfit = tensor_model.fit(data, mask=mask) FA = fractional_anisotropy(tenfit.evals) classifier = ThresholdTissueClassifier(FA, 0.1) dg = DeterministicMaximumDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=80., sphere=sphere) streamlines_generator = LocalTracking(dg, classifier, seeds, affine, step_size=0.5) streamlines = Streamlines(streamlines_generator) trk_file = save_trk("deterministic_threshold_DDG_samp_data.trk", streamlines, affine=affine, shape=mask.shape)
def dmri_recon(sid, data_dir, out_dir, resolution, recon='csd', num_threads=2): import tempfile #tempfile.tempdir = '/om/scratch/Fri/ksitek/' import os oldval = None if 'MKL_NUM_THREADS' in os.environ: oldval = os.environ['MKL_NUM_THREADS'] os.environ['MKL_NUM_THREADS'] = '%d' % num_threads ompoldval = None if 'OMP_NUM_THREADS' in os.environ: ompoldval = os.environ['OMP_NUM_THREADS'] os.environ['OMP_NUM_THREADS'] = '%d' % num_threads import nibabel as nib import numpy as np from glob import glob if resolution == '0.2mm': filename = 'Reg_S64550_nii4d.nii' fimg = os.path.abspath(glob(os.path.join(data_dir, filename))[0]) else: filename = 'Reg_S64550_nii4d_resamp-%s.nii.gz'%(resolution) fimg = os.path.abspath(glob(os.path.join(data_dir, 'resample', filename))[0]) print("dwi file = %s"%fimg) fbvec = os.path.abspath(glob(os.path.join(data_dir, 'bvecs', 'camino_120_RAS_flipped-xy.bvecs'))[0]) print("bvec file = %s"%fbvec) fbval = os.path.abspath(glob(os.path.join(data_dir, 'bvecs', 'camino_120_RAS.bvals'))[0]) print("bval file = %s"%fbval) img = nib.load(fimg) data = img.get_data() affine = img.get_affine() prefix = sid from dipy.io import read_bvals_bvecs from dipy.core.gradients import vector_norm bvals, bvecs = read_bvals_bvecs(fbval, fbvec) b0idx = [] for idx, val in enumerate(bvals): if val < 1: pass #bvecs[idx] = [1, 0, 0] else: b0idx.append(idx) #print "b0idx=%d"%idx #print "input bvecs:" #print bvecs bvecs[b0idx, :] = bvecs[b0idx, :]/vector_norm(bvecs[b0idx])[:, None] #print "bvecs after normalization:" #print bvecs from dipy.core.gradients import gradient_table gtab = gradient_table(bvals, bvecs) gtab.bvecs.shape == bvecs.shape gtab.bvecs gtab.bvals.shape == bvals.shape gtab.bvals from dipy.reconst.csdeconv import auto_response response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.1) # 0.7 #from dipy.segment.mask import median_otsu #b0_mask, mask = median_otsu(data[:, :, :, b0idx].mean(axis=3).squeeze(), 4, 4) if resolution == '0.2mm': mask_name = 'Reg_S64550_nii_b0-slice_mask.nii.gz' fmask1 = os.path.join(data_dir, mask_name) else: mask_name = 'Reg_S64550_nii_b0-slice_mask_resamp-%s.nii.gz'%(resolution) fmask1 = os.path.join(data_dir, 'resample', mask_name) print("fmask file = %s"%fmask1) mask = nib.load(fmask1).get_data() useFA = True print("creating model") if recon == 'csd': from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel model = ConstrainedSphericalDeconvModel(gtab, response) useFA = True elif recon == 'csa': from dipy.reconst.shm import CsaOdfModel, normalize_data model = CsaOdfModel(gtab, 4) useFA = False else: raise ValueError('only csd, csa supported currently') from dipy.reconst.dsi import (DiffusionSpectrumDeconvModel, DiffusionSpectrumModel) model = DiffusionSpectrumDeconvModel(gtab) fit = model.fit(data) from dipy.data import get_sphere sphere = get_sphere('symmetric724') #odfs = fit.odf(sphere) from dipy.reconst.peaks import peaks_from_model print("running peaks_from_model") peaks = peaks_from_model(model=model, data=data, sphere=sphere, mask=mask, return_sh=True, return_odf=False, normalize_peaks=True, npeaks=5, relative_peak_threshold=.5, min_separation_angle=25, parallel=num_threads > 1, nbr_processes=num_threads) from dipy.reconst.dti import TensorModel print("running tensor model") tenmodel = TensorModel(gtab) tenfit = tenmodel.fit(data, mask) from dipy.reconst.dti import fractional_anisotropy print("running FA") FA = fractional_anisotropy(tenfit.evals) FA[np.isnan(FA)] = 0 fa_img = nib.Nifti1Image(FA, img.get_affine()) tensor_fa_file = os.path.abspath('%s_tensor_fa.nii.gz' % (prefix)) nib.save(fa_img, tensor_fa_file) from dipy.reconst.dti import axial_diffusivity print("running AD") AD = axial_diffusivity(tenfit.evals) AD[np.isnan(AD)] = 0 ad_img = nib.Nifti1Image(AD, img.get_affine()) tensor_ad_file = os.path.abspath('%s_tensor_ad.nii.gz' % (prefix)) nib.save(ad_img, tensor_ad_file) from dipy.reconst.dti import radial_diffusivity print("running RD") RD = radial_diffusivity(tenfit.evals) RD[np.isnan(RD)] = 0 rd_img = nib.Nifti1Image(RD, img.get_affine()) tensor_rd_file = os.path.abspath('%s_tensor_rd.nii.gz' % (prefix)) nib.save(rd_img, tensor_rd_file) from dipy.reconst.dti import mean_diffusivity print("running MD") MD = mean_diffusivity(tenfit.evals) MD[np.isnan(MD)] = 0 md_img = nib.Nifti1Image(MD, img.get_affine()) tensor_md_file = os.path.abspath('%s_tensor_md.nii.gz' % (prefix)) nib.save(md_img, tensor_md_file) evecs = tenfit.evecs evec_img = nib.Nifti1Image(evecs, img.get_affine()) tensor_evec_file = os.path.abspath('%s_tensor_evec.nii.gz' % (prefix)) nib.save(evec_img, tensor_evec_file) shm_coeff = fit.shm_coeff shm_coeff_file = os.path.abspath('%s_shm_coeff.nii.gz' % (prefix)) nib.save(nib.Nifti1Image(shm_coeff, img.get_affine()), shm_coeff_file) #from dipy.reconst.dti import quantize_evecs #peak_indices = quantize_evecs(tenfit.evecs, sphere.vertices) #eu = EuDX(FA, peak_indices, odf_vertices = sphere.vertices, #a_low=0.2, seeds=10**6, ang_thr=35) fa_img = nib.Nifti1Image(peaks.gfa, img.get_affine()) model_gfa_file = os.path.abspath('%s_%s_gfa.nii.gz' % (prefix, recon)) nib.save(fa_img, model_gfa_file) from dipy.tracking.eudx import EuDX print("reconstructing with EuDX") if useFA: eu = EuDX(FA, peaks.peak_indices[..., 0], odf_vertices = sphere.vertices, #a_low=0.1, seeds=10**6, ang_thr=45) else: eu = EuDX(peaks.gfa, peaks.peak_indices[..., 0], odf_vertices = sphere.vertices, #a_low=0.1, seeds=10**6, ang_thr=45) sl_fname = os.path.abspath('%s_%s_streamline.trk' % (prefix, recon)) """ #import dipy.tracking.metrics as dmetrics streamlines = ((sl, None, None) for sl in eu) # if dmetrics.length(sl) > 15) hdr = nib.trackvis.empty_header() hdr['voxel_size'] = fa_img.get_header().get_zooms()[:3] hdr['voxel_order'] = 'RAS' #LAS hdr['dim'] = FA.shape[:3] nib.trackvis.write(sl_fname, streamlines, hdr, points_space='voxel') """ # trying new dipy.io.streamline module, per email to neuroimaging list # 2018.04.05 from nibabel.streamlines import Field from nibabel.orientations import aff2axcodes affine = img.get_affine() vox_size=fa_img.get_header().get_zooms()[:3] fov_shape=FA.shape[:3] if vox_size is not None and fov_shape is not None: hdr = {} hdr[Field.VOXEL_TO_RASMM] = affine.copy() hdr[Field.VOXEL_SIZES] = vox_size hdr[Field.DIMENSIONS] = fov_shape hdr[Field.VOXEL_ORDER] = "".join(aff2axcodes(affine)) tractogram = nib.streamlines.Tractogram(eu) tractogram.affine_to_rasmm = affine trk_file = nib.streamlines.TrkFile(tractogram, header=hdr) nib.streamlines.save(trk_file, sl_fname) if oldval: os.environ['MKL_NUM_THREADS'] = oldval else: del os.environ['MKL_NUM_THREADS'] if ompoldval: os.environ['OMP_NUM_THREADS'] = ompoldval else: del os.environ['OMP_NUM_THREADS'] assert tensor_fa_file assert tensor_evec_file assert model_gfa_file assert tensor_ad_file assert tensor_rd_file assert tensor_md_file assert shm_coeff_file print('all output files created') return tensor_fa_file, tensor_evec_file, model_gfa_file, sl_fname, affine, tensor_ad_file, tensor_rd_file, tensor_md_file, shm_coeff_file
from dipy.tracking.local_tracking import (LocalTracking, ParticleFilteringTracking) from dipy.tracking.streamline import Streamlines from dipy.tracking import utils from dipy.viz import window, actor, colormap, has_fury img_pve_csf, img_pve_gm, img_pve_wm = read_stanford_pve_maps() hardi_img, gtab, labels_img = read_stanford_labels() data = hardi_img.get_data() labels = labels_img.get_data() affine = hardi_img.affine shape = labels.shape response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd_model.fit(data, mask=img_pve_wm.get_data()) dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=20., sphere=default_sphere) seed_mask = (labels == 2) seed_mask[img_pve_wm.get_data() < 0.5] = 0 seeds = utils.seeds_from_mask(seed_mask, density=2, affine=affine) """ CMC/ACT Stopping Criterion ========================== Continuous map criterion (CMC) [Girard2014]_ and Anatomically-constrained tractography (ACT) [Smith2012]_ both uses PVEs information from anatomical images to determine when the tractography stops.
def test_recursive_response_calibration(): """ Test the recursive response calibration method. """ SNR = 100 S0 = 1 _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) sphere = default_sphere gtab = gradient_table(bvals, bvecs) evals = np.array([0.0015, 0.0003, 0.0003]) evecs = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]).T mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (90, 0)] where_dwi = lazy_index(~gtab.b0s_mask) S_cross, _ = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) S_single = single_tensor(gtab, S0, evals, evecs, snr=SNR) data = np.concatenate((np.tile(S_cross, (8, 1)), np.tile(S_single, (2, 1))), axis=0) odf_gt_cross = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) odf_gt_single = single_tensor_odf(sphere.vertices, evals, evecs) response = recursive_response(gtab, data, mask=None, sh_order=8, peak_thr=0.01, init_fa=0.05, init_trace=0.0021, iter=8, convergence=0.001, parallel=False) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(data) assert_equal(np.all(csd_fit.shm_coeff[:, 0] >= 0), True) fodf = csd_fit.odf(sphere) directions_gt_single, _, _ = peak_directions(odf_gt_single, sphere) directions_gt_cross, _, _ = peak_directions(odf_gt_cross, sphere) directions_single, _, _ = peak_directions(fodf[8, :], sphere) directions_cross, _, _ = peak_directions(fodf[0, :], sphere) ang_sim = angular_similarity(directions_cross, directions_gt_cross) assert_equal(ang_sim > 1.9, True) assert_equal(directions_cross.shape[0], 2) assert_equal(directions_gt_cross.shape[0], 2) ang_sim = angular_similarity(directions_single, directions_gt_single) assert_equal(ang_sim > 0.9, True) assert_equal(directions_single.shape[0], 1) assert_equal(directions_gt_single.shape[0], 1) with warnings.catch_warnings(record=True) as w: sphere = Sphere(xyz=gtab.gradients[where_dwi]) npt.assert_equal(len(w), 1) npt.assert_(issubclass(w[0].category, UserWarning)) npt.assert_("Vertices are not on the unit sphere" in str(w[0].message)) sf = response.on_sphere(sphere) S = np.concatenate(([response.S0], sf)) tenmodel = dti.TensorModel(gtab, min_signal=0.001) tenfit = tenmodel.fit(S) FA = fractional_anisotropy(tenfit.evals) FA_gt = fractional_anisotropy(evals) assert_almost_equal(FA, FA_gt, 1)
def main(): parser = _build_arg_parser() args = parser.parse_args() logging.basicConfig(level=logging.INFO) if not args.not_all: args.fodf = args.fodf or 'fodf.nii.gz' args.peaks = args.peaks or 'peaks.nii.gz' args.peak_indices = args.peak_indices or 'peak_indices.nii.gz' arglist = [args.fodf, args.peaks, args.peak_indices] if args.not_all and not any(arglist): parser.error('When using --not_all, you need to specify at least ' 'one file to output.') assert_inputs_exist(parser, [args.input, args.bvals, args.bvecs, args.frf_file]) assert_outputs_exists(parser, args, arglist) nbr_processes = args.nbr_processes parallel = True if nbr_processes is not None: if nbr_processes <= 0: nbr_processes = None elif nbr_processes == 1: parallel = False full_frf = np.loadtxt(args.frf_file) if not full_frf.shape[0] == 4: raise ValueError('FRF file did not contain 4 elements. ' 'Invalid or deprecated FRF format') frf = full_frf[0:3] mean_b0_val = full_frf[3] vol = nib.load(args.input) data = vol.get_data() 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) check_b0_threshold(args, bvals.min()) gtab = gradient_table(bvals, bvecs, b0_threshold=bvals.min()) if args.mask is None: mask = None else: mask = nib.load(args.mask).get_data().astype(np.bool) # Raise warning for sh order if there is not enough DWIs if data.shape[-1] < (args.sh_order + 1) * (args.sh_order + 2) / 2: warnings.warn( 'We recommend having at least {} unique DWIs volumes, but you ' 'currently have {} volumes. Try lowering the parameter --sh_order ' 'in case of non convergence.'.format( (args.sh_order + 1) * (args.sh_order + 2) / 2, data.shape[-1])) reg_sphere = get_sphere('symmetric362') peaks_sphere = get_sphere('symmetric724') csd_model = ConstrainedSphericalDeconvModel( gtab, (frf, mean_b0_val), reg_sphere=reg_sphere, sh_order=args.sh_order) peaks_csd = peaks_from_model(model=csd_model, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=mask, return_sh=True, sh_basis_type=args.sh_basis, sh_order=args.sh_order, normalize_peaks=True, parallel=parallel, nbr_processes=nbr_processes) if args.fodf: nib.save(nib.Nifti1Image(peaks_csd.shm_coeff.astype(np.float32), vol.affine), args.fodf) if args.peaks: nib.save(nib.Nifti1Image( reshape_peaks_for_visualization(peaks_csd), vol.affine), args.peaks) if args.peak_indices: nib.save(nib.Nifti1Image(peaks_csd.peak_indices, vol.affine), args.peak_indices)
def dodata(f_name, data_path): dipy_home = pjoin(os.path.expanduser('~'), 'dipy_data') folder = pjoin(dipy_home, data_path) fraw = pjoin(folder, f_name + '.nii.gz') fbval = pjoin(folder, f_name + '.bval') fbvec = pjoin(folder, f_name + '.bvec') flabels = pjoin(folder, f_name + '.nii-label.nii.gz') bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) data = img.get_data() affine = img.get_affine() label_img = nib.load(flabels) labels = label_img.get_data() lap = through_label_sl.label_position(labels, labelValue=1) dataslice = data[40:80, 20:80, lap[2][2] / 2] #print lap[2][2]/2 #get_csd_gfa(f_name,data,gtab,dataslice) maskdata, mask = median_otsu(data, 2, 1, False, vol_idx=range(10, 50), dilate=2) #不去背景 """ get fa and tensor evecs and ODF""" from dipy.reconst.dti import TensorModel, mean_diffusivity tenmodel = TensorModel(gtab) tenfit = tenmodel.fit(data, mask) sphere = get_sphere('symmetric724') FA = fractional_anisotropy(tenfit.evals) FA[np.isnan(FA)] = 0 np.save(os.getcwd() + '\zhibiao' + f_name + '_FA.npy', FA) fa_img = nib.Nifti1Image(FA.astype(np.float32), affine) nib.save(fa_img, os.getcwd() + '\zhibiao' + f_name + '_FA.nii.gz') print('Saving "DTI_tensor_fa.nii.gz" sucessful.') evecs_img = nib.Nifti1Image(tenfit.evecs.astype(np.float32), affine) nib.save(evecs_img, os.getcwd() + '\zhibiao' + f_name + '_DTI_tensor_evecs.nii.gz') print('Saving "DTI_tensor_evecs.nii.gz" sucessful.') MD1 = mean_diffusivity(tenfit.evals) nib.save(nib.Nifti1Image(MD1.astype(np.float32), img.get_affine()), os.getcwd() + '\zhibiao' + f_name + '_MD.nii.gz') #tensor_odfs = tenmodel.fit(data[20:50, 55:85, 38:39]).odf(sphere) #from dipy.reconst.odf import gfa #dti_gfa=gfa(tensor_odfs) wm_mask = (np.logical_or(FA >= 0.4, (np.logical_and(FA >= 0.15, MD >= 0.0011)))) response = recursive_response(gtab, data, mask=wm_mask, sh_order=8, peak_thr=0.01, init_fa=0.08, init_trace=0.0021, iter=8, convergence=0.001, parallel=False) from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel csd_model = ConstrainedSphericalDeconvModel(gtab, response) #csd_fit = csd_model.fit(data) from dipy.direction import peaks_from_model csd_peaks = peaks_from_model(model=csd_model, data=data, sphere=sphere, relative_peak_threshold=.5, min_separation_angle=25, parallel=False) GFA = csd_peaks.gfa nib.save(GFA, os.getcwd() + '\zhibiao' + f_name + '_MSD.nii.gz') print('Saving "GFA.nii.gz" sucessful.') from dipy.reconst.shore import ShoreModel asm = ShoreModel(gtab) print('Calculating...SHORE msd') asmfit = asm.fit(data, mask) msd = asmfit.msd() msd[np.isnan(msd)] = 0 #print GFA[:,:,slice].T print('Saving msd_img.png') nib.save(msd, os.getcwd() + '\zhibiao' + f_name + '_GFA.nii.gz')
def main(): parser = _build_arg_parser() args = parser.parse_args() logging.basicConfig(level=logging.INFO) assert_inputs_exist(parser, [args.input, args.bvals, args.bvecs, args.frf_file]) assert_outputs_exist(parser, args, args.out_fODF) # Loading data full_frf = np.loadtxt(args.frf_file) vol = nib.load(args.input) data = vol.get_fdata(dtype=np.float32) bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) # Checking mask if args.mask is None: mask = None else: mask = get_data_as_mask(nib.load(args.mask), dtype=bool) if mask.shape != data.shape[:-1]: raise ValueError("Mask is not the same shape as data.") sh_order = args.sh_order # Checking data and sh_order check_b0_threshold(args.force_b0_threshold, bvals.min()) if data.shape[-1] < (sh_order + 1) * (sh_order + 2) / 2: logging.warning( 'We recommend having at least {} unique DWI volumes, but you ' 'currently have {} volumes. Try lowering the parameter sh_order ' 'in case of non convergence.'.format( (sh_order + 1) * (sh_order + 2) / 2, data.shape[-1])) # Checking bvals, bvecs values and loading gtab if not is_normalized_bvecs(bvecs): logging.warning('Your b-vectors do not seem normalized...') bvecs = normalize_bvecs(bvecs) gtab = gradient_table(bvals, bvecs, b0_threshold=bvals.min()) # Checking full_frf and separating it if not full_frf.shape[0] == 4: raise ValueError('FRF file did not contain 4 elements. ' 'Invalid or deprecated FRF format') frf = full_frf[0:3] mean_b0_val = full_frf[3] # Loading the sphere reg_sphere = get_sphere('symmetric362') # Computing CSD csd_model = ConstrainedSphericalDeconvModel(gtab, (frf, mean_b0_val), reg_sphere=reg_sphere, sh_order=sh_order) # Computing CSD fit csd_fit = fit_from_model(csd_model, data, mask=mask, nbr_processes=args.nbr_processes) # Saving results shm_coeff = csd_fit.shm_coeff if args.sh_basis == 'tournier07': shm_coeff = convert_sh_basis(shm_coeff, reg_sphere, mask=mask, nbr_processes=args.nbr_processes) nib.save(nib.Nifti1Image(shm_coeff.astype(np.float32), vol.affine), args.out_fODF)
def run(self, input_files, bvalues_files, bvectors_files, mask_files, b0_threshold=50.0, bvecs_tol=0.01, roi_center=None, roi_radius=10, fa_thr=0.7, frf=None, extract_pam_values=False, sh_order=8, odf_to_sh_order=8, parallel=False, nbr_processes=None, out_dir='', out_pam='peaks.pam5', out_shm='shm.nii.gz', out_peaks_dir='peaks_dirs.nii.gz', out_peaks_values='peaks_values.nii.gz', out_peaks_indices='peaks_indices.nii.gz', out_gfa='gfa.nii.gz'): """ Constrained spherical deconvolution Parameters ---------- input_files : string Path to the input volumes. This path may contain wildcards to process multiple inputs at once. bvalues_files : string Path to the bvalues files. This path may contain wildcards to use multiple bvalues files at once. bvectors_files : string Path to the bvectors files. This path may contain wildcards to use multiple bvectors files at once. mask_files : string Path to the input masks. This path may contain wildcards to use multiple masks at once. (default: No mask used) b0_threshold : float, optional Threshold used to find b=0 directions bvecs_tol : float, optional Bvecs should be unit vectors. (default:0.01) roi_center : variable int, optional Center of ROI in data. If center is None, it is assumed that it is the center of the volume with shape `data.shape[:3]` (default None) roi_radius : int, optional radius of cubic ROI in voxels (default 10) fa_thr : float, optional FA threshold for calculating the response function (default 0.7) frf : variable float, optional Fiber response function can be for example inputed as 15 4 4 (from the command line) or [15, 4, 4] from a Python script to be converted to float and multiplied by 10**-4 . If None the fiber response function will be computed automatically (default: None). extract_pam_values : bool, optional Save or not to save pam volumes as single nifti files. sh_order : int, optional Spherical harmonics order (default 6) used in the CSA fit. odf_to_sh_order : int, optional Spherical harmonics order used for peak_from_model to compress the ODF to spherical harmonics coefficients (default 8) parallel : bool, optional Whether to use parallelization in peak-finding during the calibration procedure. Default: False nbr_processes : int, optional If `parallel` is True, the number of subprocesses to use (default multiprocessing.cpu_count()). out_dir : string, optional Output directory (default input file directory) out_pam : string, optional Name of the peaks volume to be saved (default 'peaks.pam5') out_shm : string, optional Name of the spherical harmonics volume to be saved (default 'shm.nii.gz') out_peaks_dir : string, optional Name of the peaks directions volume to be saved (default 'peaks_dirs.nii.gz') out_peaks_values : string, optional Name of the peaks values volume to be saved (default 'peaks_values.nii.gz') out_peaks_indices : string, optional Name of the peaks indices volume to be saved (default 'peaks_indices.nii.gz') out_gfa : string, optional Name of the generalized FA volume to be saved (default 'gfa.nii.gz') 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. """ io_it = self.get_io_iterator() for (dwi, bval, bvec, maskfile, opam, oshm, opeaks_dir, opeaks_values, opeaks_indices, ogfa) in io_it: logging.info('Loading {0}'.format(dwi)) data, affine = load_nifti(dwi) bvals, bvecs = read_bvals_bvecs(bval, bvec) print(b0_threshold, bvals.min()) if b0_threshold < bvals.min(): warn("b0_threshold (value: {0}) is too low, increase your " "b0_threshold. It should be higher than the first b0 value " "({1}).".format(b0_threshold, bvals.min())) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold, atol=bvecs_tol) mask_vol = load_nifti_data(maskfile).astype(np.bool) n_params = ((sh_order + 1) * (sh_order + 2)) / 2 if data.shape[-1] < n_params: raise ValueError( 'You need at least {0} unique DWI volumes to ' 'compute fiber odfs. You currently have: {1}' ' DWI volumes.'.format(n_params, data.shape[-1])) if frf is None: logging.info('Computing response function') if roi_center is not None: logging.info('Response ROI center:\n{0}' .format(roi_center)) logging.info('Response ROI radius:\n{0}' .format(roi_radius)) response, ratio, nvox = auto_response( gtab, data, roi_center=roi_center, roi_radius=roi_radius, fa_thr=fa_thr, return_number_of_voxels=True) response = list(response) else: logging.info('Using response function') if isinstance(frf, str): l01 = np.array(literal_eval(frf), dtype=np.float64) else: l01 = np.array(frf, dtype=np.float64) l01 *= 10 ** -4 response = np.array([l01[0], l01[1], l01[1]]) ratio = l01[1] / l01[0] response = (response, ratio) logging.info("Eigenvalues for the frf of the input" " data are :{0}".format(response[0])) logging.info('Ratio for smallest to largest eigen value is {0}' .format(ratio)) peaks_sphere = default_sphere logging.info('CSD computation started.') csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=sh_order) peaks_csd = peaks_from_model(model=csd_model, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=mask_vol, return_sh=True, sh_order=sh_order, normalize_peaks=True, parallel=parallel, nbr_processes=nbr_processes) peaks_csd.affine = affine save_peaks(opam, peaks_csd) logging.info('CSD computation completed.') if extract_pam_values: peaks_to_niftis(peaks_csd, oshm, opeaks_dir, opeaks_values, opeaks_indices, ogfa, reshape_dirs=True) dname_ = os.path.dirname(opam) if dname_ == '': logging.info('Pam5 file saved in current directory') else: logging.info( 'Pam5 file saved in {0}'.format(dname_)) return io_it
def run(context): #################################################### # Get the path to input files and other parameter # #################################################### analysis_data = context.fetch_analysis_data() settings = analysis_data['settings'] postprocessing = settings['postprocessing'] hcpl_dwi_file_handle = context.get_files('input', modality='HARDI')[0] hcpl_dwi_file_path = hcpl_dwi_file_handle.download('/root/') hcpl_bvalues_file_handle = context.get_files( 'input', reg_expression='.*prep.bvalues.hcpl.txt')[0] hcpl_bvalues_file_path = hcpl_bvalues_file_handle.download('/root/') hcpl_bvecs_file_handle = context.get_files( 'input', reg_expression='.*prep.gradients.hcpl.txt')[0] hcpl_bvecs_file_path = hcpl_bvecs_file_handle.download('/root/') dwi_file_handle = context.get_files('input', modality='DSI')[0] dwi_file_path = dwi_file_handle.download('/root/') bvalues_file_handle = context.get_files( 'input', reg_expression='.*prep.bvalues.txt')[0] bvalues_file_path = bvalues_file_handle.download('/root/') bvecs_file_handle = context.get_files( 'input', reg_expression='.*prep.gradients.txt')[0] bvecs_file_path = bvecs_file_handle.download('/root/') inject_file_handle = context.get_files( 'input', reg_expression='.*prep.inject.nii.gz')[0] inject_file_path = inject_file_handle.download('/root/') VUMC_ROIs_file_handle = context.get_files( 'input', reg_expression='.*VUMC_ROIs.nii.gz')[0] VUMC_ROIs_file_path = VUMC_ROIs_file_handle.download('/root/') ############################### # _____ _____ _______ __ # # | __ \_ _| __ \ \ / / # # | | | || | | |__) \ \_/ / # # | | | || | | ___/ \ / # # | |__| || |_| | | | # # |_____/_____|_| |_| # # # # dipy.org/documentation # ############################### # IronTract Team # # TrackyMcTrackface # ############################### ################# # Load the data # ################# dwi_img = nib.load(hcpl_dwi_file_path) bvals, bvecs = read_bvals_bvecs(hcpl_bvalues_file_path, hcpl_bvecs_file_path) gtab = gradient_table(bvals, bvecs) ############################################ # Extract the brain mask from the b0 image # ############################################ _, brain_mask = median_otsu(dwi_img.get_data()[:, :, :, 0], median_radius=2, numpass=1) ################################################################## # Fit the tensor model and compute the fractional anisotropy map # ################################################################## context.set_progress(message='Processing voxel-wise DTI metrics.') tenmodel = TensorModel(gtab) tenfit = tenmodel.fit(dwi_img.get_data(), mask=brain_mask) FA = fractional_anisotropy(tenfit.evals) # fa_file_path = "/root/fa.nii.gz" # nib.Nifti1Image(FA,dwi_img.affine).to_filename(fa_file_path) ################################################ # Compute Fiber Orientation Distribution (CSD) # ################################################ context.set_progress(message='Processing voxel-wise FOD estimation.') response, _ = auto_response_ssst(gtab, dwi_img.get_data(), roi_radii=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(dwi_img.get_data(), mask=brain_mask) # fod_file_path = "/root/fod.nii.gz" # nib.Nifti1Image(csd_fit.shm_coeff,dwi_img.affine).to_filename(fod_file_path) ########################################### # Compute DIPY Probabilistic Tractography # ########################################### context.set_progress(message='Processing tractography.') sphere = get_sphere("repulsion724") seed_mask_img = nib.load(inject_file_path) affine = seed_mask_img.affine seeds = utils.seeds_from_mask(seed_mask_img.get_data(), affine, density=5) stopping_criterion = ThresholdStoppingCriterion(FA, 0.2) prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=20., sphere=sphere) streamline_generator = LocalTracking(prob_dg, stopping_criterion, seeds, affine, step_size=.2, max_cross=1) streamlines = Streamlines(streamline_generator) # sft = StatefulTractogram(streamlines, seed_mask_img, Space.RASMM) # streamlines_file_path = "/root/streamlines.trk" # save_trk(sft, streamlines_file_path) ########################################################################### # Compute 3D volumes for the IronTract Challenge. For 'EPFL', we only # # keep streamlines with length > 1mm. We compute the visitation count # # image and apply a small gaussian smoothing. The gaussian smoothing # # is especially usefull to increase voxel coverage of deterministic # # algorithms. The log of the smoothed visitation count map is then # # iteratively thresholded producing 200 volumes/operation points. # # For VUMC, additional streamline filtering is done using anatomical # # priors (keeping only streamlines that intersect with at least one ROI). # ########################################################################### if postprocessing in ["EPFL", "ALL"]: context.set_progress(message='Processing density map (EPFL)') volume_folder = "/root/vol_epfl" output_epfl_zip_file_path = "/root/TrackyMcTrackface_EPFL_example.zip" os.mkdir(volume_folder) lengths = length(streamlines) streamlines = streamlines[lengths > 1] density = utils.density_map(streamlines, affine, seed_mask_img.shape) density = scipy.ndimage.gaussian_filter(density.astype("float32"), 0.5) log_density = np.log10(density + 1) max_density = np.max(log_density) for i, t in enumerate(np.arange(0, max_density, max_density / 200)): nbr = str(i) nbr = nbr.zfill(3) mask = log_density >= t vol_filename = os.path.join( volume_folder, "vol" + nbr + "_t" + str(t) + ".nii.gz") nib.Nifti1Image(mask.astype("int32"), affine, seed_mask_img.header).to_filename(vol_filename) shutil.make_archive(output_epfl_zip_file_path[:-4], 'zip', volume_folder) if postprocessing in ["VUMC", "ALL"]: context.set_progress(message='Processing density map (VUMC)') ROIs_img = nib.load(VUMC_ROIs_file_path) volume_folder = "/root/vol_vumc" output_vumc_zip_file_path = "/root/TrackyMcTrackface_VUMC_example.zip" os.mkdir(volume_folder) lengths = length(streamlines) streamlines = streamlines[lengths > 1] rois = ROIs_img.get_fdata().astype(int) _, grouping = utils.connectivity_matrix(streamlines, affine, rois, inclusive=True, return_mapping=True, mapping_as_streamlines=False) streamlines = streamlines[grouping[(0, 1)]] density = utils.density_map(streamlines, affine, seed_mask_img.shape) density = scipy.ndimage.gaussian_filter(density.astype("float32"), 0.5) log_density = np.log10(density + 1) max_density = np.max(log_density) for i, t in enumerate(np.arange(0, max_density, max_density / 200)): nbr = str(i) nbr = nbr.zfill(3) mask = log_density >= t vol_filename = os.path.join( volume_folder, "vol" + nbr + "_t" + str(t) + ".nii.gz") nib.Nifti1Image(mask.astype("int32"), affine, seed_mask_img.header).to_filename(vol_filename) shutil.make_archive(output_vumc_zip_file_path[:-4], 'zip', volume_folder) ################### # Upload the data # ################### context.set_progress(message='Uploading results...') # context.upload_file(fa_file_path, 'fa.nii.gz') # context.upload_file(fod_file_path, 'fod.nii.gz') # context.upload_file(streamlines_file_path, 'streamlines.trk') if postprocessing in ["EPFL", "ALL"]: context.upload_file(output_epfl_zip_file_path, 'TrackyMcTrackface_EPFL_example.zip') if postprocessing in ["VUMC", "ALL"]: context.upload_file(output_vumc_zip_file_path, 'TrackyMcTrackface_VUMC_example.zip')
def get_csd_streamlines(data_container, random_seeds=False, seeds_count=30000, seeds_per_voxel=False, step_width=1.0, roi_r=10, auto_response_fa_threshold=0.7, fa_threshold=0.15, relative_peak_threshold=0.5, min_separation_angle=25): """ Tracks and returns CSD Streamlines for the given DataContainer. Parameters ---------- data_container The DataContainer we would like to track streamlines on random_seeds A boolean indicating whether we would like to use random seeds seeds_count If we use random seeds, this specifies the seed count seeds_per_voxel If True, the seed count is specified per voxel step_width The step width used while tracking roi_r The radii of the cuboid roi for the automatic estimation of single-shell single-tissue response function using FA. auto_response_fa_threshold The FA threshold for the automatic estimation of single-shell single-tissue response function using FA. fa_threshold The FA threshold to use to stop tracking relative_peak_threshold The relative peak threshold to use to get peaks from the CSDModel min_separation_angle The minimal separation angle of peaks Returns ------- Streamlines A list of Streamlines """ seeds = _get_seeds(data_container, random_seeds, seeds_count, seeds_per_voxel) response, _ = auto_response_ssst(data_container.gtab, data_container.dwi, roi_radii=roi_r, fa_thr=auto_response_fa_threshold) csd_model = ConstrainedSphericalDeconvModel(data_container.gtab, response) direction_getter = peaks_from_model( model=csd_model, data=data_container.dwi, sphere=get_sphere('symmetric724'), mask=data_container.binary_mask, relative_peak_threshold=relative_peak_threshold, min_separation_angle=min_separation_angle, parallel=False) dti_fit = dti.TensorModel(data_container.gtab, fit_method='LS').fit( data_container.dwi, mask=data_container.binary_mask) classifier = ThresholdStoppingCriterion(dti_fit.fa, fa_threshold) streamlines_generator = LocalTracking(direction_getter, classifier, seeds, data_container.aff, step_size=step_width) streamlines = Streamlines(streamlines_generator) return streamlines
from dipy.tracking import utils from dipy.viz import window, actor, colormap as cmap renderer = window.Renderer() img_pve_csf, img_pve_gm, img_pve_wm = read_stanford_pve_maps() hardi_img, gtab, labels_img = read_stanford_labels() data = hardi_img.get_data() labels = labels_img.get_data() affine = hardi_img.affine shape = labels.shape response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd_model.fit(data, mask=img_pve_wm.get_data()) dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=20., sphere=default_sphere) """ CMC/ACT Tissue Classifiers --------------------- Continuous map criterion (CMC) [Girard2014]_ and Anatomically-constrained tractography (ACT) [Smith2012]_ both uses PVEs information from anatomical images to determine when the tractography stops. Both tissue classifiers use a trilinear interpolation at the tracking position. CMC tissue classifier uses a probability derived from
data, affine, hardi_img = load_nifti(hardi_fname, return_img=True) labels = load_nifti_data(label_fname) bvals, bvecs = read_bvals_bvecs(hardi_bval_fname, hardi_bvec_fname) gtab = gradient_table(bvals, bvecs) seed_mask = (labels == 2) white_matter = (labels == 1) | (labels == 2) seeds = utils.seeds_from_mask(seed_mask, affine, density=1) """ Next, we fit the CSD model. """ response, ratio = auto_response_ssst(gtab, data, roi_radii=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) """ we use the CSA fit to calculate GFA, which will serve as our stopping criterion. """ csa_model = CsaOdfModel(gtab, sh_order=6) gfa = csa_model.fit(data, mask=white_matter).gfa stopping_criterion = ThresholdStoppingCriterion(gfa, .25) """ Next, we need to set up our two direction getters """
model = sfm.SparseFascicleModel(gtab, sphere=sphere, l1_ratio=0.5, alpha=0.001, response=response[0]) odf = model.fit(data, mask=mask).odf(sphere) elif model_type == 'CSD': print('Fitting CSD') print("sh_order: ", sh_order) print("fa_thr: ", fa_thr) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=fa_thr) model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=sh_order) odf = model.fit(data).odf(sphere) elif model_type == 'Opdt': print('Orientation Probability Density Transform') print("sh_order: ", sh_order) print("smooth: ", smooth) model = OpdtModel(gtab=gtab, sh_order=sh_order, smooth=smooth) odf = model.fit(data, mask=mask).odf(sphere) else: raise ValueError( 'Model type not supported. Available models: 3D-SHORE, CSA-QBALL, SFM, CSD, Opdt' ) odf = np.nan_to_num(odf) print('Preparing ODF image')
def test_csdeconv(): SNR = 100 S0 = 1 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric362') odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) assert_equal(csd_fit.shm_coeff[0] > 0, True) fodf = csd_fit.odf(sphere) directions, _, _ = peak_directions(odf_gt, sphere) directions2, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions, directions2) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) assert_equal(directions2.shape[0], 2) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=10) assert_equal(len(w) > 0, True) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) assert_equal(len(w) > 0, False) mevecs = [] for s in sticks: mevecs += [all_tensor_evecs(s).T] S2 = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) big_S = np.zeros((10, 10, 10, len(S2))) big_S[:] = S2 aresponse, aratio = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) assert_almost_equal(aresponse[1], 100) assert_almost_equal(aratio, response[0][1]/response[0][0]) aresponse2, aratio2 = auto_response(gtab, big_S, roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0])
labels_img_csf = dipy.data.load(label_filename_csf) labels_csf = labels_img_csf.get_data() shape = labels_csf.shape bvals = os.path.join( "/home/nrajamani/Downloads/DIPYDATA/sub-control201/ses-01/dwi", "bvals") bvecs = os.path.join( "/home/nrajamani/Downloads/DIPYDATA/sub-control201/ses-01/dwi", "bvecs") gtab = gradient_table(bvals, bvecs) #gtab = os.path.join("/home/nrajamani/Downloads/HNU1/data/","gtab.bval") #gtab = dipy.data.load(gtab) #affine = hardi_img.affine response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csa_model = ConstrainedSphericalDeconvModel(gtab, response) csa_fit = csa_model.fit(data, mask=labels_wm) dg = ProbabilisticDirectionGetter.from_shcoeff(csa_fit.shm_coeff, max_angle=20., sphere=default_sphere) #Continous Map Criterion and Anatomically Constrainted Tractography(ACT) BOTH USES PVEs information from anatomical images to determine when the tractography stops. #Both tssue classifiers use a trilinear interpolation at the tracing position CMC tissue classifier uses a probability derived frm the PVE maps to determine if the #streamline reaches a 'valid' or 'invalid' region.ACT uses a fixed threshold on the PVE maps. Both tissue classifiers used in conjuction with PFT. voxel_size = 1 #avg_vox_size = np.average(voxel_size) step_size = 0.2 cmc_classifier = CmcTissueClassifier.from_pve(labels_img_wm.get_data(), labels_img_gm.get_data(), labels_img_csf.get_data(),
def main(): parser = _build_arg_parser() args = parser.parse_args() logging.basicConfig(level=logging.INFO) if not args.not_all: args.fodf = args.fodf or 'fodf.nii.gz' args.peaks = args.peaks or 'peaks.nii.gz' args.peak_indices = args.peak_indices or 'peak_indices.nii.gz' arglist = [args.fodf, args.peaks, args.peak_indices] if args.not_all and not any(arglist): parser.error('When using --not_all, you need to specify at least ' 'one file to output.') assert_inputs_exist(parser, [args.input, args.bvals, args.bvecs]) assert_outputs_exists(parser, args, arglist) nbr_processes = args.nbr_processes parallel = True if nbr_processes <= 0: nbr_processes = None elif nbr_processes == 1: parallel = False # Check for FRF filename base_odf_name, _ = split_name_with_nii(args.fodf) frf_filename = base_odf_name + '_frf.txt' if os.path.isfile(frf_filename) and not args.overwrite: parser.error('Cannot save frf file, "{0}" already exists. ' 'Use -f to overwrite.'.format(frf_filename)) vol = nib.load(args.input) data = vol.get_data() bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) if args.mask_wm is not None: wm_mask = nib.load(args.mask_wm).get_data().astype('bool') else: wm_mask = np.ones_like(data[..., 0], dtype=np.bool) logging.info( 'No white matter mask specified! mask_data will be used instead, ' 'if it has been supplied. \nBe *VERY* careful about the ' 'estimation of the fiber response function for the CSD.') data_in_wm = applymask(data, wm_mask) if not is_normalized_bvecs(bvecs): logging.warning('Your b-vectors do not seem normalized...') bvecs = normalize_bvecs(bvecs) if bvals.min() != 0: if bvals.min() > 20: raise ValueError( 'The minimal bvalue is greater than 20. This is highly ' 'suspicious. Please check your data to ensure everything is ' 'correct.\nValue found: {}'.format(bvals.min())) else: logging.warning( 'Warning: no b=0 image. Setting b0_threshold to ' 'bvals.min() = %s', bvals.min()) gtab = gradient_table(bvals, bvecs, b0_threshold=bvals.min()) else: gtab = gradient_table(bvals, bvecs) if args.mask is None: mask = None else: mask = nib.load(args.mask).get_data().astype(np.bool) # Raise warning for sh order if there is not enough DWIs if data.shape[-1] < (args.sh_order + 1) * (args.sh_order + 2) / 2: warnings.warn( 'We recommend having at least %s unique DWIs volumes, but you ' 'currently have %s volumes. Try lowering the parameter --sh_order ' 'in case of non convergence.', (args.sh_order + 1) * (args.sh_order + 2) / 2), data.shape[-1] fa_thresh = args.fa_thresh # If threshold is too high, try lower until enough indices are found # estimating a response function with fa < 0.5 does not make sense nvox = 0 while nvox < 300 and fa_thresh > 0.5: response, ratio, nvox = auto_response(gtab, data_in_wm, roi_center=args.roi_center, roi_radius=args.roi_radius, fa_thr=fa_thresh, return_number_of_voxels=True) logging.info('Number of indices is %s with threshold of %s', nvox, fa_thresh) fa_thresh -= 0.05 if fa_thresh <= 0: raise ValueError( 'Could not find at least 300 voxels for estimating the frf!') logging.info('Found %s valid voxels for frf estimation.', nvox) response = list(response) logging.info('Response function is %s', response) if args.frf is not None: l01 = np.array(literal_eval(args.frf), dtype=np.float64) if not args.no_factor: l01 *= 10**-4 response[0] = np.array([l01[0], l01[1], l01[1]]) ratio = l01[1] / l01[0] logging.info("Eigenvalues for the frf of the input data are: %s", response[0]) logging.info("Ratio for smallest to largest eigen value is %s", ratio) np.savetxt(frf_filename, response[0]) if not args.frf_only: reg_sphere = get_sphere('symmetric362') peaks_sphere = get_sphere('symmetric724') csd_model = ConstrainedSphericalDeconvModel(gtab, response, reg_sphere=reg_sphere, sh_order=args.sh_order) peaks_csd = peaks_from_model(model=csd_model, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=mask, return_sh=True, sh_basis_type=args.basis, sh_order=args.sh_order, normalize_peaks=True, parallel=parallel, nbr_processes=nbr_processes) if args.fodf: nib.save( nib.Nifti1Image(peaks_csd.shm_coeff.astype(np.float32), vol.affine), args.fodf) if args.peaks: nib.save( nib.Nifti1Image(reshape_peaks_for_visualization(peaks_csd), vol.affine), args.peaks) if args.peak_indices: nib.save(nib.Nifti1Image(peaks_csd.peak_indices, vol.affine), args.peak_indices)
def dwi_dipy_run(dwi_dir, node_size, dir_path, conn_model, parc, atlas_select, network, wm_mask=None): import os import glob import re import nipype.interfaces.fsl as fsl from dipy.reconst.dti import TensorModel, quantize_evecs from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel, recursive_response from dipy.tracking.local import LocalTracking, ThresholdTissueClassifier from dipy.tracking import utils from dipy.direction import peaks_from_model from dipy.tracking.eudx import EuDX from dipy.data import get_sphere from dipy.core.gradients import gradient_table from dipy.io import read_bvals_bvecs def atoi(text): return int(text) if text.isdigit() else text def natural_keys(text): return [atoi(c) for c in re.split('(\d+)', text)] dwi_img = "%s%s" % (dwi_dir, '/dwi.nii.gz') nodif_brain_mask_path = "%s%s" % (dwi_dir, '/nodif_brain_mask.nii.gz') bvals = "%s%s" % (dwi_dir, '/bval') bvecs = "%s%s" % (dwi_dir, '/bvec') img = nib.load(dwi_img) data = img.get_data() # Loads mask and ensures it's a true binary mask img = nib.load(nodif_brain_mask_path) mask = img.get_data() mask = mask > 0 [bvals, bvecs] = read_bvals_bvecs(bvals, bvecs) gtab = gradient_table(bvals, bvecs) # Estimates some tensors model = TensorModel(gtab) ten = model.fit(data, mask) sphere = get_sphere('symmetric724') ind = quantize_evecs(ten.evecs, sphere.vertices) # Tractography if conn_model == 'csd': trac_mod = 'csd' else: conn_model = 'tensor' trac_mod = ten.fa affine = img.affine print('Tracking with tensor model...') if wm_mask is None: mask = nib.load(mask).get_data() mask[0, :, :] = False mask[:, 0, :] = False mask[:, :, 0] = False seeds = utils.seeds_from_mask(mask, density=2) else: wm_mask_data = nib.load(wm_mask).get_data() wm_mask_data[0, :, :] = False wm_mask_data[:, 0, :] = False wm_mask_data[:, :, 0] = False seeds = utils.seeds_from_mask(wm_mask_data, density=2) #seeds = random_seeds_from_mask(ten.fa > 0.3, seeds_count=num_total_samples) if conn_model == 'tensor': eu = EuDX(a=trac_mod, ind=ind, seeds=seeds, odf_vertices=sphere.vertices, a_low=0.05, step_sz=.5) tracks = [e for e in eu] elif conn_model == 'csd': print('Tracking with CSD model...') if wm_mask is None: response = recursive_response(gtab, data, mask=mask.astype('bool'), sh_order=8, peak_thr=0.01, init_fa=0.08, init_trace=0.0021, iter=8, convergence=0.001, parallel=True) else: response = recursive_response(gtab, data, mask=wm_mask_data.astype('bool'), sh_order=8, peak_thr=0.01, init_fa=0.08, init_trace=0.0021, iter=8, convergence=0.001, parallel=True) csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_peaks = peaks_from_model(model=csd_model, data=data, sphere=sphere, relative_peak_threshold=.5, min_separation_angle=25, parallel=True) tissue_classifier = ThresholdTissueClassifier(ten.fa, 0.1) streamline_generator = LocalTracking(csd_peaks, tissue_classifier, seeds, affine=affine, step_size=0.5) tracks = [e for e in streamline_generator] if parc is True: node_size = 'parc' if network: seeds_dir = "%s%s%s%s%s%s%s" % (dir_path, '/seeds_', network, '_', atlas_select, '_', str(node_size)) else: seeds_dir = "%s%s%s%s%s" % (dir_path, '/seeds_', atlas_select, '_', str(node_size)) seed_files = glob.glob("%s%s" % (seeds_dir, '/*diff.nii.gz')) seed_files.sort(key=natural_keys) # Binarize ROIs print('\nBinarizing seed masks...') j = 1 for i in seed_files: args = ' -bin ' out_file = "%s%s" % (i.split('.nii.gz')[0], '_bin.nii.gz') maths = fsl.ImageMaths(in_file=i, op_string=args, out_file=out_file) os.system(maths.cmdline) args = ' -mul ' + str(j) maths = fsl.ImageMaths(in_file=out_file, op_string=args, out_file=out_file) os.system(maths.cmdline) j = j + 1 # Create atlas from ROIs seed_files = glob.glob("%s%s" % (seeds_dir, '/*diff_bin.nii.gz')) seed_files.sort(key=natural_keys) print('\nMerging seed masks into single labels image...') label_sum = "%s%s" % (seeds_dir, '/all_rois.nii.gz') args = ' -add ' + i maths = fsl.ImageMaths(in_file=seed_files[0], op_string=args, out_file=label_sum) os.system(maths.cmdline) for i in seed_files: args = ' -add ' + i maths = fsl.ImageMaths(in_file=label_sum, op_string=args, out_file=label_sum) os.system(maths.cmdline) labels_im = nib.load(label_sum) labels_data = labels_im.get_data().astype('int') conn_matrix, grouping = utils.connectivity_matrix( tracks, labels_data, affine=affine, return_mapping=True, mapping_as_streamlines=True) conn_matrix[:3, :] = 0 conn_matrix[:, :3] = 0 return conn_matrix
def test_recursive_response_calibration(): """ Test the recursive response calibration method. """ SNR = 100 S0 = 1 sh_order = 8 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) sphere = get_sphere('symmetric724') gtab = gradient_table(bvals, bvecs) evals = np.array([0.0015, 0.0003, 0.0003]) evecs = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]).T mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (90, 0)] where_dwi = lazy_index(~gtab.b0s_mask) S_cross, sticks_cross = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) S_single = single_tensor(gtab, S0, evals, evecs, snr=SNR) data = np.concatenate((np.tile(S_cross, (8, 1)), np.tile(S_single, (2, 1))), axis=0) odf_gt_cross = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) odf_gt_single = single_tensor_odf(sphere.vertices, evals, evecs) response = recursive_response(gtab, data, mask=None, sh_order=8, peak_thr=0.01, init_fa=0.05, init_trace=0.0021, iter=8, convergence=0.001, parallel=False) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(data) assert_equal(np.all(csd_fit.shm_coeff[:, 0] >= 0), True) fodf = csd_fit.odf(sphere) directions_gt_single, _, _ = peak_directions(odf_gt_single, sphere) directions_gt_cross, _, _ = peak_directions(odf_gt_cross, sphere) directions_single, _, _ = peak_directions(fodf[8, :], sphere) directions_cross, _, _ = peak_directions(fodf[0, :], sphere) ang_sim = angular_similarity(directions_cross, directions_gt_cross) assert_equal(ang_sim > 1.9, True) assert_equal(directions_cross.shape[0], 2) assert_equal(directions_gt_cross.shape[0], 2) ang_sim = angular_similarity(directions_single, directions_gt_single) assert_equal(ang_sim > 0.9, True) assert_equal(directions_single.shape[0], 1) assert_equal(directions_gt_single.shape[0], 1) sphere = Sphere(xyz=gtab.gradients[where_dwi]) sf = response.on_sphere(sphere) S = np.concatenate(([response.S0], sf)) tenmodel = dti.TensorModel(gtab, min_signal=0.001) tenfit = tenmodel.fit(S) FA = fractional_anisotropy(tenfit.evals) FA_gt = fractional_anisotropy(evals) assert_almost_equal(FA, FA_gt, 1)
data_noisy = add_noise(data, 1, np.mean(data[mask]), noise_type='rician') # Select a small part of it data_small = data[25:40, 65:80, 35:42] data_noisy_small = data_noisy[25:40, 65:80, 35:42] """ Fit an initial model to the data, in this case Constrained Spherical Deconvolution is used. """ # Perform CSD on the original data from dipy.reconst.csdeconv import auto_response from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model_orig = ConstrainedSphericalDeconvModel(gtab, response) csd_fit_orig = csd_model_orig.fit(data_small) csd_shm_orig = csd_fit_orig.shm_coeff # Perform CSD on the original data + noise response, ratio = auto_response(gtab, data_noisy, roi_radius=10, fa_thr=0.7) csd_model_noisy = ConstrainedSphericalDeconvModel(gtab, response) csd_fit_noisy = csd_model_noisy.fit(data_noisy_small) csd_shm_noisy = csd_fit_noisy.shm_coeff """ Inspired by [RodriguesEurographics_], a lookup-table is created, containing rotated versions of the kernel :math:`P_t` sampled over a discrete set of orientations. In order to ensure rotationally invariant processing, the discrete orientations are required to be equally distributed over a sphere. Per default, a sphere with 100 directions is used.
def test_csdeconv(): SNR = 100 S0 = 1 _, fbvals, fbvecs = get_data('small_64D') bvals = np.load(fbvals) bvecs = np.load(fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = multi_tensor(gtab, mevals, S0, angles=angles, fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric362') odf_gt = multi_tensor_odf(sphere.vertices, mevals, angles, [50, 50]) response = (np.array([0.0015, 0.0003, 0.0003]), S0) csd = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd.fit(S) assert_equal(csd_fit.shm_coeff[0] > 0, True) fodf = csd_fit.odf(sphere) directions, _, _ = peak_directions(odf_gt, sphere) directions2, _, _ = peak_directions(fodf, sphere) ang_sim = angular_similarity(directions, directions2) assert_equal(ang_sim > 1.9, True) assert_equal(directions.shape[0], 2) assert_equal(directions2.shape[0], 2) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=10) assert_equal(len(w) > 0, True) with warnings.catch_warnings(record=True) as w: ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) assert_equal(len(w) > 0, False) mevecs = [] for s in sticks: mevecs += [all_tensor_evecs(s).T] S2 = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) big_S = np.zeros((10, 10, 10, len(S2))) big_S[:] = S2 aresponse, aratio = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) assert_almost_equal(aresponse[1], 100) assert_almost_equal(aratio, response[0][1] / response[0][0]) aresponse2, aratio2 = auto_response(gtab, big_S, roi_radius=3, fa_thr=0.5) assert_array_almost_equal(aresponse[0], response[0]) _, _, nvoxels = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=30, fa_thr=0.5, return_number_of_voxels=True) assert_equal(nvoxels, 1000) _, _, nvoxels = auto_response(gtab, big_S, roi_center=(5, 5, 4), roi_radius=30, fa_thr=1, return_number_of_voxels=True) assert_equal(nvoxels, 0)
label_fname = get_fnames('stanford_labels') f_pve_csf, f_pve_gm, f_pve_wm = get_fnames('stanford_pve_maps') data, affine, hardi_img = load_nifti(hardi_fname, return_img=True) labels = load_nifti_data(label_fname) bvals, bvecs = read_bvals_bvecs(hardi_bval_fname, hardi_bvec_fname) gtab = gradient_table(bvals, bvecs) pve_csf_data = load_nifti_data(f_pve_csf) pve_gm_data = load_nifti_data(f_pve_gm) pve_wm_data, _, voxel_size = load_nifti(f_pve_wm, return_voxsize=True) shape = labels.shape response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) csd_fit = csd_model.fit(data, mask=pve_wm_data) dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=20., sphere=default_sphere) seed_mask = (labels == 2) seed_mask[pve_wm_data < 0.5] = 0 seeds = utils.seeds_from_mask(seed_mask, affine, density=2) """ CMC/ACT Stopping Criterion ========================== Continuous map criterion (CMC) [Girard2014]_ and Anatomically-constrained tractography (ACT) [Smith2012]_ both uses PVEs information from anatomical images to determine when the tractography stops.
def _run_interface(self, runtime): import numpy as np import nibabel as nib from dipy.io import read_bvals_bvecs from dipy.core.gradients import gradient_table from nipype.utils.filemanip import split_filename # Loading the data fname = self.inputs.in_file img = nib.load(fname) data = img.get_data() affine = img.get_affine() FA_fname = self.inputs.FA_file FA_img = nib.load(FA_fname) fa = FA_img.get_data() affine = FA_img.get_affine() affine = np.matrix.round(affine) mask_fname = self.inputs.brain_mask mask_img = nib.load(mask_fname) mask = mask_img.get_data() bval_fname = self.inputs.bval bvals = np.loadtxt(bval_fname) bvec_fname = self.inputs.bvec bvecs = np.loadtxt(bvec_fname) bvecs = np.vstack([bvecs[0,:],bvecs[1,:],bvecs[2,:]]).T gtab = gradient_table(bvals, bvecs) # Creating a white matter mask fa = fa*mask white_matter = fa >= 0.2 # Creating a seed mask from dipy.tracking import utils seeds = utils.seeds_from_mask(white_matter, density=[2, 2, 2], affine=affine) # Fitting the CSA model from dipy.reconst.shm import CsaOdfModel from dipy.data import default_sphere from dipy.direction import peaks_from_model csa_model = CsaOdfModel(gtab, sh_order=8) csa_peaks = peaks_from_model(csa_model, data, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=white_matter) from dipy.tracking.local import ThresholdTissueClassifier classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) # CSD model from dipy.reconst.csdeconv import (ConstrainedSphericalDeconvModel, auto_response) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=8) csd_fit = csd_model.fit(data, mask=white_matter) from dipy.direction import ProbabilisticDirectionGetter prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=45., sphere=default_sphere) # Tracking from dipy.tracking.local import LocalTracking streamlines = LocalTracking(prob_dg, classifier, seeds, affine, step_size=.5, maxlen=200, max_cross=1) # Compute streamlines and store as a list. streamlines = list(streamlines) # Saving the trackfile from dipy.io.trackvis import save_trk _, base, _ = split_filename(fname) save_trk(base + '_CSDprob.trk', streamlines, affine, fa.shape) return runtime
""" Enables/disables interactive visualization """ interactive = False """ Fit an initial model to the data, in this case Constrained Spherical Deconvolution is used. """ # Perform CSD on the original data from dipy.reconst.csdeconv import auto_response from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model_orig = ConstrainedSphericalDeconvModel(gtab, response) csd_fit_orig = csd_model_orig.fit(data_small) csd_shm_orig = csd_fit_orig.shm_coeff # Perform CSD on the original data + noise response, ratio = auto_response(gtab, data_noisy, roi_radius=10, fa_thr=0.7) csd_model_noisy = ConstrainedSphericalDeconvModel(gtab, response) csd_fit_noisy = csd_model_noisy.fit(data_noisy_small) csd_shm_noisy = csd_fit_noisy.shm_coeff """ Inspired by [Rodrigues2010]_, a lookup-table is created, containing rotated versions of the kernel :math:`P_t` sampled over a discrete set of orientations. In order to ensure rotationally invariant processing, the discrete orientations are required to be equally distributed over a sphere. By default, a sphere with 100 directions is used.
.. figure:: csd_recursive_response.png :align: center **Estimated response function using recursive calibration**. """ fvtk.rm(ren, response_actor) """ Now, that we have the response function, we are ready to start the deconvolution process. Let's import the CSD model and fit the datasets. """ from dipy.reconst.csdeconv import ConstrainedSphericalDeconvModel csd_model = ConstrainedSphericalDeconvModel(gtab, response) """ For illustration purposes we will fit only a small portion of the data. """ data_small = data[20:50, 55:85, 38:39] csd_fit = csd_model.fit(data_small) """ Show the CSD-based ODFs also known as FODFs (fiber ODFs). """ csd_odf = csd_fit.odf(sphere) """
def csd_mod_est(gtab, data, B0_mask, sh_order=8): """ 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 """ from dipy.reconst.csdeconv import ( ConstrainedSphericalDeconvModel, recursive_response, ) print("Fitting CSD model...") B0_mask_data = np.nan_to_num(np.asarray( nib.load(B0_mask).dataobj)).astype("bool") print("Reconstructing...") response = recursive_response(gtab, data, mask=B0_mask_data, sh_order=sh_order, peak_thr=0.01, init_fa=0.08, init_trace=0.0021, iter=8, convergence=0.001, parallel=False) print(f"CSD Reponse: {response}") model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=sh_order) csd_mod = model.fit(data, B0_mask_data).shm_coeff del response, B0_mask_data return csd_mod, model
voxel in the data set as a collection of small white matter fibers with different orientations. The density of fibers along each orientation is known as the Fiber Orientation Distribution (FOD). In order to perform probabilistic fiber tracking, we pick a fiber from the FOD at random at each new location along the streamline. Note: one could use this model to perform deterministic fiber tracking by always tracking along the directions that have the most fibers. Let's begin probabilistic fiber tracking by fitting the data to the CSD model. """ from dipy.reconst.csdeconv import (ConstrainedSphericalDeconvModel, auto_response) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) """ Next we'll need to make a ``ProbabilisticDirectionGetter``. Because the CSD model represents the FOD using the spherical harmonic basis, we can use the ``from_shcoeff`` method to create the direction getter. This direction getter will randomly sample directions from the FOD each time the tracking algorithm needs to take another step. """ from dipy.direction import ProbabilisticDirectionGetter prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere)
def run(self, input_files, bvalues, bvectors, mask_files, b0_threshold=0.0, frf=[15.0, 4.0, 4.0], extract_pam_values=False, out_dir='', out_pam='peaks.pam5', out_shm='shm.nii.gz', out_peaks_dir='peaks_dirs.nii.gz', out_peaks_values='peaks_values.nii.gz', out_peaks_indices='peaks_indices.nii.gz', out_gfa='gfa.nii.gz'): """ Workflow for peaks computation. Peaks computation is done by 'globing' ``input_files`` and saves the peaks in a directory specified by ``out_dir``. Parameters ---------- input_files : string Path to the input volumes. This path may contain wildcards to process multiple inputs at once. bvalues : string Path to the bvalues files. This path may contain wildcards to use multiple bvalues files at once. bvectors : string Path to the bvalues files. This path may contain wildcards to use multiple bvalues files at once. mask_files : string Path to the input masks. This path may contain wildcards to use multiple masks at once. (default: No mask used) b0_threshold : float, optional Threshold used to find b=0 directions frf : tuple, optional Fiber response function to me mutiplied by 10**-4 (default: 15,4,4) extract_pam_values : bool, optional Wheter or not to save pam volumes as single nifti files. out_dir : string, optional Output directory (default input file directory) out_pam : string, optional Name of the peaks volume to be saved (default 'peaks.pam5') out_shm : string, optional Name of the shperical harmonics volume to be saved (default 'shm.nii.gz') out_peaks_dir : string, optional Name of the peaks directions volume to be saved (default 'peaks_dirs.nii.gz') out_peaks_values : string, optional Name of the peaks values volume to be saved (default 'peaks_values.nii.gz') out_peaks_indices : string, optional Name of the peaks indices volume to be saved (default 'peaks_indices.nii.gz') out_gfa : string, optional Name of the generalise fa volume to be saved (default 'gfa.nii.gz') """ io_it = self.get_io_iterator() for dwi, bval, bvec, maskfile, opam, oshm, opeaks_dir, opeaks_values, \ opeaks_indices, ogfa in io_it: logging.info('Computing fiber odfs for {0}'.format(dwi)) vol = nib.load(dwi) data = vol.get_data() affine = vol.get_affine() bvals, bvecs = read_bvals_bvecs(bval, bvec) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold) mask_vol = nib.load(maskfile).get_data().astype(np.bool) sh_order = 8 if data.shape[-1] < 15: raise ValueError('You need at least 15 unique DWI volumes to ' 'compute fiber odfs. You currently have: {0}' ' DWI volumes.'.format(data.shape[-1])) elif data.shape[-1] < 30: sh_order = 6 response, ratio = auto_response(gtab, data) response = list(response) if frf is not None: if isinstance(frf, str): l01 = np.array(literal_eval(frf), dtype=np.float64) else: l01 = np.array(frf) l01 *= 10**-4 response[0] = np.array([l01[0], l01[1], l01[1]]) ratio = l01[1] / l01[0] logging.info( 'Eigenvalues for the frf of the input data are :{0}'.format( response[0])) logging.info( 'Ratio for smallest to largest eigen value is {0}'.format( ratio)) peaks_sphere = get_sphere('symmetric362') csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=sh_order) peaks_csd = peaks_from_model(model=csd_model, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=mask_vol, return_sh=True, sh_order=sh_order, normalize_peaks=True, parallel=False) peaks_csd.affine = affine save_peaks(opam, peaks_csd) if extract_pam_values: peaks_to_niftis(peaks_csd, oshm, opeaks_dir, opeaks_values, opeaks_indices, ogfa, reshape_dirs=True) logging.info('Peaks saved in {0}'.format(os.path.dirname(opam))) return io_it