Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NF] migrate package load_confounds main function load_confounds #2946

Merged
merged 74 commits into from Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
7e6b887
[NF] migrate load_confounds base class
htwangtw Sep 7, 2021
7ccf22e
LINT PEP8
htwangtw Sep 7, 2021
63ea3a5
LINT force PEP8 to skip long URL
htwangtw Sep 7, 2021
cafb0da
LINT more PEP8
htwangtw Sep 7, 2021
82844fd
DOCS supported fMRIprep version specified
htwangtw Sep 7, 2021
775e188
ADD modified load_confounds demo
htwangtw Sep 7, 2021
20ea698
Apply suggestions from code review
htwangtw Sep 8, 2021
d3239ff
DOCS/FIX update load_confounds in docs and demo
htwangtw Sep 8, 2021
24d1db6
EHN more readable parameter names and migrate functions
htwangtw Sep 8, 2021
e199f40
TEST/DOC Test for scrubbing/sample mask
htwangtw Sep 8, 2021
a3a62d9
Apply suggestions from code review
htwangtw Sep 9, 2021
b57d1b0
Apply suggestions from code review
htwangtw Sep 9, 2021
0b14f32
DOCS improve formatting according to pydocstyle
htwangtw Sep 9, 2021
66ca69b
ENH simplify coompcor options
htwangtw Sep 9, 2021
7a300f8
[circle full] and some flake8 issues
htwangtw Sep 9, 2021
c1dac14
Typo
htwangtw Sep 9, 2021
df7ee6a
[circile full] FIX Title underline too short
htwangtw Sep 9, 2021
8d09b06
[circle full] ADD fmriprep dependency warning
htwangtw Sep 9, 2021
3a3447a
Proposal: DRY tests
NicolasGensollen Sep 10, 2021
c25e5f8
PEP8
htwangtw Sep 10, 2021
d165dd6
TEST Replace empty image file with temporary func
htwangtw Sep 10, 2021
92f1bc3
TEST add docstrings
htwangtw Sep 10, 2021
a23606f
TEST clean up path not replaced by tmp path
htwangtw Sep 11, 2021
50558a7
pep8
htwangtw Sep 11, 2021
f161aa6
ENH/TEST Remove PCA motion regressor option
htwangtw Sep 13, 2021
59ac369
Remove irrelevant comment
htwangtw Sep 13, 2021
03f3f54
[circle full] Update the demo with meaningful name
htwangtw Sep 13, 2021
29c5ba2
[circle full] pep8
htwangtw Sep 13, 2021
7380052
EHN update sample_mask application in maskers
htwangtw Sep 13, 2021
3fcffca
[circle full] RF load_confounds function replaces class Confounds
htwangtw Sep 14, 2021
4cb9070
[circle full] PEP8
htwangtw Sep 14, 2021
d3f0afd
[circle full] PEP8
htwangtw Sep 14, 2021
ab6e9c5
[circle full] DOCS/EHN correct module template and a few formatting d…
htwangtw Sep 14, 2021
e81394b
[circle full] ENH explicitly write the function inputs
htwangtw Sep 15, 2021
f8de52e
ENH migrate load_confounds to input_data
htwangtw Sep 16, 2021
77b3f55
DOCS update descriptions for user guilde
htwangtw Sep 16, 2021
4977716
Typos
htwangtw Sep 16, 2021
05e4049
PEP8
htwangtw Sep 16, 2021
f04de9a
[circle full]DOCS update function reference
htwangtw Sep 16, 2021
39f6432
[circle full] fix function reference in API ref
htwangtw Sep 16, 2021
2b2000e
DOCS remove non existance reference
htwangtw Sep 16, 2021
d51dc26
typo
htwangtw Sep 16, 2021
d59322a
rename the modules to relect the link with fmriprep
htwangtw Sep 16, 2021
fc48651
TEST change how simulated signal is generated
htwangtw Sep 16, 2021
8d1e6f2
Apply suggestions from code review
htwangtw Sep 17, 2021
41764b1
Apply suggestions from code review
htwangtw Sep 17, 2021
c36fb7f
Address some small comments on docs and format
htwangtw Sep 17, 2021
f1fe8d6
DOCS use BibTex for literatures
htwangtw Sep 17, 2021
23ae062
DOCS missing field journal
htwangtw Sep 17, 2021
7a95338
DOCS date --> year
htwangtw Sep 17, 2021
25bf9f5
DOCS Update example text
htwangtw Sep 17, 2021
1ab365b
TEST confounds extended in the same manner of test data
htwangtw Sep 17, 2021
94f8c43
BREAK test_nilearn_standardize broke by demean=False
htwangtw Sep 21, 2021
c040b2f
ENH/TEST demean option doc
htwangtw Sep 23, 2021
ba32963
Typos
htwangtw Sep 23, 2021
5321364
TEST FIX the missing parameter
htwangtw Sep 23, 2021
3392e30
Apply suggestions from code review
htwangtw Sep 24, 2021
93ac7b1
ENH demean default change back to True
htwangtw Sep 24, 2021
96c0717
LINT example
htwangtw Sep 24, 2021
1f5d9ea
TEST increase the degree of freedom in simulation
htwangtw Sep 24, 2021
0b463b3
TEST the option for standardize_confounds,detrend
htwangtw Sep 24, 2021
0347bfe
TEST remove standardize=False from test_nilearn_standardize
htwangtw Sep 27, 2021
bfec196
Update nilearn/input_data/fmriprep_confounds.py
htwangtw Sep 28, 2021
8787d97
TEST increase DoF and add randome seed to improve stability
htwangtw Sep 28, 2021
939ac4b
[circle full] Add what's new entry
htwangtw Sep 28, 2021
bbdf73f
[circle full] typo
htwangtw Sep 28, 2021
edb77f3
[circle full] fall back to random seed in test for version <3.7
htwangtw Sep 28, 2021
a8727bd
[circle full] typo in reference to NifitMasker
htwangtw Sep 28, 2021
764de48
[circle full] Update nilearn/input_data/fmriprep_confounds.py
htwangtw Sep 29, 2021
c1c8454
Apply suggestions from code review
htwangtw Oct 11, 2021
6c86349
[circle full] [ENH] expose full scrubbing segment length
htwangtw Oct 11, 2021
c24b0c9
[circle full] fix example to fit the new srub parameter
htwangtw Oct 11, 2021
461fae8
[circle full] default value is not useful in private function
htwangtw Oct 11, 2021
6ff1f1b
[circle full] fix scrubbing related tests; add doctring
htwangtw Oct 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions doc/modules/reference.rst
Expand Up @@ -227,6 +227,14 @@ the :ref:`user guide <user_guide>` for more information and usage examples.
NiftiMapsMasker
NiftiSpheresMasker

**Functions**:

.. autosummary::
:toctree: generated/
:template: function.rst

fmriprep_confounds

.. _masking_ref:

:mod:`nilearn.masking`: Data Masking Utilities
Expand Down
66 changes: 66 additions & 0 deletions doc/references.bib
Expand Up @@ -70,6 +70,22 @@ @article{BELLEC20101126
}


@article{Ciric2017,
title = {Benchmarking of participant-level confound regression strategies for the control of motion artifact in studies of functional connectivity},
volume = {154},
issn = {10959572},
doi = {10.1016/j.neuroimage.2017.03.020},
abstract = {Since initial reports regarding the impact of motion artifact on measures of functional connectivity, there has been a proliferation of participant-level confound regression methods to limit its impact. However, many of the most commonly used techniques have not been systematically evaluated using a broad range of outcome measures. Here, we provide a systematic evaluation of 14 participant-level confound regression methods in 393 youths. Specifically, we compare methods according to four benchmarks, including the residual relationship between motion and connectivity, distance-dependent effects of motion on connectivity, network identifiability, and additional degrees of freedom lost in confound regression. Our results delineate two clear trade-offs among methods. First, methods that include global signal regression minimize the relationship between connectivity and motion, but result in distance-dependent artifact. In contrast, censoring methods mitigate both motion artifact and distance-dependence, but use additional degrees of freedom. Importantly, less effective de-noising methods are also unable to identify modular network structure in the connectome. Taken together, these results emphasize the heterogeneous efficacy of existing methods, and suggest that different confound regression strategies may be appropriate in the context of specific scientific goals.},
pages = {174--187},
number = {1},
journal = {NeuroImage},
author = {Ciric, Rastko and Wolf, Daniel H. and Power, Jonathan D. and Roalf, David R. and Baum, Graham L. and Ruparel, Kosha and Shinohara, Russell T. and Elliott, Mark A. and Eickhoff, Simon B. and Davatzikos, Christos and Gur, Ruben C. and Gur, Raquel E. and Bassett, Danielle S. and Satterthwaite, Theodore D.},
year = {2017},
pmid = {28302591},
keywords = {{fMRI}, Functional connectivity, \#nosource, Artifact, Confound, Motion, Noise},
}


@article {Clarke4766,
author = {Clarke, Alex and Tyler, Lorraine K.},
title = {Object-Specific Semantic Coding in Human Perirhinal Cortex},
Expand Down Expand Up @@ -764,6 +780,56 @@ @Article{Power2011Functional
url={https://doi.org/10.1016/j.neuron.2011.09.006}
}


@article{Power2012,
title = {Spurious but systematic correlations in functional connectivity {MRI} networks arise from subject motion},
volume = {59},
issn = {10538119},
url = {http://www.ncbi.nlm.nih.gov/pubmed/22019881 http://www.pubmedcentral.nih.gov/articlerender.fcgi?artid=PMC3254728},
doi = {10.1016/j.neuroimage.2011.10.018},
abstract = {Here, we demonstrate that subject motion produces substantial changes in the timecourses of resting state functional connectivity {MRI} (rs-{fcMRI}) data despite compensatory spatial registration and regression of motion estimates from the data. These changes cause systematic but spurious correlation structures throughout the brain. Specifically, many long-distance correlations are decreased by subject motion, whereas many short-distance correlations are increased. These changes in rs-{fcMRI} correlations do not arise from, nor are they adequately countered by, some common functional connectivity processing steps. Two indices of data quality are proposed, and a simple method to reduce motion-related effects in rs-{fcMRI} analyses is demonstrated that should be flexibly implementable across a variety of software platforms. We demonstrate how application of this technique impacts our own data, modifying previous conclusions about brain development. These results suggest the need for greater care in dealing with subject motion, and the need to critically revisit previous rs-{fcMRI} work that may not have adequately controlled for effects of transient subject movements. © 2011 Elsevier Inc.},
pages = {2142--2154},
number = {3},
journal = {NeuroImage},
author = {Power, Jonathan D. and Barnes, Kelly A. and Snyder, Abraham Z. and Schlaggar, Bradley L. and Petersen, Steven E.},
year = {2012},
pmid = {22019881},
keywords = {{FMRI}, Resting state, Artifact, Motion, Noise, Movement, {FcMRI}, Network},
}


@article{Power2014,
title = {Methods to detect, characterize, and remove motion artifact in resting state {fMRI}},
volume = {84},
issn = {10538119},
url = {http://www.sciencedirect.com/science/article/pii/S1053811913009117},
doi = {10.1016/j.neuroimage.2013.08.048},
abstract = {Head motion systematically alters correlations in resting state functional connectivity {fMRI} ({RSFC}). In this report we examine impact of motion on signal intensity and {RSFC} correlations. We find that motion-induced signal changes (1) are often complex and variable waveforms, (2) are often shared across nearly all brain voxels, and (3) often persist more than 10. s after motion ceases. These signal changes, both during and after motion, increase observed {RSFC} correlations in a distance-dependent manner. Motion-related signal changes are not removed by a variety of motion-based regressors, but are effectively reduced by global signal regression. We link several measures of data quality to motion, changes in signal intensity, and changes in {RSFC} correlations. We demonstrate that improvements in data quality measures during processing may represent cosmetic improvements rather than true correction of the data. We demonstrate a within-subject, censoring-based artifact removal strategy based on volume censoring that reduces group differences due to motion to chance levels. We note conditions under which group-level regressions do and do not correct motion-related effects. © 2013 Elsevier Inc.},
pages = {320--341},
journal = {NeuroImage},
author = {Power, Jonathan D. and Mitra, Anish and Laumann, Timothy O. and Snyder, Abraham Z. and Schlaggar, Bradley L. and Petersen, Steven E.},
year = {2014},
pmid = {23994314},
keywords = {Functional connectivity, \#nosource, Resting state, Artifact, Motion, Movement, {MRI}},
}


@article{Pruim2015,
title = {{ICA}-{AROMA}: A robust {ICA}-based strategy for removing motion artifacts from {fMRI} data},
volume = {112},
issn = {1095-9572},
doi = {10.1016/j.neuroimage.2015.02.064},
shorttitle = {{ICA}-{AROMA}},
abstract = {Head motion during functional {MRI} ({fMRI}) scanning can induce spurious findings and/or harm detection of true effects. Solutions have been proposed, including deleting ('scrubbing') or regressing out ('spike regression') motion volumes from {fMRI} time-series. These strategies remove motion-induced signal variations at the cost of destroying the autocorrelation structure of the {fMRI} time-series and reducing temporal degrees of freedom. {ICA}-based {fMRI} denoising strategies overcome these drawbacks but typically require re-training of a classifier, needing manual labeling of derived components (e.g. {ICA}-{FIX}; Salimi-Khorshidi et al. (2014)). Here, we propose an {ICA}-based strategy for Automatic Removal of Motion Artifacts ({ICA}-{AROMA}) that uses a small (n=4), but robust set of theoretically motivated temporal and spatial features. Our strategy does not require classifier re-training, retains the data's autocorrelation structure and largely preserves temporal degrees of freedom. We describe {ICA}-{AROMA}, its implementation, and initial validation. {ICA}-{AROMA} identified motion components with high accuracy and robustness as illustrated by leave-N-out cross-validation. We additionally validated {ICA}-{AROMA} in resting-state (100 participants) and task-based {fMRI} data (118 participants). Our approach removed (motion-related) spurious noise from both {rfMRI} and task-based {fMRI} data to larger extent than regression using 24 motion parameters or spike regression. Furthermore, {ICA}-{AROMA} increased sensitivity to group-level activation. Our results show that {ICA}-{AROMA} effectively reduces motion-induced signal variations in {fMRI} data, is applicable across datasets without requiring classifier re-training, and preserves the temporal characteristics of the {fMRI} data.},
pages = {267--277},
journal = {Neuroimage},
author = {Pruim, Raimon H. R. and Mennes, Maarten and van Rooij, Daan and Llera, Alberto and Buitelaar, Jan K. and Beckmann, Christian F.},
year = {2015},
pmid = {25770991},
keywords = {Algorithms, Artifact, Artifacts, Artificial Intelligence, Cerebrospinal Fluid, Connectivity, Functional {MRI}, Humans, Image Processing, Computer-Assisted, Independent component analysis, Magnetic Resonance Imaging, Motion, Principal Component Analysis, Reproducibility of Results, Rest, Resting state},
}


@article{reilly2009cerebellum,
author = {O'Reilly, Jill X. and Beckmann, Christian F. and Tomassini, Valentina and Ramnani, Narender and Johansen-Berg, Heidi},
title = "{Distinct and Overlapping Functional Zones in the Cerebellum Defined by Resting State Functional Connectivity}",
Expand Down
3 changes: 3 additions & 0 deletions doc/whats_new.rst
Expand Up @@ -4,6 +4,9 @@
NEW
---

- New function :func:`nilearn.input_data.fmriprep_confounds` to load confound variables easily
from :term:`fMRIPrep` outputs.

Fixes
-----

Expand Down
134 changes: 120 additions & 14 deletions examples/03_connectivity/plot_signal_extraction.py
Expand Up @@ -8,9 +8,12 @@
We also show the importance of defining good confounds signals: the
first correlation matrix is computed after regressing out simple
confounds signals: movement regressors, white matter and CSF signals, ...
The second one is without any confounds: all regions are connected to
each other.

The second one is without any confounds: all regions are connected to each
other. Finally we demonstrated the functionality of
:func:`nilearn.input_data.fmriprep_confounds` to flexibly select confound
variables from :term:`fMRIPrep` outputs while following some implementation
guideline of :term:`fMRIPrep` confounds documentation
`<https://fmriprep.org/en/stable/outputs.html#confounds>`_.

One reference that discusses the importance of confounds is `Varoquaux and
Craddock, Learning and comparing functional connectomes across subjects,
Expand All @@ -26,7 +29,7 @@

##############################################################################
# Retrieve the atlas and the data
# --------------------------------
# -------------------------------
from nilearn import datasets

dataset = datasets.fetch_atlas_harvard_oxford('cort-maxprob-thr25-2mm')
Expand All @@ -37,12 +40,13 @@
atlas_filename) # 4D data

# One subject of brain development fmri data
data = datasets.fetch_development_fmri(n_subjects=1)
data = datasets.fetch_development_fmri(n_subjects=1, reduce_confounds=True)
fmri_filenames = data.func[0]
reduced_confounds = data.confounds[0] # This is a preselected set of confounds

##############################################################################
# Extract signals on a parcellation defined by labels
# -----------------------------------------------------
# ---------------------------------------------------
# Using the NiftiLabelsMasker
from nilearn.input_data import NiftiLabelsMasker
masker = NiftiLabelsMasker(labels_img=atlas_filename, standardize=True,
Expand All @@ -51,12 +55,11 @@
# Here we go from nifti files to the signal time series in a numpy
# array. Note how we give confounds to be regressed out during signal
# extraction
time_series = masker.fit_transform(fmri_filenames, confounds=data.confounds)

time_series = masker.fit_transform(fmri_filenames, confounds=reduced_confounds)

##############################################################################
# Compute and display a correlation matrix
# -----------------------------------------
# ----------------------------------------
from nilearn.connectome import ConnectivityMeasure
correlation_measure = ConnectivityMeasure(kind='correlation')
correlation_matrix = correlation_measure.fit_transform([time_series])[0]
Expand All @@ -71,21 +74,124 @@
# first label
# matrices are ordered for block-like representation
plotting.plot_matrix(correlation_matrix, figure=(10, 8), labels=labels[1:],
vmax=0.8, vmin=-0.8, reorder=True)
vmax=0.8, vmin=-0.8, title="Preset",
reorder=True)

###############################################################################
# Same thing without confounds, to stress the importance of confounds
# --------------------------------------------------------------------
##############################################################################
# Extract signals and compute a connectivity matrix without confounds
htwangtw marked this conversation as resolved.
Show resolved Hide resolved
# -------------------------------------------------------------------
# After covering the basic of signal extraction and functional connectivity
# matrix presentation, let's look into the impact of confounds to :term:`fMRI`
# signal and functional connectivity. Firstly let's find out what a functional
# connectivity matrix looks like without confound removal.

time_series = masker.fit_transform(fmri_filenames)
# Note how we did not specify confounds above. This is bad!

correlation_matrix = correlation_measure.fit_transform([time_series])[0]

# Mask the main diagonal for visualization:
np.fill_diagonal(correlation_matrix, 0)

plotting.plot_matrix(correlation_matrix, figure=(10, 8), labels=labels[1:],
vmax=0.8, vmin=-0.8, title='No confounds', reorder=True)

##############################################################################
# Load confounds from file using a flexible strategy with fmriprep_confounds
# --------------------------------------------------------------------------
# The :func:`nilearn.input_data.fmriprep_confounds` function provides flexible
# parameters to retrieve the relevant columns from the TSV file generated by
# :term:`fMRIPrep`. :func:`nilearn.input_data.fmriprep_confounds` ensures
# two things:
# 1. The correct regressors are selected with provided strategy, and
# 2. Volumes such as non-steady-state volumes are masked out correctly.
# Let's try a simple strategy removing motion, white matter signal,
# cerebrospinal fluid signal with high-pass filtering.

from nilearn.input_data import fmriprep_confounds
confounds_simple, sample_mask = fmriprep_confounds(
fmri_filenames,
strategy=["high_pass", "motion", "wm_csf"],
motion="basic", wm_csf="basic")

print("The shape of the confounds matrix is:", confounds_simple.shape)
print(confounds_simple.columns)

time_series = masker.fit_transform(fmri_filenames,
confounds=confounds_simple,
sample_mask=sample_mask)

correlation_matrix = correlation_measure.fit_transform([time_series])[0]

np.fill_diagonal(correlation_matrix, 0)

plotting.plot_matrix(correlation_matrix, figure=(10, 8), labels=labels[1:],
vmax=0.8, vmin=-0.8, title='Motion, WM, CSF',
reorder=True)

##############################################################################
# Motion-based scrubbing
# ----------------------
# With a scrubbing-based strategy, `fmriprep_confounds` returns a `sample_mask`
# that remove the index of volumes exceeding the framewise displacement and
htwangtw marked this conversation as resolved.
Show resolved Hide resolved
# standardised DVARS threshold, and all the continuous segment with less than
# five volumes. Before applying scrubbing, it's important to access the
# percentage of volumns scrubbed. Scrubbing is not a suitable strategy for
# datasets with too many high motion subjects.
# On top of the simple strategy above, let's add scrubbing to our
# strategy.

confounds_scrub, sample_mask = fmriprep_confounds(
fmri_filenames,
strategy=["high_pass", "motion", "wm_csf", "scrub"],
motion="basic", wm_csf="basic",
scrub="full", fd_thresh=0.2, std_dvars_thresh=3)

print("After scrubbing, {} out of {} volumes remains".format(
sample_mask.shape[0], confounds_scrub.shape[0]))
print("The shape of the confounds matrix is:", confounds_simple.shape)
print(confounds_scrub.columns)

time_series = masker.fit_transform(fmri_filenames,
confounds=confounds_scrub,
sample_mask=sample_mask)

correlation_matrix = correlation_measure.fit_transform([time_series])[0]

np.fill_diagonal(correlation_matrix, 0)

plotting.plot_matrix(correlation_matrix, figure=(10, 8), labels=labels[1:],
vmax=0.8, vmin=-0.8,
title='Motion, WM, CSF, Scrubbing',
reorder=True)

##############################################################################
# The impact of global signal removal
# -----------------------------------
# Global signal removes the grand mean from your signal. The benefit is that
# it can remove impacts of physiological artifacts with minimal impact on the
# degree of freedom. The downside is that one cannot get insight into variance
htwangtw marked this conversation as resolved.
Show resolved Hide resolved
# explained by certain sources of noise. Now let's add global signal to the
# simple strategy and see its impact.

confounds_minimal_no_gsr, sample_mask = fmriprep_confounds(
fmri_filenames,
strategy=["high_pass", "motion", "wm_csf", "global"],
motion="basic", wm_csf="basic", global_signal="basic")
print("The shape of the confounds matrix is:",
confounds_minimal_no_gsr.shape)
print(confounds_minimal_no_gsr.columns)

time_series = masker.fit_transform(fmri_filenames,
confounds=confounds_minimal_no_gsr,
sample_mask=sample_mask)

correlation_matrix = correlation_measure.fit_transform([time_series])[0]

np.fill_diagonal(correlation_matrix, 0)

plotting.plot_matrix(correlation_matrix, figure=(10, 8), labels=labels[1:],
vmax=0.8, vmin=-0.8,
title='Motion, WM, CSF, GSR',
reorder=True)

plotting.show()
5 changes: 3 additions & 2 deletions nilearn/__init__.py
Expand Up @@ -21,8 +21,9 @@
and for sparse multi-subjects learning of Gaussian graphical models
image --- Set of functions defining mathematical operations
working on Niimg-like objects
input_data --- includes scikit-learn tranformers and tools to
preprocess neuro-imaging data
input_data --- Includes scikit-learn transformers and tools to
preprocess neuro-imaging data and access fMRIPrep
generated confounds.
masking --- Utilities to compute and operate on brain masks
mass_univariate --- Defines a Massively Univariate Linear Model
estimated with OLS and permutation test
Expand Down
28 changes: 28 additions & 0 deletions nilearn/_utils/fmriprep_confounds.py
@@ -0,0 +1,28 @@
""" Misc utilities for the library.

Authors: load_confounds team
bthirion marked this conversation as resolved.
Show resolved Hide resolved
"""


def _flag_single_gifti(img_files):
"""Test if the paired input files are giftis."""
# Possibly two gifti; if file is not correct, will be caught
if isinstance(img_files[0], list):
return False

flag_single_gifti = [] # gifti in pairs
for img in img_files:
ext = ".".join(img.split(".")[-2:])
flag_single_gifti.append((ext == "func.gii"))
return all(flag_single_gifti)


def _is_camel_case(s):
"Check if the given string is in camel case."
return s != s.lower() and s != s.upper() and "_" not in s


def _to_camel_case(snake_str):
"""Convert camel to snake case."""
components = snake_str.split('_')
return components[0] + ''.join(x.title() for x in components)