Пример #1
0
    def fit(
        dwdata,
        *,
        n_iter=1,
        align_kwargs=None,
        model="b0",
        omp_nthreads=None,
        seed=None,
        **kwargs,
    ):
        r"""
        Estimate head-motion and Eddy currents.

        Parameters
        ----------
        dwdata : :obj:`~eddymotion.dmri.DWI`
            The target DWI dataset, represented by this tool's internal
            type. The object is used in-place, and will contain the estimated
            parameters in its ``em_affines`` property, as well as the rotated
            *b*-vectors within its ``gradients`` property.
        n_iter : :obj:`int`
            Number of iterations this particular model is going to be repeated.
        align_kwargs : :obj:`dict`
            Parameters to configure the image registration process.
        model : :obj:`str`
            Selects the diffusion model that will generate the registration target
            corresponding to each gradient map.
            See :obj:`~eddymotion.model.ModelFactory` for allowed models (and corresponding
            keywords).
        seed : :obj:`int` or :obj:`bool`
            Seed the random number generator (necessary when we want deterministic
            estimation).

        Return
        ------
        affines : :obj:`list` of :obj:`numpy.ndarray`
            A list of :math:`4 \times 4` affine matrices encoding the estimated
            parameters of the deformations caused by head-motion and eddy-currents.

        """
        align_kwargs = align_kwargs or {}
        reg_target_type = ("dwi" if model.lower() not in ("b0", "s0", "avg",
                                                          "average",
                                                          "mean") else "b0")

        if seed or seed == 0:
            np.random.seed(20210324 if seed is True else seed)

        bmask_img = None
        if dwdata.brainmask is not None:
            _, bmask_img = mkstemp(suffix="_bmask.nii.gz")
            nb.Nifti1Image(dwdata.brainmask.astype("uint8"), dwdata.affine,
                           None).to_filename(bmask_img)
            kwargs["mask"] = dwdata.brainmask

        kwargs["S0"] = _advanced_clip(dwdata.bzero)

        if "n_threads" in kwargs:
            align_kwargs["num_threads"] = kwargs["n_threads"]

        for i_iter in range(1, n_iter + 1):
            index_order = np.arange(len(dwdata))
            np.random.shuffle(index_order)
            with tqdm(total=len(index_order), unit="dwi") as pbar:
                for i in index_order:
                    # run a original-to-synthetic affine registration
                    with TemporaryDirectory() as tmpdir:
                        pbar.write(
                            f"Pass {i_iter}/{n_iter} | Processing b-index <{i}> in <{tmpdir}>"
                        )
                        data_train, data_test = dwdata.logo_split(i,
                                                                  with_b0=True)

                        # Factory creates the appropriate model and pipes arguments
                        dwmodel = ModelFactory.init(gtab=data_train[1],
                                                    model=model,
                                                    omp_nthreads=omp_nthreads,
                                                    **kwargs)

                        # fit the model
                        dwmodel.fit(data_train[0])

                        # generate a synthetic dw volume for the test gradient
                        predicted = dwmodel.predict(data_test[1])

                        tmpdir = Path(tmpdir)
                        moving = tmpdir / "moving.nii.gz"
                        fixed = tmpdir / "fixed.nii.gz"
                        _to_nifti(data_test[0], dwdata.affine, moving)
                        _to_nifti(
                            predicted,
                            dwdata.affine,
                            fixed,
                            clip=reg_target_type == "dwi",
                        )

                        registration = Registration(
                            terminal_output="file",
                            from_file=pkg_fn(
                                "eddymotion",
                                f"config/dwi-to-{reg_target_type}_level{i_iter}.json",
                            ),
                            fixed_image=str(fixed.absolute()),
                            moving_image=str(moving.absolute()),
                            **align_kwargs,
                        )
                        if bmask_img:
                            registration.inputs.fixed_image_masks = [
                                "NULL", bmask_img
                            ]

                        if dwdata.em_affines and dwdata.em_affines[
                                i] is not None:
                            mat_file = tmpdir / f"init{i_iter}.mat"
                            dwdata.em_affines[i].to_filename(mat_file,
                                                             fmt="itk")
                            registration.inputs.initial_moving_transform = str(
                                mat_file)

                        # execute ants command line
                        result = registration.run(cwd=str(tmpdir)).outputs

                        # read output transform
                        xform = nt.io.itk.ITKLinearTransform.from_filename(
                            result.forward_transforms[0]).to_ras(
                                reference=fixed, moving=moving)

                    # update
                    dwdata.set_transform(i, xform)
                    pbar.update()

        return dwdata.em_affines