Exemple #1
0
def test_spdot():
    n = 100
    m = 20
    k = 10
    A = np.random.randn(n, m)
    B = np.random.randn(m, k)
    A_sparse = sps.csr_matrix(A)
    B_sparse = sps.csr_matrix(B)
    dense_dot = np.dot(A, B)
    # Try all the different variations:
    npt.assert_array_almost_equal(dense_dot,
                                  spdot(A_sparse, B_sparse).todense())
    npt.assert_array_almost_equal(dense_dot, spdot(A, B_sparse))
    npt.assert_array_almost_equal(dense_dot, spdot(A_sparse, B))
Exemple #2
0
def test_spdot():
    n = 100
    m = 20
    k = 10
    A = np.random.randn(n, m)
    B = np.random.randn(m, k)
    A_sparse = sps.csr_matrix(A)
    B_sparse = sps.csr_matrix(B)
    dense_dot = np.dot(A, B)
    # Try all the different variations:
    npt.assert_array_almost_equal(dense_dot,
                                  spdot(A_sparse, B_sparse).todense())
    npt.assert_array_almost_equal(dense_dot, spdot(A, B_sparse))
    npt.assert_array_almost_equal(dense_dot, spdot(A_sparse, B))
Exemple #3
0
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)
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
    def predict(self, gtab=None, S0=None):
        """
        Predict the signal

        Parameters
        ----------
        gtab : GradientTable
            Default: use self.gtab
        S0 : float or array
            The non-diffusion-weighted signal in the voxels for which a
            prediction is made. Default: use self.b0_signal

        Returns
        -------
        prediction : ndarray of shape (voxels, bvecs)
            An array with a prediction of the signal in each voxel/direction
        """
        # We generate the prediction and in each voxel, we add the
        # offset, according to the isotropic part of the signal, which was
        # removed prior to fitting:
        if gtab is None:
            _matrix = self.life_matrix
            gtab = self.model.gtab
        else:
            _model = FiberModel(gtab)
            _matrix, _ = _model.setup(self.streamline,
                                      self.affine,
                                      self.evals)

        pred_weighted = np.reshape(opt.spdot(_matrix, self.beta),
                                   (self.vox_coords.shape[0],
                                    np.sum(~gtab.b0s_mask)))

        pred = np.empty((self.vox_coords.shape[0], gtab.bvals.shape[0]))
        if S0 is None:
            S0 = self.b0_signal

        pred[..., gtab.b0s_mask] = S0[:, None]
        pred[..., ~gtab.b0s_mask] =\
            (pred_weighted + self.mean_signal[:, None]) * S0[:, None]

        return pred
Exemple #7
0
    def predict(self, gtab=None, S0=None):
        """
        Predict the signal

        Parameters
        ----------
        gtab : GradientTable
            Default: use self.gtab
        S0 : float or array
            The non-diffusion-weighted signal in the voxels for which a
            prediction is made. Default: use self.b0_signal

        Returns
        -------
        prediction : ndarray of shape (voxels, bvecs)
            An array with a prediction of the signal in each voxel/direction
        """
        # We generate the prediction and in each voxel, we add the
        # offset, according to the isotropic part of the signal, which was
        # removed prior to fitting:
        if gtab is None:
            _matrix = self.life_matrix
            gtab = self.model.gtab
        else:
            _model = FiberModel(gtab)
            _matrix, _ = _model.setup(self.streamline,
                                      self.affine,
                                      self.evals)

        pred_weighted = np.reshape(opt.spdot(_matrix, self.beta),
                                   (self.vox_coords.shape[0],
                                    np.sum(~gtab.b0s_mask)))

        pred = np.empty((self.vox_coords.shape[0], gtab.bvals.shape[0]))
        if S0 is None:
            S0 = self.b0_signal

        pred[..., gtab.b0s_mask] = S0[:, None]
        pred[..., ~gtab.b0s_mask] =\
            (pred_weighted + self.mean_signal[:, None]) * S0[:, None]

        return pred
Exemple #8
0
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
Exemple #9
0
def test_FiberFit():
    data_file, bval_file, bvec_file = dpd.get_data('small_64D')
    data_ni = nib.load(data_file)
    data = data_ni.get_data()
    data_aff = data_ni.affine
    bvals, bvecs = (np.load(f) for f in (bval_file, bvec_file))
    gtab = dpg.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, None, 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]
    rel_sig = data[..., ~gtab.b0s_mask]/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)
    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)
"""

model_error = model_predict - fiber_fit.data
model_rmse = np.sqrt(np.mean(model_error[:, 10:]**2, -1))
"""

As a baseline against which we can compare, we calculate another error term. In
this case, 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.

"""

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
"""

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 voxel:

"""

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))
"""

model_error = model_predict - fiber_fit.data
model_rmse = np.sqrt(np.mean(model_error[:, 10:] ** 2, -1))

"""

As a baseline against which we can compare, we calculate another error term. In
this case, 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.

"""

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

"""

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 voxel:

"""

mean_pred[..., gtab.b0s_mask] = S0[:, None]
mean_pred[..., ~gtab.b0s_mask] =\
    (pred_weighted + fiber_fit.mean_signal[:, None]) * S0[:, None]
Exemple #12
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
"""

model_error = model_predict - fiber_fit.data
model_rmse = np.sqrt(np.mean(model_error[:, 10:] ** 2, -1))

"""

As a baseline against which we can compare, we calculate another error term. In
this case, 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.

"""
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

"""

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 voxel:

"""

mean_pred[..., gtab.b0s_mask] = S0[:, None]
mean_pred[..., ~gtab.b0s_mask] =\
        (pred_weighted + fiber_fit.mean_signal[:, None]) * S0[:, None]
model_error = model_predict - fiber_fit.data
model_rmse = np.sqrt(np.mean(model_error[:, 10:] ** 2, -1))

"""

As a baseline against which we can compare, we calculate another error term. In
this case, 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.

"""

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

"""

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 voxel:

"""

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))
Exemple #15
0
def LiFEvaluation(dwidata,
                  trk_streamlines,
                  gtab,
                  subject="lifesubj",
                  header=None,
                  roimask=None,
                  affine=None,
                  display=True,
                  outpathpickle=None,
                  outpathtrk=None,
                  processes=1,
                  outpathfig=None,
                  strproperty="",
                  verbose=None):
    """     Implementation of Linear Fascicle Evaluation, outputs histograms, evals

    Parameters
    ----------
    dwidata : array
        output trk filename
    trkdata : array
    gtab : array og bval & bvec table
    outpath: string
    folder location for resulting values and figures
    display : boolean, optional
    Condition to display the results (default = False)
    savefig: boolean, optional
    Condition to save the results in outpath (default = True)

    Defined by Pestilli, F., Yeatman, J, Rokem, A. Kay, K. and Wandell B.A. (2014).
    Validation and statistical inference in living connectomes and recreated by Dipy

    :param dwidata: array of diffusion data
    :param trkdata: array of tractography data obtained from dwi
    :param gtab: bval & bvec table
    :param outpath: location to save analysis outputs
    :param display:
    :param savefig:
    :return:
    """
    """""" """
    if not op.exists('lr-superiorfrontal.trk'):
        
    else:
        # We'll need to know where the corpus callosum is from these variables:
        from dipy.data import (read_stanford_labels,
                               fetch_stanford_t1,
                               read_stanford_t1)
        hardi_img, gtab, labels_img = read_stanford_labels()
        labels = labels_img.get_data()
        cc_slice = labels == 2
        fetch_stanford_t1()
        t1 = read_stanford_t1()
        t1_data = t1.get_data()
        data = hardi_img.get_data()
    """ """"""
    # Read the candidates from file in voxel space:

    if roimask is None:
        roimask = dwidata > 0
    else:
        dwidataroi = dwidata * np.repeat(
            roimask[:, :, :, None], np.shape(dwidata)[3], axis=3)

    print("verbose: " + str(verbose) + " outpathpickle: " + str(outpathpickle))
    fiber_model = life.FiberModel(gtab)
    # inv_affine must be used if the streamlines are in the world space, and thus we must useapply the inverse affine of dwi
    #when comparing the diffusion directions gtab and the voxels of trk
    #inv_affine = np.linalg.inv(hardi_img.affine)

    #fiber_fit will fit the streamlines to the original diffusion data and
    if verbose:
        txt = "Begin the evaluation over " + str(
            np.size(trk_streamlines)) + " streamlines"
        print(txt)
        send_mail(txt, subject="LifE start msg ")

    fiber_fit = fiber_model.fit(dwidata,
                                trk_streamlines,
                                affine=np.eye(4),
                                processes=processes,
                                verbose=verbose)
    #fiber_fit_roi = fiber_model.fit(dwidataroi, trk_streamlines, affine=np.eye(4), processes=processes, verbose=verbose)
    optimized_sl = list(
        np.array(trk_streamlines)[np.where(fiber_fit.beta > 0)[0]])
    plt.ioff()
    if verbose:
        txt = "End of the evaluation over " + str(np.size(trk_streamlines))
        print(txt)
        send_mail(txt, subject="LifE status msg ")
    if outpathtrk is not None:
        outpathfile = str(
            outpathtrk) + subject + strproperty + "_lifeopt_test.trk"
        myheader = create_tractogram_header(outpathfile, *header)
        optimized_sl_gen = lambda: (s for s in optimized_sl)
        save_trk_heavy_duty(outpathfile,
                            streamlines=optimized_sl_gen,
                            affine=affine,
                            header=myheader)
        txt = ("Saved final trk at " + outpathfile)
        print(txt)
        send_mail(txt, subject="LifE save msg ")
        """
        except TypeError:
            txt=('Could not save new tractogram file, header of original trk file not properly implemented into '
                  'LifEvaluation')
            print(txt)
            send_mail(txt,subject="LifE error msg ")
        """
    """
    if interactive:
        ren = window.Renderer()
        ren.add(actor.streamtube(optimized_sl, cmap.line_colors(optimized_sl)))
        ren.add(ROI_actor)
        #ren.add(vol_actor)
        if interactive:
            window.show(ren)      
        if outpathfig is not None:
            print("reached windowrecord")
            window.record(ren, n_frames=1, out_path=outpathfig +'_life_optimized.png',
                size=(800, 800))
            print("did window record")
    """
    maxsize_var = 20525023825

    sizebeta = getsize(fiber_fit.beta)
    if sizebeta < maxsize_var:
        picklepath = outpathpickle + subject + strproperty + '_beta.p'
        txt = ("fiber_fit.beta saved at " + picklepath)
        pickle.dump(fiber_fit.beta, open(picklepath, "wb"))
        if verbose:
            print(txt)
            send_mail(txt, subject="LifE save msg ")
    else:
        txt = (
            "Object fiber_fit.beta exceeded the imposed the 20GB limit with a size of: "
            + str(sizebeta / (10 ^ 9)) + "GB")
        print(txt)
        send_mail(txt, subject="LifE error msg")

    sizecoords = getsize(fiber_fit.vox_coords)
    if sizecoords < maxsize_var:
        picklepath = outpathpickle + subject + strproperty + '_voxcoords.p'
        txt = ("fiber_fit.voxcoords saved at " + picklepath)
        pickle.dump(fiber_fit.vox_coords, open(picklepath, "wb"))
        if verbose:
            print(txt)
            send_mail(txt, subject="LifE save msg ")
    else:
        txt = (
            "Object fiber_fit.beta exceeded the imposed the 20GB limit with a size of: "
            + str(sizebeta / (10 ^ 9)) + "GB")
        print(txt)
        send_mail(txt, subject="LifE error msg")

    #predict diffusion data based on new model
    model_predict = fiber_fit.predict(
    )  #possible to predict based on different gtab or base signal (change gtab, S0)
    model_error = model_predict - fiber_fit.data  #compare original dwi data and the model fit, calculate error
    model_rmse = np.sqrt(
        np.mean(model_error[:, 10:]**2,
                -1))  #this is good, but must check ways to avoid overfitting
    #how does the model get built? add lasso? JS

    beta_baseline = np.zeros(
        fiber_fit.beta.shape[0]
    )  #baseline assumption where the streamlines weight is 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))

    size_meanrmse = getsize(mean_rmse)
    if size_meanrmse < maxsize_var:
        picklepath = outpathpickle + subject + strproperty + '_mean_rmse.p'
        txt = ("mean_rmse saved at " + picklepath)
        pickle.dump(mean_rmse, open(picklepath, "wb"))
        if verbose:
            print(txt)
            send_mail(txt, subject="LifE save msg ")
    else:
        txt = (
            "Object mean_rmse exceeded the imposed the 20GB limit with a size of: "
            + str(size_meanrmse / (10 ^ 9)) + " GB")
        print(txt)
        send_mail(txt, subject="LifE error msg")

    size_modelrmse = getsize(model_rmse)
    if size_modelrmse < maxsize_var:
        picklepath = outpathpickle + subject + strproperty + '_model_rmse.p'
        txt = ("model_rmse saved at " + picklepath)
        pickle.dump(model_rmse, open(picklepath, "wb"))
        if verbose:
            print(txt)
            send_mail(txt, subject="LifE save msg ")
    else:
        txt = (
            "Object model_rmse exceeded the imposed the 20GB limit with a size of: "
            + str(size_modelrmse / (10 ^ 9)) + " GB")
        print(txt)
        send_mail(txt, subject="LifE error msg")

    if outpathfig is not None:
        try:
            import matplotlib.pyplot as myplot
            fig, ax = plt.subplots(1)
            ax.hist(fiber_fit.beta, bins=100, histtype='step')
            LifEcreate_fig(fiber_fit.beta,
                           mean_rmse,
                           model_rmse,
                           fiber_fit.vox_coords,
                           dwidata,
                           subject,
                           t1_data=dwidata[:, :, :, 0],
                           outpathfig=outpathfig,
                           interactive=False,
                           strproperty=strproperty,
                           verbose=verbose)
        except:
            print(
                "Coult not launch life create fig, possibly qsub location (this is a template warning, to be improved upon"
            )
    return model_error, mean_error
Exemple #16
0
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)