Esempio n. 1
0
def test_check_multi_b():
    bvals = np.array([1000, 1000, 1000, 1000, 2000, 2000, 2000, 2000, 0])
    bvecs = generate_bvecs(bvals.shape[-1])
    gtab = gradient_table(bvals, bvecs)
    npt.assert_(check_multi_b(gtab, 2, non_zero=False))

    # We don't consider differences this small to be sufficient:
    bvals = np.array([1995, 1995, 1995, 1995, 2005, 2005, 2005, 2005, 0])
    bvecs = generate_bvecs(bvals.shape[-1])
    gtab = gradient_table(bvals, bvecs)
    npt.assert_(not check_multi_b(gtab, 2, non_zero=True))

    # Unless you specify that you are interested in this magnitude of changes:
    npt.assert_(check_multi_b(gtab, 2, non_zero=True, bmag=1))

    # Or if you consider zero to be one of your b-values:
    npt.assert_(check_multi_b(gtab, 2, non_zero=False))
def test_check_multi_b():
    bvals = np.array([1000, 1000, 1000, 1000, 2000, 2000, 2000, 2000, 0])
    bvecs = generate_bvecs(bvals.shape[-1])
    gtab = gradient_table(bvals, bvecs)
    npt.assert_(check_multi_b(gtab, 2, non_zero=False))

    # We don't consider differences this small to be sufficient:
    bvals = np.array([1995, 1995, 1995, 1995, 2005, 2005, 2005, 2005, 0])
    bvecs = generate_bvecs(bvals.shape[-1])
    gtab = gradient_table(bvals, bvecs)
    npt.assert_(not check_multi_b(gtab, 2, non_zero=True))

    # Unless you specify that you are interested in this magnitude of changes:
    npt.assert_(check_multi_b(gtab, 2, non_zero=True, bmag=1))

    # Or if you consider zero to be one of your b-values:
    npt.assert_(check_multi_b(gtab, 2, non_zero=False))
Esempio n. 3
0
    def __init__(self, gtab, fit_method="NLS", *args, **kwargs):
        """ Free Water Diffusion Tensor Model [1]_.

        Parameters
        ----------
        gtab : GradientTable class instance
        fit_method : str or callable
            str can be one of the following:

            'WLS' for weighted linear least square fit according to [1]_
                :func:`fwdti.wls_iter`
            'NLS' for non-linear least square fit according to [1]_
                :func:`fwdti.nls_iter`

            callable has to have the signature:
              fit_method(design_matrix, data, *args, **kwargs)
        args, kwargs : arguments and key-word arguments passed to the
           fit_method. See fwdti.wls_iter, fwdti.nls_iter for
           details

        References
        ----------
        .. [1] Henriques, R.N., Rokem, A., Garyfallidis, E., St-Jean, S.,
               Peterson E.T., Correia, M.M., 2017. [Re] Optimization of a free
               water elimination two-compartment model for diffusion tensor
               imaging. ReScience volume 3, issue 1, article number 2

        """
        ReconstModel.__init__(self, gtab)

        if not callable(fit_method):
            try:
                fit_method = common_fit_methods[fit_method]
            except KeyError:
                e_s = '"' + str(fit_method) + '" is not a known fit '
                e_s += 'method, the fit method should either be a '
                e_s += 'function or one of the common fit methods'
                raise ValueError(e_s)
        self.fit_method = fit_method
        self.design_matrix = design_matrix(self.gtab)
        self.args = args
        self.kwargs = kwargs

        # Check if at least three b-values are given
        enough_b = check_multi_b(self.gtab, 3, non_zero=False)
        if not enough_b:
            mes = "fwDTI requires at least 3 b-values (which can include b=0)"
            raise ValueError(mes)
Esempio n. 4
0
    def __init__(self, gtab, fit_method="NLS", *args, **kwargs):
        """ Free Water Diffusion Tensor Model [1]_.

        Parameters
        ----------
        gtab : GradientTable class instance
        fit_method : str or callable
            str can be one of the following:

            'WLS' for weighted linear least square fit according to [1]_
                :func:`fwdti.wls_iter`
            'NLS' for non-linear least square fit according to [1]_
                :func:`fwdti.nls_iter`

            callable has to have the signature:
              fit_method(design_matrix, data, *args, **kwargs)
        args, kwargs : arguments and key-word arguments passed to the
           fit_method. See fwdti.wls_iter, fwdti.nls_iter for
           details

        References
        ----------
        .. [1] Hoy, A.R., Koay, C.G., Kecskemeti, S.R., Alexander, A.L., 2014.
               Optimization of a free water elimination two-compartmental model
               for diffusion tensor imaging. NeuroImage 103, 323-333.
               doi: 10.1016/j.neuroimage.2014.09.053
        """
        ReconstModel.__init__(self, gtab)

        if not callable(fit_method):
            try:
                fit_method = common_fit_methods[fit_method]
            except KeyError:
                e_s = '"' + str(fit_method) + '" is not a known fit '
                e_s += 'method, the fit method should either be a '
                e_s += 'function or one of the common fit methods'
                raise ValueError(e_s)
        self.fit_method = fit_method
        self.design_matrix = design_matrix(self.gtab)
        self.args = args
        self.kwargs = kwargs

        # Check if at least three b-values are given
        enough_b = check_multi_b(self.gtab, 3, non_zero=False)
        if not enough_b:
            mes = "fwDTI requires at least 3 b-values (which can include b=0)"
            raise ValueError(mes)
Esempio n. 5
0
    def __init__(self, gtab, fit_method="NLS", *args, **kwargs):
        """ Free Water Diffusion Tensor Model [1]_.

        Parameters
        ----------
        gtab : GradientTable class instance
        fit_method : str or callable
            str can be one of the following:

            'WLS' for weighted linear least square fit according to [1]_
                :func:`fwdti.wls_iter`
            'NLS' for non-linear least square fit according to [1]_
                :func:`fwdti.nls_iter`

            callable has to have the signature:
              fit_method(design_matrix, data, *args, **kwargs)
        args, kwargs : arguments and key-word arguments passed to the
           fit_method. See fwdti.wls_iter, fwdti.nls_iter for
           details

        References
        ----------
        .. [1] Hoy, A.R., Koay, C.G., Kecskemeti, S.R., Alexander, A.L., 2014.
               Optimization of a free water elimination two-compartmental model
               for diffusion tensor imaging. NeuroImage 103, 323-333.
               doi: 10.1016/j.neuroimage.2014.09.053
        """
        ReconstModel.__init__(self, gtab)

        if not callable(fit_method):
            try:
                fit_method = common_fit_methods[fit_method]
            except KeyError:
                e_s = '"' + str(fit_method) + '" is not a known fit '
                e_s += 'method, the fit method should either be a '
                e_s += 'function or one of the common fit methods'
                raise ValueError(e_s)
        self.fit_method = fit_method
        self.design_matrix = design_matrix(self.gtab)
        self.args = args
        self.kwargs = kwargs

        # Check if at least three b-values are given
        enough_b = check_multi_b(self.gtab, 3, non_zero=False)
        if not enough_b:
            mes = "fwDTI requires at least 3 b-values (which can include b=0)"
            raise ValueError(mes)
Esempio n. 6
0
    def __init__(self, gtab, bmag=None, return_S0_hat=False, *args, **kwargs):
        """ Mean Signal Diffusion Kurtosis Model [1]_.

        Parameters
        ----------
        gtab : GradientTable class instance

        bmag : int
            The order of magnitude that the bvalues have to differ to be
            considered an unique b-value. Default: derive this value from the
            maximal b-value provided: $bmag=log_{10}(max(bvals)) - 1$.

        return_S0_hat : bool
            If True, also return S0 values for the fit.

        args, kwargs : arguments and keyword arguments passed to the
        fit_method. See msdki.wls_fit_msdki for details

        References
        ----------
        .. [1] Henriques, R.N., 2018. Advanced Methods for Diffusion MRI Data
               Analysis and their Application to the Healthy Ageing Brain
               (Doctoral thesis). Downing College, University of Cambridge.
               https://doi.org/10.17863/CAM.29356

        """
        ReconstModel.__init__(self, gtab)

        self.return_S0_hat = return_S0_hat
        self.ubvals = unique_bvals_magnitude(gtab.bvals, bmag=bmag)
        self.design_matrix = design_matrix(self.ubvals)
        self.bmag = bmag
        self.args = args
        self.kwargs = kwargs
        self.min_signal = self.kwargs.pop('min_signal', MIN_POSITIVE_SIGNAL)
        if self.min_signal is not None and self.min_signal <= 0:
            e_s = "The `min_signal` key-word argument needs to be strictly"
            e_s += " positive."
            raise ValueError(e_s)

        # Check if at least three b-values are given
        enough_b = check_multi_b(self.gtab, 3, non_zero=False, bmag=bmag)
        if not enough_b:
            mes = "MSDKI requires at least 3 b-values (which can include b=0)"
            raise ValueError(mes)
Esempio n. 7
0
    def __init__(self, gtab, bmag=None, return_S0_hat=False, *args, **kwargs):
        """ Mean Signal Diffusion Kurtosis Model [1]_.

        Parameters
        ----------
        gtab : GradientTable class instance

        bmag : int
            The order of magnitude that the bvalues have to differ to be
            considered an unique b-value. Default: derive this value from the
            maximal b-value provided: $bmag=log_{10}(max(bvals)) - 1$.

        return_S0_hat : bool
            If True, also return S0 values for the fit.

        args, kwargs : arguments and keyword arguments passed to the
        fit_method. See msdki.wls_fit_msdki for details

        References
        ----------
        .. [1] Henriques, R.N., 2018. Advanced Methods for Diffusion MRI Data
               Analysis and their Application to the Healthy Ageing Brain
               (Doctoral thesis). Downing College, University of Cambridge.
               https://doi.org/10.17863/CAM.29356
        """
        ReconstModel.__init__(self, gtab)

        self.return_S0_hat = return_S0_hat
        self.ubvals = unique_bvals(gtab.bvals, bmag=bmag)
        self.design_matrix = design_matrix(self.ubvals)
        self.bmag = bmag
        self.args = args
        self.kwargs = kwargs
        self.min_signal = self.kwargs.pop('min_signal', MIN_POSITIVE_SIGNAL)
        if self.min_signal is not None and self.min_signal <= 0:
            e_s = "The `min_signal` key-word argument needs to be strictly"
            e_s += " positive."
            raise ValueError(e_s)

        # Check if at least three b-values are given
        enough_b = check_multi_b(self.gtab, 3, non_zero=False, bmag=bmag)
        if not enough_b:
            mes = "MSDKI requires at least 3 b-values (which can include b=0)"
            raise ValueError(mes)
Esempio n. 8
0
    def init(gtab, model="DTI", **kwargs):
        """
        Instatiate a diffusion model.

        Parameters
        ----------
        gtab : :obj:`numpy.ndarray`
            An array representing the gradient table in RAS+B format.
        model : :obj:`str`
            Diffusion model.
            Options: ``"3DShore"``, ``"SFM"``, ``"GP"``, ``"DTI"``,
            ``"DKI"``, ``"S0"``

        Return
        ------
        model : :obj:`~dipy.reconst.ReconstModel`
            An model object compliant with DIPY's interface.

        """
        if model.lower() in ("s0", "b0"):
            return TrivialB0Model(gtab=gtab, S0=kwargs.pop("S0"))

        if model.lower() in ("avg", "average", "mean"):
            return AverageDWModel(gtab=gtab, **kwargs)

        # Generate a GradientTable object for DIPY
        gtab = _rasb2dipy(gtab)
        param = {}

        if model.lower().startswith("3dshore"):
            from dipy.reconst.shore import ShoreModel as Model

            param = {
                "radial_order": 6,
                "zeta": 700,
                "lambdaN": 1e-8,
                "lambdaL": 1e-8,
            }

        elif model.lower() in ("sfm", "gp"):
            Model = SparseFascicleModel
            param = {"solver": "ElasticNet"}

            if model.lower() == "gp":
                from sklearn.gaussian_process import GaussianProcessRegressor
                param = {"solver": GaussianProcessRegressor}

            multi_b = check_multi_b(gtab, 2, non_zero=False)
            if multi_b:
                from dipy.reconst.sfm import ExponentialIsotropicModel
                param.update({"isotropic": ExponentialIsotropicModel})

        elif model.lower() in ("dti", "dki"):
            Model = DTIModel if model.lower() == "dti" else DKIModel

        else:
            raise NotImplementedError(f"Unsupported model <{model}>.")

        omp_nthreads = kwargs.pop("omp_nthreads", None)
        param.update(kwargs)
        return get_run_cls(Model(gtab, **param), omp_nthreads)
Esempio n. 9
0
    def main(self):

        self.imgFile = str(self.imgFile)
        self.maskFile = str(self.maskFile)

        self.mk_low_high = [
            float(x) for x in self.mk_low_high[1:-1].split(',')
        ]
        self.mk_low_high.sort()
        self.fa_low_high = [
            float(x) for x in self.fa_low_high[1:-1].split(',')
        ]
        self.fa_low_high.sort()
        self.md_low_high = [
            float(x) for x in self.md_low_high[1:-1].split(',')
        ]
        self.md_low_high.sort()
        hdr = None
        affine = None

        if not self.out_dir:
            self.out_dir = os.path.dirname(self.imgFile)

        outPrefix = os.path.join(self.out_dir,
                                 os.path.basename(self.imgFile).split('.')[0])

        if self.imgFile.endswith('.nii.gz') or self.imgFile.endswith('.nii'):
            bvals, bvecs = read_bvals_bvecs(self.bvalFile, self.bvecFile)
            outFormat = '.nii.gz'

            img = nib.load(self.imgFile)
            data = img.get_data()

            affine = img.affine
            grad_axis = 3
            if len(data.shape) != 4:
                raise AttributeError('Not a valid dwi, check dimension')

        elif self.imgFile.endswith('.nrrd') or self.imgFile.endswith('.nhdr'):

            img = nrrd.read(self.imgFile)
            data = img[0]
            hdr = img[1]

            outFormat = '.nrrd'

            bvals, bvecs, b_max, grad_axis, N = nrrd_bvals_bvecs(hdr)

            # put the gradients along last axis
            if grad_axis != 3:
                data = np.moveaxis(data, grad_axis, 3)

        # provide the user a liberty to specify different file formats for dwi and mask
        if self.maskFile.endswith('.nii.gz') or self.maskFile.endswith('.nii'):
            mask_data = nib.load(self.maskFile).get_data()

        elif self.maskFile.endswith('.nrrd') or self.maskFile.endswith(
                '.nhdr'):
            mask_data = nrrd.read(self.maskFile)[0]

        data = applymask(data, mask_data)

        gtab = gradient_table(bvals, bvecs)

        dtimodel = dti.TensorModel(gtab)
        dtifit = dtimodel.fit(data, mask_data)
        evals = dtifit.evals
        fa = dtifit.fa
        md = dtifit.md
        ad = dtifit.ad
        rd = dtifit.rd
        evals_zero = evals < 0.
        evals_zero_mask = (evals_zero[..., 0] | evals_zero[..., 1]
                           | evals_zero[..., 2]) * 1

        mkFlag = check_multi_b(gtab, n_bvals=3)
        if mkFlag:
            dkimodel = dki.DiffusionKurtosisModel(gtab)
            dkifit = dkimodel.fit(data, mask_data)
            mk = dkifit.mk(
                0, 3)  # http://nipy.org/dipy/examples_built/reconst_dki.html

        else:
            warnings.warn(
                "DIPY DKI requires at least 3 b-shells (which can include b=0), "
                "kurtosis quality cannot be computed.")

        fa_mask = mask_calc(fa, self.fa_low_high)
        md_mask = mask_calc(md, self.md_low_high)

        where_b0s = np.where(bvals == 0)[0]
        where_dwi = np.where(bvals != 0)[0]
        bse_data = data[..., where_b0s].mean(-1)
        b0File = outPrefix + '_b0' + outFormat
        save_map(b0File, bse_data, affine, hdr)

        # prevent division by zero during normalization
        bse_data[bse_data < 1] = 1.
        extend_bse = np.expand_dims(bse_data, grad_axis)
        extend_bse = np.repeat(extend_bse, len(where_dwi), grad_axis)
        curtail_dwi = np.take(data, where_dwi, axis=grad_axis)

        # 1 / b0 * min(b0 - Gi)
        minOverGrads = np.min(extend_bse - curtail_dwi,
                              axis=grad_axis) / bse_data

        # another way to prevent division by zero: 1/b0 * min(b0-Gi) with condition at b0~eps
        # minOverGrads = np.min(extend_bse - curtail_dwi, axis=grad_axis) / (bse_data + eps)
        # minOverGrads[(bse_data < eps) & (minOverGrads < 5 * eps)] = 0.
        # minOverGrads[(bse_data < eps) & (minOverGrads > 5 * eps)] = 10.

        minOverGradsNegativeMask = (minOverGrads < 0) * 1

        # compute histograms
        print('\nminOverGrads (b0-Gi)/b0 histogram')
        bins = [-inf, 0, inf]
        negative, _ = hist_calc(minOverGrads, bins)

        print('\nevals<0 histogram')
        bins = [-inf, 0, inf]
        hist_calc(evals, bins)

        print('\nfractional anisotropy histogram')
        bins = form_bins(self.fa_low_high)
        hist_calc(fa, bins)

        print('\nmean diffusivity histogram')
        bins = form_bins(self.md_low_high)
        hist_calc(md, bins)

        if mkFlag:
            print('\nmean kurtosis mask')
            bins = form_bins(self.mk_low_high)
            hist_calc(mk, bins)

        # save histograms
        print('\nCreating minOverGrads image ...')
        save_map(outPrefix + '_minOverGrads' + outFormat, minOverGrads, affine,
                 hdr)
        print('\nCreating minOverGrads<0 mask ...')
        save_map(outPrefix + '_minOverGradsMask' + outFormat,
                 minOverGradsNegativeMask.astype('short'), affine, hdr)

        print('\nCreating evals<0 mask ...')
        save_map(outPrefix + '_evalsZeroMask' + outFormat,
                 evals_zero_mask.astype('short'), affine, hdr)

        if mkFlag:
            mk_mask = mask_calc(mk, self.mk_low_high)
            print('\nCreating mk image ...')
            save_map(outPrefix + '_MK' + outFormat, mk, affine, hdr)
            print('Creating mk out of range mask ...')
            save_map(outPrefix + '_MK_mask' + outFormat,
                     mk_mask.astype('short'), affine, hdr)
        else:
            mk = np.zeros(fa.shape)

        print('\nCreating fa image ...')
        save_map(outPrefix + '_FA' + outFormat, fa, affine, hdr)
        print('Creating fa out of range mask ...')
        save_map(outPrefix + '_FA_mask' + outFormat, fa_mask.astype('short'),
                 affine, hdr)

        print('\nCreating md image ....')
        save_map(outPrefix + '_MD' + outFormat, md, affine, hdr)
        print('Creating md out of range mask ...')
        save_map(outPrefix + '_MD_mask' + outFormat, md_mask.astype('short'),
                 affine, hdr)

        # conclusion
        N_mask = mask_data.size
        print('\n\nConclusion: ')
        print('The masked dwi has %.5f%% voxels with values less than b0' %
              (negative * 100))
        print('The masked dwi has %.5f%% voxels with negative eigen value' %
              (evals_zero_mask.sum() / N_mask * 100))
        print('The masked dwi has %.5f%% voxels with FA out of [%f,%f]' %
              (fa_mask.sum() / N_mask * 100, self.fa_low_high[0],
               self.fa_low_high[1]))
        print('The masked dwi has %.5f%% voxels with MD out of [%f,%f]' %
              (md_mask.sum() / N_mask * 100, self.md_low_high[0],
               self.md_low_high[1]))
        if mkFlag:
            print('The masked dwi has %.5f%% voxels with MK out of [%f,%f]' %
                  (mk_mask.sum() / N_mask * 100, self.mk_low_high[0],
                   self.mk_low_high[1]))

        # perform roi based analysis
        if self.template and self.labelMap:
            antsReg(b0File, self.maskFile, self.template, outPrefix)
            warp = outPrefix + '1Warp.nii.gz'
            trans = outPrefix + '0GenericAffine.mat'
            outLabelMapFile = outPrefix + '_labelMap.nii.gz'
            applyXform(self.labelMap,
                       b0File,
                       warp,
                       trans,
                       outLabelMapFile,
                       interp='NearestNeighbor')
            rm = local['rm']
            rm(warp, trans, outPrefix + 'Warped.nii.gz',
               outPrefix + '1InverseWarp.nii.gz',
               outPrefix + 'InverseWarped.nii.gz')

            outLabelMap = nib.load(outLabelMapFile).get_data()
            labels = np.unique(outLabelMap)[1:]
            label2name = parse_labels(labels,
                                      self.lut._path if self.lut else None)

            print('Creating ROI based statistics ...')
            stat_file = outPrefix + f'_{self.name}_stat.csv'

            df = pd.DataFrame(columns=[
                'region',
                'FA_mean',
                'FA_std',
                'MD_mean',
                'MD_std',
                'AD_mean',
                'AD_std',
                'RD_mean',
                'RD_std',
                'total_{min_i(b0-Gi)<0}',
                'total_evals<0',
                'MK_mean',
                'MK_std',
            ])

            for i, label in enumerate(label2name.keys()):
                roi = outLabelMap == int(label)

                properties = [
                    num2str(x) for x in [
                        fa[roi > 0].mean(), fa[roi > 0].std(), md[roi > 0].
                        mean(), md[roi > 0].std(), ad[roi > 0].mean(), ad[
                            roi > 0].std(), rd[roi > 0].mean(),
                        rd[roi > 0].std(), minOverGradsNegativeMask[
                            roi > 0].sum(), evals_zero_mask[roi > 0].sum(), mk[
                                roi > 0].mean(), mk[roi > 0].std()
                    ]
                ]

                df.loc[i] = [label2name[label]] + properties

            df = df.set_index('region')
            # print(df)
            df.to_csv(stat_file)
            print('See ', os.path.abspath(stat_file))