def test_fit_and_transform_modality_with_perf():
    anat_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    func_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'func.nii.gz')
    template_file = os.path.join(tst.tmpdir, 'template.nii.gz')
    crop_and_oblique(anat_file, template_file)
    registrator = TemplateRegistrator(template_file, 400,
                                      output_dir=tst.tmpdir,
                                      use_rats_tool=False, verbose=False,
                                      registration_kind='affine')
    registrator.fit_anat(anat_file)
    assert_raises_regex(
        ValueError, 'has not been perf fitted',
        registrator.transform_modality_like, func_file, 'perf')
    func_img = nibabel.load(func_file)
    m0_img = nibabel.Nifti1Image(func_img.get_data()[..., 0], func_img.affine)
    m0_file = os.path.join(tst.tmpdir, 'm0.nii.gz')
    m0_img.to_filename(m0_file)

    # test fit_modality for perf
    registrator.fit_modality(m0_file, 'perf')
    assert_true(_check_same_fov(nibabel.load(registrator.registered_perf_),
                                nibabel.load(template_file)))

    # test transform_modality for perf    
    m0_like_file = os.path.join(tst.tmpdir, 'm0_like.nii.gz')
    empty_img_like(m0_file, m0_like_file)
    transformed_file = registrator.transform_modality_like(m0_like_file,
                                                           'perf')
    assert_true(_check_same_fov(nibabel.load(transformed_file),
                                nibabel.load(template_file)))
def test_fit_anat_and_transform_anat_like():
    anat_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    template_file = os.path.join(tst.tmpdir, 'template.nii.gz')
    # Create template
    crop_and_oblique(anat_file, template_file)
    registrator = TemplateRegistrator(template_file, 400,
                                      output_dir=tst.tmpdir,
                                      use_rats_tool=False, verbose=False,
                                      registration_kind='affine')
    assert_raises_regex(
        ValueError, 'has not been anat fitted',
        registrator.transform_anat_like, anat_file)

    # test fit_anat
    registrator.fit_anat(anat_file)
    assert_true(_check_same_fov(nibabel.load(registrator.registered_anat_),
                                nibabel.load(template_file)))

    # test transform_anat_like
    anat_like_file = os.path.join(tst.tmpdir, 'anat_like.nii.gz')
    empty_img_like(anat_file, anat_like_file)
    registrator.fit_anat(anat_file)
    
    transformed_file = registrator.transform_anat_like(anat_like_file)
    assert_true(_check_same_fov(nibabel.load(transformed_file),
                                nibabel.load(template_file)))
def test_fit_transform_and_inverse_modality_with_func():
    anat_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    func_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'func.nii.gz')
    template_file = os.path.join(tst.tmpdir, 'template.nii.gz')
    crop_and_oblique(anat_file, template_file)

    registrator = TemplateRegistrator(template_file, 400,
                                      output_dir=tst.tmpdir,
                                      use_rats_tool=False, verbose=False,
                                      registration_kind='affine')
    registrator.fit_anat(anat_file)

    assert_raises_regex(
        ValueError, "Only 'func' and 'perf' ", registrator.fit_modality,
        func_file, 'diffusion')
    assert_raises_regex(
        ValueError, "'t_r' is needed for slice ", registrator.fit_modality,
        func_file, 'func')
    assert_raises_regex(
        ValueError, 'has not been func fitted',
        registrator.transform_modality_like, func_file, 'func')

    # test fit_modality for func
    registrator.fit_modality(func_file, 'func', slice_timing=False)
    registered_func_img = nibabel.load(registrator.registered_func_)
    template_img = nibabel.load(template_file)
    np.testing.assert_array_almost_equal(registered_func_img.affine,
                                         template_img.affine)
    np.testing.assert_array_equal(registered_func_img.shape[:-1],
                                  template_img.shape)


    # test transform_modality for func
    func_like_file = os.path.join(tst.tmpdir, 'func_like.nii.gz')
    empty_img_like(func_file, func_like_file)
    transformed_file = registrator.transform_modality_like(func_like_file,
                                                           'func')
    transformed_img = nibabel.load(transformed_file)
    assert_true(_check_same_fov(transformed_img, nibabel.load(template_file)))

    # test transform then inverse transform brings back to the original image
    inverse_transformed_file = registrator.inverse_transform_towards_modality(
        transformed_file, 'func')
    inverse_transformed_img = nibabel.load(inverse_transformed_file)
    func_like_img = nibabel.load(func_like_file)
    assert_true(_check_same_fov(inverse_transformed_img, func_like_img))
    np.testing.assert_array_equal(inverse_transformed_img.get_data(),
                                  func_like_img.get_data())

    # test inverse transform then transform brings back to the original image 
    transformed_file2 = registrator.transform_modality_like(
        inverse_transformed_file, 'func')
    transformed_img2 = nibabel.load(transformed_file2)
    assert_true(_check_same_fov(transformed_img2,
                                transformed_img))
    np.testing.assert_array_equal(transformed_img2.get_data(),
                                  transformed_img.get_data())
def test_check_same_fov():

    affine_a = np.eye(4)
    affine_b = np.eye(4) * 2

    shape_a = (2, 2, 2)
    shape_b = (3, 3, 3)

    shape_a_affine_a = nibabel.Nifti1Image(np.empty(shape_a), affine_a)
    shape_a_affine_a_2 = nibabel.Nifti1Image(np.empty(shape_a), affine_a)
    shape_a_affine_b = nibabel.Nifti1Image(np.empty(shape_a), affine_b)
    shape_b_affine_a = nibabel.Nifti1Image(np.empty(shape_b), affine_a)
    shape_b_affine_b = nibabel.Nifti1Image(np.empty(shape_b), affine_b)

    niimg_conversions._check_same_fov(a=shape_a_affine_a, b=shape_a_affine_a_2, raise_error=True)

    assert_raises_regex(
        ValueError,
        "[ac] and [ac] do not have the same affine",
        niimg_conversions._check_same_fov,
        a=shape_a_affine_a,
        b=shape_a_affine_a_2,
        c=shape_a_affine_b,
        raise_error=True,
    )

    assert_raises_regex(
        ValueError,
        "[ab] and [ab] do not have the same shape",
        niimg_conversions._check_same_fov,
        a=shape_a_affine_a,
        b=shape_b_affine_a,
        raise_error=True,
    )

    assert_raises_regex(
        ValueError,
        "[ab] and [ab] do not have the same affine",
        niimg_conversions._check_same_fov,
        a=shape_b_affine_b,
        b=shape_a_affine_a,
        raise_error=True,
    )

    assert_raises_regex(
        ValueError,
        "[ab] and [ab] do not have the same shape",
        niimg_conversions._check_same_fov,
        a=shape_b_affine_b,
        b=shape_a_affine_a,
        raise_error=True,
    )
def filter_and_mask(imgs, mask_img_, parameters,
                    memory_level=0, memory=Memory(cachedir=None),
                    verbose=0,
                    confounds=None,
                    copy=True):

    imgs = _utils.check_niimg(imgs, atleast_4d=True, ensure_ndim=4)

    # Check whether resampling is truly necessary. If so, crop mask
    # as small as possible in order to speed up the process

    if not _check_same_fov(imgs, mask_img_):
        parameters = copy_object(parameters)
        # now we can crop
        mask_img_ = image.crop_img(mask_img_, copy=False)
        parameters['target_shape'] = mask_img_.shape
        parameters['target_affine'] = mask_img_.get_affine()

    data, affine = filter_and_extract(imgs, _ExtractionFunctor(mask_img_),
                                      parameters,
                                      memory_level=memory_level,
                                      memory=memory,
                                      verbose=verbose,
                                      confounds=confounds, copy=copy)

    # For _later_: missing value removal or imputing of missing data
    # (i.e. we want to get rid of NaNs, if smoothing must be done
    # earlier)
    # Optionally: 'doctor_nan', remove voxels with NaNs, other option
    # for later: some form of imputation

    return data, affine
Exemple #6
0
def filter_and_mask(imgs, mask_img_, parameters,
                    memory_level=0, memory=Memory(cachedir=None),
                    verbose=0,
                    confounds=None,
                    copy=True):

    imgs = _utils.check_niimg(imgs, atleast_4d=True, ensure_ndim=4)

    # Check whether resampling is truly necessary. If so, crop mask
    # as small as possible in order to speed up the process

    if not _check_same_fov(imgs, mask_img_):
        parameters = copy_object(parameters)
        # now we can crop
        mask_img_ = image.crop_img(mask_img_, copy=False)
        parameters['target_shape'] = mask_img_.shape
        parameters['target_affine'] = mask_img_.get_affine()

    data, affine = filter_and_extract(imgs, _ExtractionFunctor(mask_img_),
                                      parameters,
                                      memory_level=memory_level,
                                      memory=memory,
                                      verbose=verbose,
                                      confounds=confounds, copy=copy)

    # For _later_: missing value removal or imputing of missing data
    # (i.e. we want to get rid of NaNs, if smoothing must be done
    # earlier)
    # Optionally: 'doctor_nan', remove voxels with NaNs, other option
    # for later: some form of imputation

    return data, affine
Exemple #7
0
def test_afni_unifize():
    in_file = os.path.join(os.path.dirname(testing_data.__file__),
                           'func.nii.gz')
    unbiased_file = bias_correction.afni_unifize(in_file,
                                                 write_dir=tst.tmpdir,
                                                 verbose=False)
    assert_true(
        _check_same_fov(nibabel.load(unbiased_file), nibabel.load(in_file)))
def test_check_same_fov():

    affine_a = np.eye(4)
    affine_b = np.eye(4) * 2

    shape_a = (2, 2, 2)
    shape_b = (3, 3, 3)

    shape_a_affine_a = nibabel.Nifti1Image(np.empty(shape_a), affine_a)
    shape_a_affine_a_2 = nibabel.Nifti1Image(np.empty(shape_a), affine_a)
    shape_a_affine_b = nibabel.Nifti1Image(np.empty(shape_a), affine_b)
    shape_b_affine_a = nibabel.Nifti1Image(np.empty(shape_b), affine_a)
    shape_b_affine_b = nibabel.Nifti1Image(np.empty(shape_b), affine_b)

    niimg_conversions._check_same_fov(a=shape_a_affine_a,
                                      b=shape_a_affine_a_2,
                                      raise_error=True)

    assert_raises_regex(ValueError,
                        '[ac] and [ac] do not have the same affine',
                        niimg_conversions._check_same_fov,
                        a=shape_a_affine_a,
                        b=shape_a_affine_a_2,
                        c=shape_a_affine_b,
                        raise_error=True)

    assert_raises_regex(ValueError,
                        '[ab] and [ab] do not have the same shape',
                        niimg_conversions._check_same_fov,
                        a=shape_a_affine_a,
                        b=shape_b_affine_a,
                        raise_error=True)

    assert_raises_regex(ValueError,
                        '[ab] and [ab] do not have the same affine',
                        niimg_conversions._check_same_fov,
                        a=shape_b_affine_b,
                        b=shape_a_affine_a,
                        raise_error=True)

    assert_raises_regex(ValueError,
                        '[ab] and [ab] do not have the same shape',
                        niimg_conversions._check_same_fov,
                        a=shape_b_affine_b,
                        b=shape_a_affine_a,
                        raise_error=True)
Exemple #9
0
def test_compute_histo_brain_mask():
    head_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    brain_mask_file = brain_mask.compute_histo_brain_mask(
        head_file, 400, write_dir=tst.tmpdir,
        verbose=False)
    assert_true(os.path.isfile(brain_mask_file))
    assert_true(_check_same_fov(nibabel.load(brain_mask_file),
                                nibabel.load(head_file)))
def compute_confounds(imgs, mask_img, n_confounds=5, get_randomized_svd=False,
                      compute_not_mask=False):
    """
    """
    confounds = []
    if not isinstance(imgs, collections.Iterable) or \
            isinstance(imgs, _basestring):
        imgs = [imgs, ]

    img = _utils.check_niimg_4d(imgs[0])
    shape = img.shape[:3]
    affine = get_affine(img)

    if isinstance(mask_img, _basestring):
        mask_img = _utils.check_niimg_3d(mask_img)

    if not _check_same_fov(img, mask_img):
        mask_img = resample_img(
            mask_img, target_shape=shape, target_affine=affine,
            interpolation='nearest')

    if compute_not_mask:
        print("Non mask based confounds extraction")
        not_mask_data = np.logical_not(mask_img.get_data().astype(np.int))
        whole_brain_mask = masking.compute_multi_epi_mask(imgs)
        not_mask = np.logical_and(not_mask_data, whole_brain_mask.get_data())
        mask_img = new_img_like(img, not_mask.astype(np.int), affine)

    for img in imgs:
        print("[Confounds Extraction] {0}".format(img))
        img = _utils.check_niimg_4d(img)
        print("[Confounds Extraction] high ariance confounds computation]")
        high_variance = high_variance_confounds(img, mask_img=mask_img,
                                                n_confounds=n_confounds)
        if compute_not_mask and get_randomized_svd:
            signals = masking.apply_mask(img, mask_img)
            non_constant = np.any(np.diff(signals, axis=0) != 0, axis=0)
            signals = signals[:, non_constant]
            signals = signal.clean(signals, detrend=True)
            print("[Confounds Extraction] Randomized SVD computation")
            U, s, V = randomized_svd(signals, n_components=n_confounds,
                                     random_state=0)
            if high_variance is not None:
                confound_ = np.hstack((U, high_variance))
            else:
                confound_ = U
        else:
            confound_ = high_variance
        confounds.append(confound_)

    return confounds
Exemple #11
0
def test_coregister():
    anat_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    func_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'func.nii.gz')
    mean_func_file = os.path.join(tst.tmpdir, 'mean_func.nii.gz')
    mean_img(func_file).to_filename(mean_func_file)

    bunch = func.coregister(anat_file,
                            mean_func_file,
                            tst.tmpdir,
                            slice_timing=False,
                            verbose=False,
                            reorient_only=True)
    assert_true(
        _check_same_fov(nibabel.load(bunch.coreg_func_),
                        nibabel.load(bunch.coreg_anat_)))
    assert_true(_check_same_obliquity(bunch.coreg_anat_, bunch.coreg_func_))
    assert_true(os.path.isfile(bunch.coreg_transform_))
    assert_less(0, len(bunch.coreg_warps_))
    assert_true(bunch.coreg_warps_[-1] is None)  # Last slice in functional
    # is without signal
    for warp_file in bunch.coreg_warps_[:-1]:
        assert_true(os.path.isfile(warp_file))

    # Check environement variables setting
    assert_raises_regex(RuntimeError,
                        "3dcopy",
                        func.coregister,
                        anat_file,
                        mean_func_file,
                        tst.tmpdir,
                        slice_timing=False,
                        verbose=False,
                        reorient_only=True,
                        AFNI_DECONFLICT='NO')

    # Check caching does not change the paths
    bunch2 = func.coregister(anat_file,
                             mean_func_file,
                             tst.tmpdir,
                             slice_timing=False,
                             verbose=False,
                             caching=True,
                             reorient_only=True,
                             AFNI_DECONFLICT='OVERWRITE')
    assert_equal(bunch.coreg_func_, bunch2.coreg_func_)
    assert_equal(bunch.coreg_anat_, bunch2.coreg_anat_)
    assert_equal(bunch.coreg_transform_, bunch2.coreg_transform_)
    for warp_file, warp_file2 in zip(bunch.coreg_warps_, bunch2.coreg_warps_):
        assert_equal(warp_file, warp_file2)
def extract_confounds(imgs, mask_img, n_confounds=10):
    """To extract confounds on list of subjects

    See nilearn.image.high_variance_confounds for technical details.

    Parameters
    ----------
    imgs : list of Nifti images, either str or nibabel.Nifti1Image
        Functional images on which confounds should be extracted

    mask_img : str or nibabel.Nifti1Image
        Mask image with binary values. This image is imposed on
        each functional image for confounds extraction..

    n_confounds : int, optional
        By default, 10 high variance confounds are extracted. Otherwise,
        confounds as specified are extracted.

    Returns
    -------
    confounds : list of Numpy arrays.
        Each numpy array is a confound corresponding to imgs provided.
        Each numpy array will have shape (n_timepoints, n_confounds)        
    """
    confounds = []
    if not isinstance(imgs, collections.Iterable) or \
            isinstance(imgs, _basestring):
        imgs = [imgs, ]

    img = _utils.check_niimg_4d(imgs[0])
    shape = img.shape[:3]
    affine = img.affine

    if isinstance(mask_img, _basestring):
        mask_img = _utils.check_niimg_3d(mask_img)

    if not _check_same_fov(img, mask_img):
        mask_img = resample_img(
            mask_img, target_shape=shape, target_affine=affine,
            interpolation='nearest')

    for img in imgs:
        print("[Confounds Extraction] Image selected {0}".format(img))
        img = _utils.check_niimg_4d(img)
        print("Extracting high variance confounds")
        high_variance = high_variance_confounds(img, mask_img=mask_img,
                                                n_confounds=n_confounds)
        confounds.append(high_variance)
    return confounds
Exemple #13
0
def test_warp():
    anat_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    func_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'func.nii.gz')
    func_file0 = os.path.join(tst.tmpdir, 'mean_func.nii.gz')
    func_img0 = index_img(func_file, 0)
    func_img0.to_filename(func_file0)

    registered_anat_oblique_file, mat_file =\
        base._warp(anat_file, func_file0, write_dir=tst.tmpdir,
                   caching=False, verbose=False)
    assert_true(
        _check_same_fov(nibabel.load(registered_anat_oblique_file), func_img0))
    assert_true(os.path.isfile(mat_file))
Exemple #14
0
def test_coregister_fmri_session():
    anat_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    func_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'func.nii.gz')

    animal_session = FMRISession(anat=anat_file,
                                 func=func_file,
                                 animal_id='test_coreg_dir')

    func.coregister_fmri_session(animal_session,
                                 1.,
                                 tst.tmpdir,
                                 400,
                                 slice_timing=False,
                                 verbose=False,
                                 use_rats_tool=False)
    assert_true(
        _check_same_fov(nibabel.load(animal_session.coreg_func_),
                        nibabel.load(animal_session.coreg_anat_)))
    assert_true(
        _check_same_obliquity(animal_session.coreg_anat_,
                              animal_session.coreg_func_))
    assert_true(os.path.isfile(animal_session.coreg_transform_))
    assert_equal(os.path.join(tst.tmpdir, 'test_coreg_dir'),
                 animal_session.output_dir_)

    # Check environement variables setting
    current_dir = os.getcwd()  # coregister_fmri_session changes the directory
    assert_raises_regex(RuntimeError,
                        "already exists",
                        func.coregister_fmri_session,
                        animal_session,
                        1.,
                        tst.tmpdir,
                        400,
                        slice_timing=False,
                        use_rats_tool=False,
                        AFNI_DECONFLICT='NO')
    os.chdir(current_dir)
Exemple #15
0
    def _preprocess_input(self, dataset):
        """Preprocess inputs to the Estimator from the Dataset as needed."""
        masker = self.masker or dataset.masker

        mask_img = masker.mask_img or masker.labels_img
        if isinstance(mask_img, str):
            mask_img = nb.load(mask_img)

        # Ensure that protected values are not included among _required_inputs
        assert "aggressive_mask" not in self._required_inputs.keys(
        ), "This is a protected name."

        # A dictionary to collect masked image data, to be further reduced by the aggressive mask.
        temp_image_inputs = {}

        for name, (type_, _) in self._required_inputs.items():
            if type_ == "image":
                # If no resampling is requested, check if resampling is required
                if not self.resample:
                    check_imgs = {
                        img: nb.load(img)
                        for img in self.inputs_[name]
                    }
                    _check_same_fov(**check_imgs,
                                    reference_masker=mask_img,
                                    raise_error=True)
                    imgs = list(check_imgs.values())
                else:
                    # resampling will only occur if shape/affines are different
                    # making this harmless if all img shapes/affines are the same as the reference
                    imgs = [
                        resample_to_img(nb.load(img), mask_img,
                                        **self._resample_kwargs)
                        for img in self.inputs_[name]
                    ]

                # input to NiFtiLabelsMasker must be 4d
                img4d = concat_imgs(imgs, ensure_ndim=4)

                # Mask required input images using either the dataset's mask or the estimator's.
                temp_arr = masker.transform(img4d)

                # An intermediate step to mask out bad voxels.
                # Can be dropped once PyMARE is able to handle masked arrays or missing data.
                nonzero_voxels_bool = np.all(temp_arr != 0, axis=0)
                nonnan_voxels_bool = np.all(~np.isnan(temp_arr), axis=0)
                good_voxels_bool = np.logical_and(nonzero_voxels_bool,
                                                  nonnan_voxels_bool)

                data = masker.transform(img4d)

                temp_image_inputs[name] = data
                if "aggressive_mask" not in self.inputs_.keys():
                    self.inputs_["aggressive_mask"] = good_voxels_bool
                else:
                    # Remove any voxels that are bad in any image-based inputs
                    self.inputs_["aggressive_mask"] = np.logical_or(
                        self.inputs_["aggressive_mask"],
                        good_voxels_bool,
                    )

            elif type_ == "coordinates":
                # Try to load existing MA maps
                if hasattr(self, "kernel_transformer"):
                    self.kernel_transformer._infer_names(
                        affine=md5(mask_img.affine).hexdigest())
                    if self.kernel_transformer.image_type in dataset.images.columns:
                        files = dataset.get_images(
                            ids=self.inputs_["id"],
                            imtype=self.kernel_transformer.image_type,
                        )
                        if all(f is not None for f in files):
                            self.inputs_["ma_maps"] = files

                # Calculate IJK matrix indices for target mask
                # Mask space is assumed to be the same as the Dataset's space
                # These indices are used directly by any KernelTransformer
                xyz = self.inputs_["coordinates"][["x", "y", "z"]].values
                ijk = mm2vox(xyz, mask_img.affine)
                self.inputs_["coordinates"][["i", "j", "k"]] = ijk

        # Further reduce image-based inputs to remove "bad" voxels
        # (voxels with zeros or NaNs in any studies)
        if "aggressive_mask" in self.inputs_.keys():
            n_bad_voxels = (self.inputs_["aggressive_mask"].size -
                            self.inputs_["aggressive_mask"].sum())
            if n_bad_voxels:
                LGR.warning(
                    f"Masking out {n_bad_voxels} additional voxels. "
                    "The updated masker is available in the Estimator.masker attribute."
                )
        for name, raw_masked_data in temp_image_inputs.items():
            self.inputs_[name] = raw_masked_data[:, self.
                                                 inputs_["aggressive_mask"]]
def cluster_stats(stat_img,
                  mask_img,
                  threshold,
                  height_control='fpr',
                  cluster_th=0,
                  nulls=None):
    """
    Return a list of clusters, each cluster being represented by a
    dictionary. Clusters are sorted by descending size order. Within
    each cluster, local maxima are sorted by descending statical value

    Parameters
    ----------
    stat_img: Niimg-like object,
       statsitical image (presumably in z scale)
    mask_img: Niimg-like object,
        mask image
    threshold: float,
        cluster forming threshold (either a p-value or z-scale value)
    height_control: string
        false positive control meaning of cluster forming
        threshold: 'fpr'|'fdr'|'bonferroni'|'none'
    cluster_th: int or float,
        cluster size threshold
    nulls: dictionary,
        statistics of the null distribution

    Notes
    -----
    If there is no cluster, an empty list is returned
    """
    if nulls is None: nulls = {}

    # Masking
    mask_img, stat_img = check_niimg(mask_img), check_niimg(stat_img)
    if not _check_same_fov(mask_img, stat_img):
        raise ValueError('mask_img and stat_img do not have the same fov')
    mask = mask_img.get_data().astype(np.bool)
    affine = mask_img.get_affine()
    stat_map = stat_img.get_data() * mask
    n_voxels = mask.sum()

    # Thresholding
    if height_control == 'fpr':
        z_th = norm.isf(threshold)
    elif height_control == 'fdr':
        z_th = fdr_threshold(stat_map[mask], threshold)
    elif height_control == 'bonferroni':
        z_th = norm.isf(threshold / n_voxels)
    else:  # Brute-force thresholding
        z_th = threshold

    p_th = norm.sf(z_th)
    # General info
    info = {
        'n_voxels': n_voxels,
        'threshold_z': z_th,
        'threshold_p': p_th,
        'threshold_pcorr': np.minimum(1, p_th * n_voxels)
    }

    above_th = stat_map > z_th
    above_values = stat_map * above_th
    if (above_th == 0).all():
        return [], info

    # Extract connected components above threshold
    labels, n_labels = label(above_th)

    # Extract the local maxima anove the threshold
    maxima_mask = (above_values == np.maximum(z_th,
                                              maximum_filter(above_values, 3)))
    x, y, z = np.array(np.where(maxima_mask))
    maxima_coords = np.array(coord_transform(x, y, z, affine)).T
    maxima_labels = labels[maxima_mask]
    maxima_values = above_values[maxima_mask]

    # FDR-corrected p-values
    max_fdr_p_values = fdr_p_values(stat_map[mask])[maxima_mask[mask]]

    # Default "nulls"
    if not 'zmax' in nulls:
        nulls['zmax'] = 'bonferroni'
    if not 'smax' in nulls:
        nulls['smax'] = None
    if not 's' in nulls:
        nulls['s'] = None

    # Make list of clusters, each cluster being a dictionary
    clusters = []
    for k in range(n_labels):
        cluster_size = np.sum(labels == k + 1)
        if cluster_size >= cluster_th:

            # get the position of the maxima that belong to that cluster
            in_cluster = maxima_labels == k + 1

            # sort the maxima by decreasing statistical value
            max_vals = maxima_values[in_cluster]
            sorted_ = max_vals.argsort()[::-1]

            # Report significance levels in each cluster
            z_score = max_vals[sorted_]
            p_values = norm.sf(z_score)

            # Voxel-level corrected p-values
            fwer_p_value = None
            if nulls['zmax'] == 'bonferroni':
                fwer_p_value = np.minimum(1, p_values * n_voxels)
            elif isinstance(nulls['zmax'], np.ndarray):
                fwer_p_value = empirical_p_value(clusters['z_score'],
                                                 nulls['zmax'])

            # Cluster-level p-values (corrected)
            cluster_fwer_p_value = None
            if isinstance(nulls['smax'], np.ndarray):
                cluster_fwer_p_value = empirical_p_value(
                    cluster_size, nulls['smax'])

            # Cluster-level p-values (uncorrected)
            cluster_p_value = None
            if isinstance(nulls['s'], np.ndarray):
                cluster_p_value = empirical_p_value(cluster_size, nulls['s'])

            # write all this into the cluster structure
            clusters.append({
                'size':
                cluster_size,
                'maxima':
                maxima_coords[in_cluster][sorted_],
                'z_score':
                z_score,
                'fdr_p_value':
                max_fdr_p_values[in_cluster][sorted_],
                'p_value':
                p_values,
                'fwer_p_value':
                fwer_p_value,
                'cluster_fwer_p_value':
                cluster_fwer_p_value,
                'cluster_p_value':
                cluster_p_value
            })

    # Sort clusters by descending size order
    order = np.argsort(-np.array([cluster['size'] for cluster in clusters]))
    clusters = [clusters[i] for i in order]

    return clusters, info
# -------------------------------------------------

collection_terms = {'id': 503}
image_terms = {'not_mni': False}
emotion_data = fetch_neurovault(max_images=None,
                                image_terms=image_terms,
                                collection_terms=collection_terms)
n_images = len(emotion_data.images)

input_images = []
y = []
groups = []
ref_img = load_img(emotion_data.images[0])
for index in range(n_images):
    img = emotion_data.images[index]
    if not _check_same_fov(ref_img, load_img(img)):
        img = resample_to_img(source_img=img, target_img=ref_img)
    input_images.append(img)
    target = emotion_data.images_meta[index]['Rating']
    subject_id = emotion_data.images_meta[index]['SubjectID']
    y.append(target)
    groups.append(subject_id)
y = np.ravel(y)
groups = np.ravel(groups)
######################################################################
# Grid search 'alpha' for prediction
# ---------------------------------

X_sc = StandardScaler()
# RidgeCV
ridge = RidgeCV(alphas=np.logspace(-3., 3., 10))
Exemple #18
0
def test_ants_n4():
    in_file = os.path.join(os.path.dirname(testing_data.__file__),
                           'func.nii.gz')
    unbiased_file = bias_correction.ants_n4(in_file, write_dir=tst.tmpdir)
    assert_true(
        _check_same_fov(nibabel.load(unbiased_file), nibabel.load(in_file)))
Exemple #19
0
def test_coregistrator():
    anat_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'anat.nii.gz')
    func_file = os.path.join(os.path.dirname(testing_data.__file__),
                             'func.nii.gz')

    registrator = Coregistrator(output_dir=tst.tmpdir,
                                use_rats_tool=False,
                                verbose=False)
    assert_raises_regex(ValueError, 'has not been anat fitted. ',
                        registrator.fit_modality, func_file, 'func')

    registrator.fit_anat(anat_file)
    assert_equal(registrator.anat_, anat_file)
    assert_true(registrator._anat_brain_mask is None)

    assert_raises_regex(ValueError, "Only 'func' and 'perf' ",
                        registrator.fit_modality, func_file, 'diffusion')
    assert_raises_regex(ValueError, "'t_r' is needed for slice ",
                        registrator.fit_modality, func_file, 'func')
    assert_raises_regex(ValueError,
                        '`brain_volume` must be ',
                        registrator.fit_modality,
                        func_file,
                        'func',
                        slice_timing=False,
                        prior_rigid_body_registration=True)

    # without rigid body registration
    registrator.fit_modality(func_file, 'func', slice_timing=False)
    func_img = nibabel.load(func_file)
    assert_true(
        _check_same_fov(nibabel.load(registrator.undistorted_func_), func_img))
    np.testing.assert_array_almost_equal(
        nibabel.load(registrator.anat_in_func_space_).affine, func_img.affine)
    np.testing.assert_array_equal(
        nibabel.load(registrator.anat_in_func_space_).shape,
        func_img.shape[:-1])

    # test transform_modality_like on an image with oriented as the functional
    func_like_img = nibabel.Nifti1Image(np.zeros(func_img.shape[:-1]),
                                        func_img.affine)
    func_like_file = os.path.join(tst.tmpdir, 'func_like.nii.gz')
    func_like_img.to_filename(func_like_file)
    transformed_file = registrator.transform_modality_like(
        func_like_file, 'func')
    transformed_img = nibabel.load(transformed_file)
    np.testing.assert_array_almost_equal(transformed_img.affine,
                                         func_img.affine)
    np.testing.assert_array_equal(transformed_img.shape, func_img.shape[:-1])

    # Similarly with rigid body registration
    registrator = Coregistrator(output_dir=tst.tmpdir,
                                use_rats_tool=False,
                                verbose=False,
                                brain_volume=400)
    registrator.fit_anat(anat_file)

    # Provide manual brain mask
    mean_func_file = os.path.join(tst.tmpdir, 'mean_func.nii.gz')
    image.mean_img(func_img).to_filename(mean_func_file)
    func_brain_mask = compute_histo_brain_mask(mean_func_file,
                                               400,
                                               tst.tmpdir,
                                               opening=2)

    registrator.fit_modality(func_file,
                             'func',
                             slice_timing=False,
                             prior_rigid_body_registration=True,
                             brain_mask_file=func_brain_mask)
    assert_true(
        _check_same_fov(nibabel.load(registrator.undistorted_func_), func_img))
    np.testing.assert_array_almost_equal(
        nibabel.load(registrator.anat_in_func_space_).affine, func_img.affine)
    np.testing.assert_array_equal(
        nibabel.load(registrator.anat_in_func_space_).shape,
        func_img.shape[:-1])

    func_like_img = nibabel.Nifti1Image(np.zeros(func_img.shape[:-1]),
                                        func_img.affine)
    func_like_file = os.path.join(tst.tmpdir, 'func_like.nii.gz')
    func_like_img.to_filename(func_like_file)
    transformed_file = registrator.transform_modality_like(
        func_like_file, 'func')
    transformed_img = nibabel.load(transformed_file)
    np.testing.assert_array_almost_equal(transformed_img.affine,
                                         func_img.affine)
    np.testing.assert_array_equal(transformed_img.shape, func_img.shape[:-1])

    # Similarly with perf
    m0_img = nibabel.Nifti1Image(func_img.get_data()[..., 0], func_img.affine)
    m0_file = os.path.join(tst.tmpdir, 'm0.nii.gz')
    m0_img.to_filename(m0_file)
    registrator.fit_modality(m0_file, 'perf')
    assert_true(
        _check_same_fov(nibabel.load(registrator.undistorted_perf_), m0_img))
    assert_true(
        _check_same_fov(nibabel.load(registrator.anat_in_perf_space_), m0_img))

    m0_like_img = nibabel.Nifti1Image(np.zeros(m0_img.shape), m0_img.affine)
    m0_like_file = os.path.join(tst.tmpdir, 'm0_like.nii.gz')
    m0_like_img.to_filename(m0_like_file)
    transformed_file = registrator.transform_modality_like(
        m0_like_file, 'perf')
    transformed_img = nibabel.load(transformed_file)
    assert_true(_check_same_fov(transformed_img, m0_img))
Exemple #20
0
def _make_parcellation(imgs,
                       clustering_index,
                       clustering,
                       n_pieces,
                       masker,
                       smoothing_fwhm=5,
                       verbose=0):
    """Convenience function to use nilearn Parcellation class in our pipeline.
    It is used to find local regions of the brain in which alignment will be later applied.
    For alignment computational efficiency, regions should be of hundreds of voxels.

    Parameters
    ----------
    imgs: Niimgs
        data to cluster
    clustering_index: list of integers
        Clustering is performed on a subset of the data chosen randomly
        in timeframes. This index carries this subset.
    clustering: string or 3D Niimg
        In : {'kmeans', 'ward', 'rena'}, passed to nilearn Parcellations class.
        If you aim for speed, choose k-means (and check kmeans_smoothing_fwhm parameter)
        If you want spatially connected and/or reproducible regions use 'ward'
        If you want balanced clusters (especially from timeseries) used 'hierarchical_kmeans'
        For 'rena', need nilearn > 0.5.2
        If 3D Niimg, image used as predefined clustering, n_pieces is ignored
    n_pieces: int
        number of different labels
    masker: instance of NiftiMasker or MultiNiftiMasker
        Masker to be used on the data. For more information see:
        http://nilearn.github.io/manipulating_images/masker_objects.html
    smoothing_fwhm: None or int
        By default 5mm smoothing will be applied before kmeans clustering to have
        more compact clusters (but this will not change the data later).
        To disable this option, this parameter should be None.

    Returns
    -------
    labels : list of ints (len n_features)
        Parcellation of features in clusters
    """
    # check if clustering is provided
    if type(clustering) == nib.nifti1.Nifti1Image or os.path.isfile(
            clustering):
        _check_same_fov(masker.mask_img_, clustering)
        labels = _apply_mask_fmri(clustering, masker.mask_img_).astype(int)

    # otherwise check it's needed, if not return 1 everywhere
    elif n_pieces == 1:
        labels = np.ones(int(masker.mask_img_.get_fdata().sum()),
                         dtype=np.int8)
    # otherwise check requested clustering method
    elif clustering == "hierarchical_kmeans" and n_pieces > 1:
        imgs_subset = index_img(imgs, clustering_index)
        if smoothing_fwhm is not None:
            X = masker.transform(smooth_img(imgs_subset, smoothing_fwhm))
        else:
            X = masker.transform(imgs_subset)
        labels = _hierarchical_k_means(
            X.T, n_clusters=n_pieces, verbose=verbose) + 1

    elif clustering in ['kmeans', 'ward', 'rena'] and n_pieces > 1:
        imgs_subset = index_img(imgs, clustering_index)
        if clustering == "kmeans" and smoothing_fwhm is not None:
            images_to_parcel = smooth_img(imgs_subset, smoothing_fwhm)
        else:
            images_to_parcel = imgs_subset
        try:
            parcellation = Parcellations(method=clustering,
                                         n_parcels=n_pieces,
                                         mask=masker,
                                         scaling=False,
                                         n_iter=20,
                                         verbose=verbose)
        except TypeError:
            if clustering == "rena" and (version.parse(nilearn.__version__) <=
                                         version.parse("0.5.2")):
                raise InputError((
                    'ReNA algorithm is only available in Nilearn version > 0.5.2. \
                     Your version is {}. If you want to use ReNA, please run "pip install nilearn --upgrade"'
                    .format(nilearn.__version__)))
            else:
                parcellation = Parcellations(method=clustering,
                                             n_parcels=n_pieces,
                                             mask=masker,
                                             verbose=verbose)
        parcellation.fit(images_to_parcel)
        labels = _apply_mask_fmri(parcellation.labels_img_,
                                  masker.mask_img_).astype(int)

    else:
        raise InputError((
            'Clustering should be "kmeans", "ward", "rena", "hierarchical_kmeans", \
             or a 3D Niimg, and n_pieces should be an integer ≥ 1'))

    if verbose > 0:
        unique_labels, counts = np.unique(labels, return_counts=True)
        print("The alignment will be applied on parcels of sizes {}".format(
            counts))

    # raise warning if some parcels are bigger than 1000 voxels
    _check_labels(labels)

    return labels
Exemple #21
0
    def _preprocess_input(self, dataset):
        """Preprocess inputs to the Estimator from the Dataset as needed."""
        masker = self.masker or dataset.masker

        mask_img = masker.mask_img or masker.labels_img
        if isinstance(mask_img, str):
            mask_img = nib.load(mask_img)

        # Ensure that protected values are not included among _required_inputs
        assert "aggressive_mask" not in self._required_inputs.keys(
        ), "This is a protected name."

        if "aggressive_mask" in self.inputs_.keys():
            LGR.warning("Removing existing 'aggressive_mask' from Estimator.")
            self.inputs_.pop("aggressive_mask")

        # A dictionary to collect masked image data, to be further reduced by the aggressive mask.
        temp_image_inputs = {}

        for name, (type_, _) in self._required_inputs.items():
            if type_ == "image":
                # If no resampling is requested, check if resampling is required
                if not self.resample:
                    check_imgs = {
                        img: nib.load(img)
                        for img in self.inputs_[name]
                    }
                    _check_same_fov(**check_imgs,
                                    reference_masker=mask_img,
                                    raise_error=True)
                    imgs = list(check_imgs.values())
                else:
                    # resampling will only occur if shape/affines are different
                    # making this harmless if all img shapes/affines are the same as the reference
                    imgs = [
                        resample_to_img(nib.load(img), mask_img,
                                        **self._resample_kwargs)
                        for img in self.inputs_[name]
                    ]

                # input to NiFtiLabelsMasker must be 4d
                img4d = concat_imgs(imgs, ensure_ndim=4)

                # Mask required input images using either the dataset's mask or the estimator's.
                temp_arr = masker.transform(img4d)

                # An intermediate step to mask out bad voxels.
                # Can be dropped once PyMARE is able to handle masked arrays or missing data.
                nonzero_voxels_bool = np.all(temp_arr != 0, axis=0)
                nonnan_voxels_bool = np.all(~np.isnan(temp_arr), axis=0)
                good_voxels_bool = np.logical_and(nonzero_voxels_bool,
                                                  nonnan_voxels_bool)

                data = masker.transform(img4d)

                temp_image_inputs[name] = data
                if "aggressive_mask" not in self.inputs_.keys():
                    self.inputs_["aggressive_mask"] = good_voxels_bool
                else:
                    # Remove any voxels that are bad in any image-based inputs
                    self.inputs_["aggressive_mask"] = np.logical_or(
                        self.inputs_["aggressive_mask"],
                        good_voxels_bool,
                    )

        # Further reduce image-based inputs to remove "bad" voxels
        # (voxels with zeros or NaNs in any studies)
        if "aggressive_mask" in self.inputs_.keys():
            n_bad_voxels = (self.inputs_["aggressive_mask"].size -
                            self.inputs_["aggressive_mask"].sum())
            if n_bad_voxels:
                LGR.warning(
                    f"Masking out {n_bad_voxels} additional voxels. "
                    "The updated masker is available in the Estimator.masker attribute."
                )

            for name, raw_masked_data in temp_image_inputs.items():
                self.inputs_[
                    name] = raw_masked_data[:, self.inputs_["aggressive_mask"]]
def cluster_stats(stat_img, mask_img, threshold, height_control='fpr',
                  cluster_th=0, nulls=None):
    """
    Return a list of clusters, each cluster being represented by a
    dictionary. Clusters are sorted by descending size order. Within
    each cluster, local maxima are sorted by descending statical value

    Parameters
    ----------
    stat_img: Niimg-like object,
       statsitical image (presumably in z scale)
    mask_img: Niimg-like object,
        mask image
    threshold: float,
        cluster forming threshold (either a p-value or z-scale value)
    height_control: string
        false positive control meaning of cluster forming
        threshold: 'fpr'|'fdr'|'bonferroni'|'none'
    cluster_th: int or float,
        cluster size threshold
    nulls: dictionary,
        statistics of the null distribution

    Notes
    -----
    If there is no cluster, an empty list is returned
    """
    if nulls is None: nulls = {}

    # Masking
    mask_img, stat_img = check_niimg(mask_img), check_niimg(stat_img)
    if not _check_same_fov(mask_img, stat_img):
        raise ValueError('mask_img and stat_img do not have the same fov')
    mask = mask_img.get_data().astype(np.bool)
    affine = mask_img.get_affine()
    stat_map = stat_img.get_data() * mask
    n_voxels = mask.sum()

    # Thresholding
    if height_control == 'fpr':
        z_th = norm.isf(threshold)
    elif height_control == 'fdr':
        z_th = fdr_threshold(stat_map[mask], threshold)
    elif height_control == 'bonferroni':
        z_th = norm.isf(threshold / n_voxels)
    else:  # Brute-force thresholding
        z_th = threshold

    p_th = norm.sf(z_th)
    # General info
    info = {'n_voxels': n_voxels,
            'threshold_z': z_th,
            'threshold_p': p_th,
            'threshold_pcorr': np.minimum(1, p_th * n_voxels)}

    above_th = stat_map > z_th
    above_values = stat_map * above_th
    if (above_th == 0).all():
        return [], info

    # Extract connected components above threshold
    labels, n_labels = label(above_th)

    # Extract the local maxima anove the threshold
    maxima_mask = (above_values ==
                   np.maximum(z_th, maximum_filter(above_values, 3)))
    x, y, z = np.array(np.where(maxima_mask))
    maxima_coords = np.array(coord_transform(x, y, z, affine)).T
    maxima_labels = labels[maxima_mask]
    maxima_values = above_values[maxima_mask]

    # FDR-corrected p-values
    max_fdr_p_values = fdr_p_values(stat_map[mask])[maxima_mask[mask]]

    # Default "nulls"
    if not 'zmax' in nulls:
        nulls['zmax'] = 'bonferroni'
    if not 'smax' in nulls:
        nulls['smax'] = None
    if not 's' in nulls:
        nulls['s'] = None

    # Make list of clusters, each cluster being a dictionary
    clusters = []
    for k in range(n_labels):
        cluster_size = np.sum(labels == k + 1)
        if cluster_size >= cluster_th:

            # get the position of the maxima that belong to that cluster
            in_cluster = maxima_labels == k + 1

            # sort the maxima by decreasing statistical value
            max_vals = maxima_values[in_cluster]
            sorted_ = max_vals.argsort()[::-1]

            # Report significance levels in each cluster
            z_score = max_vals[sorted_]
            p_values = norm.sf(z_score)

            # Voxel-level corrected p-values
            fwer_p_value = None
            if nulls['zmax'] == 'bonferroni':
                fwer_p_value = np.minimum(1, p_values * n_voxels)
            elif isinstance(nulls['zmax'], np.ndarray):
                fwer_p_value = empirical_p_value(
                    clusters['z_score'], nulls['zmax'])

            # Cluster-level p-values (corrected)
            cluster_fwer_p_value = None
            if isinstance(nulls['smax'], np.ndarray):
                cluster_fwer_p_value = empirical_p_value(
                    cluster_size, nulls['smax'])

            # Cluster-level p-values (uncorrected)
            cluster_p_value = None
            if isinstance(nulls['s'], np.ndarray):
                cluster_p_value = empirical_p_value(
                    cluster_size, nulls['s'])

            # write all this into the cluster structure
            clusters.append({
                    'size': cluster_size,
                    'maxima': maxima_coords[in_cluster][sorted_],
                    'z_score': z_score,
                    'fdr_p_value': max_fdr_p_values[in_cluster][sorted_],
                    'p_value': p_values,
                    'fwer_p_value': fwer_p_value,
                    'cluster_fwer_p_value': cluster_fwer_p_value,
                    'cluster_p_value': cluster_p_value
                    })

    # Sort clusters by descending size order
    order = np.argsort(- np.array([cluster['size'] for cluster in clusters]))
    clusters = [clusters[i] for i in order]

    return clusters, info
Exemple #23
0
def filter_and_mask(imgs, mask_img_,
                    parameters,
                    memory_level=0,
                    memory=Memory(cachedir=None),
                    verbose=0,
                    confounds=None,
                    copy=True,
                    sample_mask=None):
    # If we have a string (filename), we won't need to copy, as
    # there will be no side effect

    if isinstance(imgs, _basestring):
        copy = False

    if verbose > 0:
        class_name = enclosing_scope_name(stack_level=2)

    mask_img_ = _utils.check_niimg_3d(mask_img_)

    imgs = _utils.check_niimg(imgs, atleast_4d=True)
    if sample_mask is not None:
        imgs = image.index_img(imgs, sample_mask)

    # Resampling: allows the user to change the affine, the shape or both
    if verbose > 1:
        print("[%s] Resampling" % class_name)

    # Check whether resampling is truly necessary. If so, crop mask
    # as small as possible in order to speed up the process
    if not _check_same_fov(imgs, mask_img_):
        # now we can crop
        mask_img_ = image.crop_img(mask_img_, copy=False)

        imgs = cache(image.resample_img, memory, func_memory_level=2,
                     memory_level=memory_level, ignore=['copy'])(
                        imgs,
                        target_affine=mask_img_.get_affine(),
                        target_shape=mask_img_.shape,
                        copy=copy)

    # Load data (if filenames are given, load them)
    if verbose > 0:
        print("[%s] Loading data from %s" % (
            class_name,
            _utils._repr_niimgs(imgs)[:200]))

    # Get series from data with optional smoothing
    if verbose > 1:
        print("[%s] Masking and smoothing" % class_name)
    data = masking.apply_mask(imgs, mask_img_,
                              smoothing_fwhm=parameters['smoothing_fwhm'])

    # Temporal
    # ========
    # Detrending (optional)
    # Filtering
    # Confounds removing (from csv file or numpy array)
    # Normalizing

    if verbose > 1:
        print("[%s] Cleaning signal" % class_name)
    if not 'sessions' in parameters or parameters['sessions'] is None:
        clean_memory_level = 2
        if (parameters['high_pass'] is not None
                and parameters['low_pass'] is not None):
            clean_memory_level = 4

        data = cache(signal.clean, memory,
                     func_memory_level=clean_memory_level,
                     memory_level=memory_level)(
                        data,
                        confounds=confounds, low_pass=parameters['low_pass'],
                        high_pass=parameters['high_pass'],
                        t_r=parameters['t_r'],
                        detrend=parameters['detrend'],
                        standardize=parameters['standardize'])
    else:
        sessions = parameters['sessions']
        if not len(sessions) == len(data):
            raise ValueError(('The length of the session vector (%i) '
                              'does not match the length of the data (%i)')
                              % (len(sessions), len(data)))
        for s in np.unique(sessions):
            if confounds is not None:
                confounds = confounds[sessions == s]
            data[sessions == s, :] = \
                cache(signal.clean, memory, func_memory_level=2,
                      memory_level=memory_level)(
                        data[sessions == s, :],
                        confounds=confounds,
                        low_pass=parameters['low_pass'],
                        high_pass=parameters['high_pass'],
                        t_r=parameters['t_r'],
                        detrend=parameters['detrend'],
                        standardize=parameters['standardize']
                )

    # For _later_: missing value removal or imputing of missing data
    # (i.e. we want to get rid of NaNs, if smoothing must be done
    # earlier)
    # Optionally: 'doctor_nan', remove voxels with NaNs, other option
    # for later: some form of imputation

    return data, imgs.get_affine()
Exemple #24
0
def filter_and_mask(imgs, mask_img_,
                    parameters,
                    memory_level=0,
                    memory=Memory(cachedir=None),
                    verbose=0,
                    confounds=None,
                    copy=True,
                    sample_mask=None):
    # If we have a string (filename), we won't need to copy, as
    # there will be no side effect

    if isinstance(imgs, _basestring):
        copy = False

    if verbose > 0:
        class_name = enclosing_scope_name(stack_level=2)

    mask_img_ = _utils.check_niimg_3d(mask_img_)

    imgs = _utils.check_niimg(imgs, atleast_4d=True, ensure_ndim=4)
    if sample_mask is not None:
        imgs = image.index_img(imgs, sample_mask)

    # Resampling: allows the user to change the affine, the shape or both
    if verbose > 1:
        print("[%s] Resampling" % class_name)

    # Check whether resampling is truly necessary. If so, crop mask
    # as small as possible in order to speed up the process
    if not _check_same_fov(imgs, mask_img_):
        # now we can crop
        mask_img_ = image.crop_img(mask_img_, copy=False)

        imgs = cache(image.resample_img, memory, func_memory_level=2,
                     memory_level=memory_level, ignore=['copy'])(
                        imgs,
                        target_affine=mask_img_.get_affine(),
                        target_shape=mask_img_.shape,
                        copy=copy)

    # Load data (if filenames are given, load them)
    if verbose > 0:
        print("[%s] Loading data from %s" % (
            class_name,
            _utils._repr_niimgs(imgs)[:200]))

    # Get series from data with optional smoothing
    if verbose > 1:
        print("[%s] Masking and smoothing" % class_name)
    data = masking.apply_mask(imgs, mask_img_,
                              smoothing_fwhm=parameters['smoothing_fwhm'])

    # Temporal
    # ========
    # Detrending (optional)
    # Filtering
    # Confounds removing (from csv file or numpy array)
    # Normalizing

    if verbose > 1:
        print("[%s] Cleaning signal" % class_name)
    if 'sessions' not in parameters or parameters['sessions'] is None:
        clean_memory_level = 2
        if (parameters['high_pass'] is not None and
                parameters['low_pass'] is not None):
            clean_memory_level = 4

        data = cache(signal.clean, memory,
                     func_memory_level=clean_memory_level,
                     memory_level=memory_level)(
                        data,
                        confounds=confounds, low_pass=parameters['low_pass'],
                        high_pass=parameters['high_pass'],
                        t_r=parameters['t_r'],
                        detrend=parameters['detrend'],
                        standardize=parameters['standardize'])
    else:
        sessions = parameters['sessions']
        if not len(sessions) == len(data):
            raise ValueError(('The length of the session vector (%i) '
                              'does not match the length of the data (%i)')
                              % (len(sessions), len(data)))
        for s in np.unique(sessions):
            if confounds is not None:
                confounds = confounds[sessions == s]
            data[sessions == s, :] = \
                cache(signal.clean, memory, func_memory_level=2,
                      memory_level=memory_level)(
                        data[sessions == s, :],
                        confounds=confounds,
                        low_pass=parameters['low_pass'],
                        high_pass=parameters['high_pass'],
                        t_r=parameters['t_r'],
                        detrend=parameters['detrend'],
                        standardize=parameters['standardize']
            )

    # For _later_: missing value removal or imputing of missing data
    # (i.e. we want to get rid of NaNs, if smoothing must be done
    # earlier)
    # Optionally: 'doctor_nan', remove voxels with NaNs, other option
    # for later: some form of imputation

    return data, imgs.get_affine()