def life(streamline_file, data_file, bvals, bvecs, seed_label, target_label): import numpy as np import nibabel as nib import os import dipy.tracking.life as life from dipy.core.gradients import gradient_table trk_file = nib.streamlines.load(streamline_file) streams = trk_file.streamlines hdr = trk_file.header data_img = nib.load(data_file) data = data_img.get_data() gtab = gradient_table(bvals, bvecs) fiber_model = life.FiberModel(gtab) fiber_fit = fiber_model.fit(data, streams, affine=np.eye(4)) optimized_sl = list(np.array(streams)[np.where(fiber_fit.beta > 0)[0]]) tractogram = nib.streamlines.Tractogram(optimized_sl) tractogram.affine_to_rasmm = data_img.affine life_streams = nib.streamlines.TrkFile(tractogram, header=hdr) life_trk = os.path.abspath('life_seed-%d_target-%d.trk' % (seed_label, target_label)) nib.streamlines.save(life_streams, life_trk) return streamline_file, life_trk
def test_FiberFit(): data_file, bval_file, bvec_file = dpd.get_fnames('small_64D') data_ni = nib.load(data_file) data = data_ni.get_data() bvals, bvecs = read_bvals_bvecs(bval_file, bvec_file) gtab = grad.gradient_table(bvals, bvecs) FM = life.FiberModel(gtab) evals = [0.0015, 0.0005, 0.0005] streamline = [[[1, 2, 3], [4, 5, 3], [5, 6, 3], [6, 7, 3]], [[1, 2, 3], [4, 5, 3], [5, 6, 3]]] fiber_matrix, vox_coords = FM.setup(streamline, np.eye(4), evals) w = np.array([0.5, 0.5]) sig = opt.spdot(fiber_matrix, w) + 1.0 # Add some isotropic stuff S0 = data[..., gtab.b0s_mask] this_data = np.zeros((10, 10, 10, 64)) this_data[vox_coords[:, 0], vox_coords[:, 1], vox_coords[:, 2]] =\ (sig.reshape((4, 64)) * S0[vox_coords[:, 0], vox_coords[:, 1], vox_coords[:, 2]]) # Grab some realistic S0 values: this_data = np.concatenate([data[..., gtab.b0s_mask], this_data], -1) fit = FM.fit(this_data, streamline, np.eye(4)) npt.assert_almost_equal(fit.predict()[1], fit.data[1], decimal=-1) # Predict with an input GradientTable npt.assert_almost_equal(fit.predict(gtab)[1], fit.data[1], decimal=-1) npt.assert_almost_equal( this_data[vox_coords[:, 0], vox_coords[:, 1], vox_coords[:, 2]], fit.data)
def test_FiberModel_init(): # Get some small amount of data: data_file, bval_file, bvec_file = dpd.get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(bval_file, bvec_file) gtab = grad.gradient_table(bvals, bvecs) FM = life.FiberModel(gtab) streamline_cases = [[[[1, 2, 3], [4, 5, 3], [5, 6, 3], [6, 7, 3]], [[1, 2, 3], [4, 5, 3], [5, 6, 3]]], [[[1, 2, 3]], [[1, 2, 3], [4, 5, 3], [5, 6, 3]]]] affine = np.eye(4) for sphere in [None, False, dpd.get_sphere('symmetric362')]: for streamline in streamline_cases: if streamline == [[[1, 2, 3]], [[1, 2, 3], [4, 5, 3], [5, 6, 3]]]: pytest.xfail("Too few nodes in streamline") fiber_matrix, vox_coords = FM.setup(streamline, affine, sphere=sphere) npt.assert_array_equal( np.array(vox_coords), np.array([[1, 2, 3], [4, 5, 3], [5, 6, 3], [6, 7, 3]])) npt.assert_equal(fiber_matrix.shape, (len(vox_coords) * 64, len(streamline)))
def eval_method(name=None, method=None, track_path=None, data_path=None): if track_path == None: track_path = './Result/Track/tractogram_' + method + '_' + name + '.trk' if data_path == None: data_path = './data/DWI/' + name + '/' if not op.exists(track_path): print('no tracking') return 0 else: from dipy.io.gradients import read_bvals_bvecs from dipy.io.image import load_nifti_data, load_nifti from dipy.core.gradients import gradient_table data, affine, hardi_img = load_nifti(data_path + 'norm.nii.gz', return_img=True) print(data.shape) labels = load_nifti_data(data_path + 'seg.nii.gz') # t1_data = load_nifti_data('./data/tanenci_20170601/b0.nii.gz') bvals, bvecs = read_bvals_bvecs(data_path + 'DWI.bval', data_path + 'DWI.bvec') gtab = gradient_table(bvals, bvecs) # Read the candidates from file in voxel space: candidate_sl_sft = load_trk(track_path, 'same', bbox_valid_check=False) candidate_sl_sft.to_vox() candidate_sl = candidate_sl_sft.streamlines print('loading finished, begin weighting') fiber_model = life.FiberModel(gtab) inv_affine = np.linalg.inv(hardi_img.affine) fiber_fit = fiber_model.fit(data, reduct(candidate_sl, data[:, :, :, 0]), affine=np.eye(4)) print('weighting finished, begin prediction') beta_baseline = np.zeros(fiber_fit.beta.shape[0]) pred_weighted = np.reshape( opt.spdot(fiber_fit.life_matrix, beta_baseline), (fiber_fit.vox_coords.shape[0], np.sum(~gtab.b0s_mask))) model_predict = fiber_fit.predict() model_error = model_predict - fiber_fit.data model_rmse = np.sqrt(np.mean(model_error[:, 10:]**2, -1)) #print('model_rmse:', model_rmse.shape) vol_model = np.zeros(data.shape[:3]) * np.nan vol_model[fiber_fit.vox_coords[:, 0], fiber_fit.vox_coords[:, 1], fiber_fit.vox_coords[:, 2]] = model_rmse #print('error:', np.sum(vol_model) / model_rmse.shape[0]) return np.sum(model_rmse) / model_rmse.shape[0], vol_model, affine
def run_LIFE_all(data, gtab, streamlines): import dipy.tracking.life as life import dipy.core.optimize as opt fiber_model = life.FiberModel(gtab) fiber_fit = fiber_model.fit(data, streamlines, affine=np.eye(4)) streamlines_filt = list(np.array(streamlines)[np.where(fiber_fit.beta > 0)[0]]) beta_baseline = np.zeros(fiber_fit.beta.shape[0]) pred_weighted = np.reshape(opt.spdot(fiber_fit.life_matrix, beta_baseline), (fiber_fit.vox_coords.shape[0], np.sum(~gtab.b0s_mask))) mean_pred = np.empty((fiber_fit.vox_coords.shape[0], gtab.bvals.shape[0])) S0 = fiber_fit.b0_signal mean_pred[..., gtab.b0s_mask] = S0[:, None] mean_pred[..., ~gtab.b0s_mask] = (pred_weighted + fiber_fit.mean_signal[:, None]) * S0[:, None] mean_error = mean_pred - fiber_fit.data mean_rmse = np.sqrt(np.mean(mean_error ** 2, -1)) return streamlines_filt, mean_rmse
def test_fit_data(): fdata, fbval, fbvec = dpd.get_fnames('small_25') fstreamlines = dpd.get_fnames('small_25_streamlines') gtab = grad.gradient_table(fbval, fbvec) ni_data = nib.load(fdata) data = ni_data.get_data() tensor_streamlines = nib.streamlines.load(fstreamlines).streamlines tensor_streamlines = move_streamlines(tensor_streamlines, np.eye(4), ni_data.affine) life_model = life.FiberModel(gtab) life_fit = life_model.fit(data, tensor_streamlines) model_error = life_fit.predict() - life_fit.data model_rmse = np.sqrt(np.mean(model_error**2, -1)) matlab_rmse, matlab_weights = dpd.matlab_life_results() # Lower error than the matlab implementation for these data: npt.assert_(np.median(model_rmse) < np.median(matlab_rmse)) # And a moderate correlation with the Matlab implementation weights: npt.assert_(np.corrcoef(matlab_weights, life_fit.beta)[0, 1] > 0.6)
def test_FiberModel_init(): # Get some small amount of data: data_file, bval_file, bvec_file = dpd.get_data('small_64D') data_ni = nib.load(data_file) bvals, bvecs = (np.load(f) for f in (bval_file, bvec_file)) gtab = dpg.gradient_table(bvals, bvecs) FM = life.FiberModel(gtab) streamline = [[[1, 2, 3], [4, 5, 3], [5, 6, 3], [6, 7, 3]], [[1, 2, 3], [4, 5, 3], [5, 6, 3]]] affine = np.eye(4) for sphere in [None, False, dpd.get_sphere('symmetric362')]: fiber_matrix, vox_coords = FM.setup(streamline, affine, sphere=sphere) npt.assert_array_equal( np.array(vox_coords), np.array([[1, 2, 3], [4, 5, 3], [5, 6, 3], [6, 7, 3]])) npt.assert_equal(fiber_matrix.shape, (len(vox_coords) * 64, len(streamline)))
def run_LIFE_all(data, gtab, streamlines): ''' Filters tractography streamlines using Linear Fascicle Evaluation (LiFE). Parameters ---------- data : array 4D numpy array of diffusion image data. gtab : Obj DiPy object storing diffusion gradient information. streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. Returns ------- streamlines_filt : ArraySequence DiPy list/array-like object of filtered streamline fibers with positive beta-coefficients after fitting LiFE model. mean_rmse : float Root Mean-Squared Error (RMSE) when using LiFE-filtered fibers to predict diffusion data. ''' import dipy.tracking.life as life import dipy.core.optimize as opt fiber_model = life.FiberModel(gtab) fiber_fit = fiber_model.fit(data, streamlines, affine=np.eye(4)) streamlines_filt = list( np.array(streamlines)[np.where(fiber_fit.beta > 0)[0]]) beta_baseline = np.zeros(fiber_fit.beta.shape[0]) pred_weighted = np.reshape( opt.spdot(fiber_fit.life_matrix, beta_baseline), (fiber_fit.vox_coords.shape[0], np.sum(~gtab.b0s_mask))) mean_pred = np.empty((fiber_fit.vox_coords.shape[0], gtab.bvals.shape[0])) S0 = fiber_fit.b0_signal mean_pred[..., gtab.b0s_mask] = S0[:, None] mean_pred[..., ~gtab.b0s_mask] = (pred_weighted + fiber_fit.mean_signal[:, None]) * S0[:, None] mean_error = mean_pred - fiber_fit.data mean_rmse = np.sqrt(np.mean(mean_error**2, -1)) return streamlines_filt, mean_rmse
def test_fit_data(): fdata, fbval, fbvec = dpd.get_data('small_25') gtab = grad.gradient_table(fbval, fbvec) ni_data = nib.load(fdata) data = ni_data.get_data() dtmodel = dti.TensorModel(gtab) dtfit = dtmodel.fit(data) sphere = dpd.get_sphere() peak_idx = dti.quantize_evecs(dtfit.evecs, sphere.vertices) eu = edx.EuDX(dtfit.fa.astype('f8'), peak_idx, seeds=list(nd.ndindex(data.shape[:-1])), odf_vertices=sphere.vertices, a_low=0) tensor_streamlines = [streamline for streamline in eu] life_model = life.FiberModel(gtab) life_fit = life_model.fit(data, tensor_streamlines) model_error = life_fit.predict() - life_fit.data model_rmse = np.sqrt(np.mean(model_error**2, -1)) matlab_rmse, matlab_weights = dpd.matlab_life_results() # Lower error than the matlab implementation for these data: npt.assert_(np.median(model_rmse) < np.median(matlab_rmse)) # And a moderate correlation with the Matlab implementation weights: npt.assert_(np.corrcoef(matlab_weights, life_fit.beta)[0, 1] > 0.68)
.. figure:: life_candidates.png :align: center **Candidate connectome before life optimization** """ """ Next, we initialize a LiFE model. We import the `dipy.tracking.life` module, which contains the classes and functions that implement the model: """ import dipy.tracking.life as life fiber_model = life.FiberModel(gtab) """ Since we read the streamlines from a file, already in the voxel space, we do not need to transform them into this space. Otherwise, if the streamline coordinates were in the world space (relative to the scanner iso-center, or relative to the mid-point of the AC-PC-connecting line), we would use this:: inv_affine = np.linalg.inv(hardi_img.get_affine()) the inverse transformation from world space to the voxel space as the affine for the following model fit. The next step is to fit the model, producing a `FiberFit` class instance, that stores the data, as well as the results of the fitting procedure.
def run_LiFE(subject): print 'Process subject ' + subject if os.path.isfile( os.path.join(path_saveing, subject, 'Lamyg2LpMFG_LIFE_started.txt')) == False: print "LiFE Files do not exist for this subject, start calculation." if os.path.isfile( os.path.join( path_saveing, subject, 'Lamyg2LpMFG_clustered.trk')) == True and os.path.isfile( os.path.join(path_saveing, subject, '2M_SIFT.trk')) == True: print "All neccessary files there, continue ..." print "Show other processes that this subject is processed" done = np.array([1]) np.savetxt(os.path.join(path_saveing, subject, 'Lamyg2LpMFG_LIFE_started.txt'), done, delimiter=',') try: directory_output = os.path.join(path_saveing, subject) print "Start calculation for subject %s" % subject f_streamlines = os.path.join(path_saveing, subject, 'Lamyg2LpMFG_clustered.trk') f_in_nifti = os.path.join(path, subject, 'T1w/Diffusion/data.nii.gz') streams, hdr = tv.read(f_streamlines, points_space='voxel') streamlines = [i[0] for i in streams] data, affine, gtab, header, shell_mask = load_hcp_data( path, subject) dim = header['dim'][1:4] # Otherwise all weights are NaN data[data <= 0.0] = 1.0 print "Calculating neighborhood with LiFE" fiber_model_neighborhood = life.FiberModel(gtab) fiber_fit_neighborhood = fiber_model_neighborhood.fit( data, streamlines, affine=np.eye(4)) indices_neighborhood = fiber_fit_neighborhood.vox_coords neighborhood = np.zeros(dim, dtype=bool) for i in range(indices_neighborhood.shape[0]): neighborhood[indices_neighborhood[i][0], indices_neighborhood[i][1], indices_neighborhood[i][2]] = 1 save_as_nifti( path_saveing + subject + "/Lamyg2LpMFG_neighborhood", neighborhood.astype(np.int), affine) print 'Find fiber that pass through neighborhood' f_streamlines_whole_brain = path_saveing + subject + "/2M_SIFT.trk" streams_whole_brain, hdr_whole_brain = tv.read( f_streamlines_whole_brain, points_space='voxel') streamlines_whole_brain = [i[0] for i in streams_whole_brain] neighborhood_streamlines = utils.target( streamlines_whole_brain, neighborhood, affine=np.eye(4)) neighborhood_streamlines = list(neighborhood_streamlines) strm = ((sl, None, None) for sl in neighborhood_streamlines) tv.write(path_saveing + subject + "/Lamyg2LpMFG_2M_SIFT_without_path.trk", strm, hdr_mapping=hdr_whole_brain, points_space='voxel') print "Combine streamlines" streamlines_together = neighborhood_streamlines + streamlines strm_together = ((sl, None, None) for sl in streamlines_together) tv.write(path_saveing + subject + "/Lamyg2LpMFG_2M_SIFT_with_path.trk", strm_together, hdr_mapping=hdr_whole_brain, points_space='voxel') print "Start LiFE optimization with new path" fiber_model_together = life.FiberModel(gtab) fiber_fit_together = fiber_model_together.fit( data, streamlines_together, affine=np.eye(4)) model_predict_together = fiber_fit_together.predict() indices_together = fiber_fit_together.vox_coords mask_with = np.zeros(dim, dtype=bool) whole_brain_together = np.zeros(header['dim'][1:5]) for i in range(indices_together.shape[0]): whole_brain_together[ indices_together[i][0], indices_together[i][1], indices_together[i][2]] = model_predict_together[i] mask_with[indices_together[i][0], indices_together[i][1], indices_together[i][2]] = 1 save_as_nifti( path_saveing + subject + "/Lamyg2LpMFG_LiFE_prediction_with_path", whole_brain_together, affine) save_as_matlab_file(path_saveing + subject + "/Lamyg2LpMFG_LiFE_betas_with_path", beta=fiber_fit_together.beta) save_as_nifti( path_saveing + subject + "/Lamyg2LpMFG_LiFE_mask_with_path", mask_with.astype(np.int), affine) print "Calculate RMSE with" model_error_together = model_predict_together - fiber_fit_together.data model_rmse_together = np.sqrt( np.mean(model_error_together[..., ~gtab.b0s_mask]**2, -1)) whole_brain_rmse_together = np.zeros(dim) for i in range(indices_together.shape[0]): whole_brain_rmse_together[ indices_together[i][0], indices_together[i][1], indices_together[i][2]] = model_rmse_together[i] save_as_nifti( path_saveing + subject + "/Lamyg2LpMFG_LiFE_rmse_with_path", whole_brain_rmse_together, affine) print "Start LiFE optimization without new path" fiber_fit = copy.deepcopy(fiber_fit_together) fiber_fit.beta[-len(streamlines):] = 0 model_predict = fiber_fit.predict() indices = fiber_fit.vox_coords whole_brain = np.zeros(header['dim'][1:5]) mask_without = np.zeros(dim, dtype=bool) for i in range(indices.shape[0]): whole_brain[indices[i][0], indices[i][1], indices[i][2]] = model_predict[i] mask_without[indices[i][0], indices[i][1], indices[i][2]] = 1 save_as_nifti( path_saveing + subject + "/Lamyg2LpMFG_LiFE_prediction_without_path", whole_brain, affine) save_as_matlab_file(path_saveing + subject + "/Lamyg2LpMFG_LiFE_betas_without_path", beta=fiber_fit.beta) save_as_nifti( path_saveing + subject + "/Lamyg2LpMFG_LiFE_mask_without_path", mask_without.astype(np.int), affine) print "Calculate RMSE without" model_error = model_predict - fiber_fit.data model_rmse = np.sqrt( np.mean(model_error[..., ~gtab.b0s_mask]**2, -1)) whole_brain_rmse = np.zeros(dim) for i in range(indices.shape[0]): whole_brain_rmse[indices[i][0], indices[i][1], indices[i][2]] = model_rmse[i] save_as_nifti( path_saveing + subject + "/Lamyg2LpMFG_LiFE_rmse_without_path", whole_brain_rmse, affine) print "All done" except: print "An error occured while computing LiFE. Skip this subject." else: print "Some input files are missing, skip this subject." else: print "LiFE Files exist already for this subject, skip calculation." return 0
def evaluate_streamline_plausibility(dwi_data, gtab, mask_data, streamlines, affine=np.eye(4), sphere='repulsion724'): """ Linear Fascicle Evaluation (LiFE) takes any connectome and uses a forward modelling approach to predict diffusion measurements in the same brain. Parameters ---------- dwi_data : array 4D array of dwi data. gtab : Obj DiPy object storing diffusion gradient information. mask_data : array 3D Brain mask. streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. Returns ------- streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. References ---------- .. [1] Pestilli, F., Yeatman, J, Rokem, A. Kay, K. and Wandell B.A. (2014). Validation and statistical inference in living connectomes. Nature Methods 11: 1058-1063. doi:10.1038/nmeth.3098 """ import dipy.tracking.life as life import dipy.core.optimize as opt from dipy.tracking._utils import _mapping_to_voxel # from dipy.data import get_sphere from dipy.tracking import utils from dipy.tracking.streamline import Streamlines original_count = len(streamlines) streamlines_long = nib.streamlines. \ array_sequence.ArraySequence( [ s for s in streamlines if len(s) >= float(10) ] ) print('Removing streamlines with negative voxel indices...') # Remove any streamlines with negative voxel indices lin_T, offset = _mapping_to_voxel(np.eye(4)) streamlines_positive = [] for sl in streamlines_long: inds = np.dot(sl, lin_T) inds += offset if not inds.min().round(decimals=6) < 0: streamlines_positive.append(sl) del streamlines_long # Filter resulting streamlines by those that stay entirely # inside the ROI of interest mask_data = np.array(mask_data, dtype=bool, copy=False) streamlines_in_brain = Streamlines( utils.target(streamlines_positive, np.eye(4), mask_data, include=True)) streamlines_in_brain = [i for i in streamlines_in_brain] del streamlines_positive print('Fitting fiber model...') # ! Remember this 4d masking function ! data_in_mask = np.nan_to_num( np.broadcast_to(mask_data[..., None], dwi_data.shape).astype('bool') * dwi_data) # ! Remember this 4d masking function ! fiber_model = life.FiberModel(gtab) fiber_fit = fiber_model.fit(data_in_mask, streamlines_in_brain, affine=affine, sphere=False) # sphere = get_sphere(sphere) # fiber_fit = fiber_model.fit(data_in_mask, streamlines_in_brain, # affine=affine, # sphere=sphere) streamlines = list( np.array(streamlines_in_brain)[np.where(fiber_fit.beta > 0)[0]]) pruned_count = len(streamlines) if pruned_count == 0: print( UserWarning('\nWarning LiFE skipped due to implausible values ' 'detected in model betas. This does not ' 'necessarily invalidate the ' 'tractography. Rather it could indicate that ' 'you\'ve sampled too few streamlines, or that the ' 'sampling scheme is simply incompatible with the ' 'LiFE model. Is your acquisition hemispheric? ' 'Also check the gradient table for errors. \n')) return streamlines_in_brain else: del streamlines_in_brain model_predict = fiber_fit.predict() model_error = model_predict - fiber_fit.data model_rmse = np.sqrt(np.mean(model_error[:, 10:]**2, -1)) beta_baseline = np.zeros(fiber_fit.beta.shape[0]) pred_weighted = np.reshape( opt.spdot(fiber_fit.life_matrix, beta_baseline), (fiber_fit.vox_coords.shape[0], np.sum(~gtab.b0s_mask))) mean_pred = np.empty((fiber_fit.vox_coords.shape[0], gtab.bvals.shape[0])) S0 = fiber_fit.b0_signal mean_pred[..., gtab.b0s_mask] = S0[:, None] mean_pred[..., ~gtab.b0s_mask] = (pred_weighted + fiber_fit.mean_signal[:, None]) * S0[:, None] mean_error = mean_pred - fiber_fit.data mean_rmse = np.sqrt(np.mean(mean_error**2, -1)) print(f"Original # Streamlines: {original_count}") print(f"Final # Streamlines: {pruned_count}") print(f"Streamlines removed: {pruned_count - original_count}") print(f"Mean RMSE: {np.mean(mean_rmse)}") print(f"Mean Model RMSE: {np.mean(model_rmse)}") print(f"Mean Reduction RMSE: {np.mean(mean_rmse - model_rmse)}") return streamlines
def life(dwifile, bvecsfile, bvalsfile, tractogramfile, outdir, display_tracks=False, verbose=0): """ Linear fascicle evaluation (LiFE) Evaluating the results of tractography algorithms is one of the biggest challenges for diffusion MRI. One proposal for evaluation of tractography results is to use a forward model that predicts the signal from each of a set of streamlines, and then fit a linear model to these simultaneous prediction. Parameters ---------- dwifile: str the path to the diffusion dataset. bvecsfile: str the path to the diffusion b-vectors. bvalsfile: str the path to the diffusion b-values. tractogramfile: str the path to the tractogram. outdir: str the destination folder. display_tracks: bool, default False if True render the tracks. verbose: int, default 0 the verbosity level. Returns ------- life_weights_file: str a file containing the fiber track weights. life_weights_snap: str a snap with the distrubution of weights. spatial_error_file: str the model root mean square error. tracks_snap: str a snap with the tracks. """ # Load diffusion data and tractogram bvecs = numpy.loadtxt(bvecsfile) bvals = numpy.loadtxt(bvalsfile) gtab = gradient_table(bvals, bvecs) im = nibabel.load(dwifile) data = im.get_data() trk = nibabel.streamlines.load(tractogramfile) if verbose > 0: print("[info] Diffusion shape: {0}".format(data.shape)) print("[info] Number of tracks: {0}".format(len(trk.streamlines))) # Express the tractogram in voxel coordiantes inv_affine = numpy.linalg.inv(trk.affine) trk = [ numpy.dot( numpy.concatenate( ( streamline, numpy.ones( (len(streamline), 1) ) ), axis=1 ), inv_affine) for streamline in trk.streamlines] trk = [track[..., :3] for track in trk] # Create a viewer tracks_snap = None if display_tracks: nb_tracks = len(trk) if nb_tracks < 5000: downsampling = 1 else: downsampling = nb_tracks // 5000 tracks_snap = os.path.join(outdir, "tracks.png") streamlines_actor = fvtk.line(trk[::downsampling], line_colors(trk[::downsampling])) vol_actor = fvtk.slicer(data[..., 0]) vol_actor.display(data.shape[0] // 2, None, None) ren = fvtk.ren() fvtk.add(ren, streamlines_actor) fvtk.add(ren, vol_actor) fvtk.record(ren, n_frames=1, out_path=tracks_snap, size=(800, 800)) if verbose > 1: fvtk.show(ren) # Fit the Life model and save the associated weights fiber_model = dpilife.FiberModel(gtab) fiber_fit = fiber_model.fit(data, trk, affine=numpy.eye(4)) life_weights = fiber_fit.beta life_weights_file = os.path.join(outdir, "life_weights.txt") numpy.savetxt(life_weights_file, life_weights) life_weights_snap = os.path.join(outdir, "life_weights.png") fig, ax = plt.subplots(1) ax.hist(life_weights, bins=100, histtype="step") ax.set_xlabel("Fiber weights") ax.set_ylabel("# Fibers") fig.savefig(life_weights_snap) # Invert the model and predict back either the data that was used to fit # the model: compute the prediction error of the diffusion-weighted data # and calculate the root of the mean squared error. model_predict = fiber_fit.predict() model_error = model_predict - fiber_fit.data model_rmse = numpy.sqrt(numpy.mean(model_error[:, 10:] ** 2, -1)) data_rmse = numpy.ones(data.shape[:3]) * numpy.nan data_rmse[fiber_fit.vox_coords[:, 0], fiber_fit.vox_coords[:, 1], fiber_fit.vox_coords[:, 2]] = model_rmse model_error_file = os.path.join(outdir, "model_rmse.nii.gz") error_im = nibabel.Nifti1Image(data_rmse, im.affine) nibabel.save(error_im, model_error_file) # As a baseline against which we can compare, we assume that the weight # for each streamline is equal to zero. This produces the naive prediction # of the mean of the signal in each voxel. life_weights_baseline = numpy.zeros(life_weights.shape[0]) pred_weighted = numpy.reshape( opt.spdot(fiber_fit.life_matrix, life_weights_baseline), (fiber_fit.vox_coords.shape[0], numpy.sum(~gtab.b0s_mask))) mean_pred = numpy.empty( (fiber_fit.vox_coords.shape[0], gtab.bvals.shape[0])) S0 = fiber_fit.b0_signal # Since the fitting is done in the demeaned S/S0 domain, we need to add # back the mean and then multiply by S0 in every voxels. mean_pred[..., gtab.b0s_mask] = S0[:, None] mean_pred[..., ~gtab.b0s_mask] = ( (pred_weighted + fiber_fit.mean_signal[:, None]) * S0[:, None]) mean_error = mean_pred - fiber_fit.data mean_rmse = numpy.sqrt(numpy.mean(mean_error ** 2, -1)) data_rmse = numpy.ones(data.shape[:3]) * numpy.nan data_rmse[fiber_fit.vox_coords[:, 0], fiber_fit.vox_coords[:, 1], fiber_fit.vox_coords[:, 2]] = mean_rmse mean_error_file = os.path.join(outdir, "mean_rmse.nii.gz") error_im = nibabel.Nifti1Image(data_rmse, im.affine) nibabel.save(error_im, mean_error_file) # Compute the improvment array data_rmse = numpy.ones(data.shape[:3]) * numpy.nan data_rmse[fiber_fit.vox_coords[:, 0], fiber_fit.vox_coords[:, 1], fiber_fit.vox_coords[:, 2]] = mean_rmse - model_rmse improvment_error_file = os.path.join(outdir, "improvment_rmse.nii.gz") error_im = nibabel.Nifti1Image(data_rmse, im.affine) nibabel.save(error_im, improvment_error_file) return (life_weights_file, life_weights_snap, model_error_file, mean_error_file, improvment_error_file, tracks_snap)