junifer 0.0.2.dev138__py3-none-any.whl → 0.0.2.dev140__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- junifer/_version.py +2 -2
- junifer/data/masks.py +102 -30
- junifer/data/tests/test_masks.py +166 -8
- junifer/datagrabber/aomic/id1000.py +33 -1
- junifer/datagrabber/aomic/piop1.py +14 -0
- junifer/datagrabber/aomic/piop2.py +35 -1
- junifer/datagrabber/aomic/tests/test_id1000.py +6 -0
- junifer/datagrabber/aomic/tests/test_piop1.py +6 -0
- junifer/datagrabber/aomic/tests/test_piop2.py +6 -1
- junifer/markers/ets_rss.py +8 -8
- junifer/markers/falff/falff_parcels.py +7 -7
- junifer/markers/falff/falff_spheres.py +8 -8
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +8 -8
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +7 -7
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +8 -8
- junifer/markers/functional_connectivity/functional_connectivity_base.py +7 -7
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +7 -7
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +8 -8
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_base.py +4 -2
- junifer/markers/parcel_aggregation.py +11 -9
- junifer/markers/reho/reho_parcels.py +8 -8
- junifer/markers/reho/reho_spheres.py +8 -8
- junifer/markers/sphere_aggregation.py +11 -9
- junifer/markers/tests/test_collection.py +8 -6
- junifer/markers/tests/test_marker_utils.py +2 -1
- junifer/markers/tests/test_parcel_aggregation.py +2 -2
- junifer/markers/tests/test_sphere_aggregation.py +1 -1
- junifer/markers/utils.py +10 -10
- junifer/preprocess/base.py +11 -1
- junifer/preprocess/confounds/fmriprep_confound_remover.py +31 -24
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +59 -3
- {junifer-0.0.2.dev138.dist-info → junifer-0.0.2.dev140.dist-info}/METADATA +1 -1
- {junifer-0.0.2.dev138.dist-info → junifer-0.0.2.dev140.dist-info}/RECORD +38 -38
- {junifer-0.0.2.dev138.dist-info → junifer-0.0.2.dev140.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.2.dev138.dist-info → junifer-0.0.2.dev140.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.2.dev138.dist-info → junifer-0.0.2.dev140.dist-info}/WHEEL +0 -0
- {junifer-0.0.2.dev138.dist-info → junifer-0.0.2.dev140.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.2.dev138.dist-info → junifer-0.0.2.dev140.dist-info}/top_level.txt +0 -0
junifer/_version.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
# file generated by setuptools_scm
|
2
2
|
# don't change, don't track in version control
|
3
|
-
__version__ = version = '0.0.2.
|
4
|
-
__version_tuple__ = version_tuple = (0, 0, 2, '
|
3
|
+
__version__ = version = '0.0.2.dev140'
|
4
|
+
__version_tuple__ = version_tuple = (0, 0, 2, 'dev140')
|
junifer/data/masks.py
CHANGED
@@ -23,6 +23,7 @@ from nilearn.masking import (
|
|
23
23
|
compute_background_mask,
|
24
24
|
compute_brain_mask,
|
25
25
|
compute_epi_mask,
|
26
|
+
intersect_masks,
|
26
27
|
)
|
27
28
|
|
28
29
|
from ..utils.logging import logger, raise_error
|
@@ -36,7 +37,10 @@ if TYPE_CHECKING:
|
|
36
37
|
_masks_path = Path(__file__).parent / "masks"
|
37
38
|
|
38
39
|
|
39
|
-
def _fetch_icbm152_brain_gm_mask(
|
40
|
+
def _fetch_icbm152_brain_gm_mask(
|
41
|
+
target_img: "Nifti1Image",
|
42
|
+
**kwargs,
|
43
|
+
):
|
40
44
|
"""Fetch ICBM152 brain mask and resample.
|
41
45
|
|
42
46
|
Parameters
|
@@ -65,6 +69,9 @@ data.
|
|
65
69
|
|
66
70
|
The built-in masks are files that are shipped with the package in the
|
67
71
|
data/masks directory. The user can also register their own masks.
|
72
|
+
|
73
|
+
Callable masks should be functions that take at least one parameter:
|
74
|
+
* `target_img`: the image to which the mask will be applied.
|
68
75
|
"""
|
69
76
|
_available_masks: Dict[str, Dict[str, Any]] = {
|
70
77
|
"GM_prob0.2": {"family": "Vickery-Patil"},
|
@@ -146,19 +153,23 @@ def list_masks() -> List[str]:
|
|
146
153
|
|
147
154
|
|
148
155
|
def get_mask(
|
149
|
-
|
156
|
+
masks: Union[str, Dict, List[Union[Dict, str]]],
|
150
157
|
target_data: Dict[str, Any],
|
158
|
+
extra_input: Optional[Dict[str, Any]] = None,
|
151
159
|
) -> "Nifti1Image":
|
152
160
|
"""Get mask, tailored for the target image.
|
153
161
|
|
154
162
|
Parameters
|
155
163
|
----------
|
156
|
-
masks : str or dict
|
164
|
+
masks : str, dict or list of dict or str
|
157
165
|
The name of the mask, or the name of a callable mask and the parameters
|
158
|
-
of the mask.
|
166
|
+
of the mask as a dictionary. Several masks can be passed as a list.
|
159
167
|
target_data : dict
|
160
168
|
The corresponding item of the data object to which the mask will be
|
161
169
|
applied.
|
170
|
+
extra_input : dict, optional
|
171
|
+
The other fields in the data object. Useful for accessing other data
|
172
|
+
kinds that needs to be used in the computation of masks (default None).
|
162
173
|
|
163
174
|
Returns
|
164
175
|
-------
|
@@ -167,37 +178,98 @@ def get_mask(
|
|
167
178
|
"""
|
168
179
|
# Get the min of the voxels sizes and use it as the resolution
|
169
180
|
target_img = target_data["data"]
|
181
|
+
inherited_mask_item = target_data.get("mask_item", None)
|
170
182
|
resolution = np.min(target_img.header.get_zooms()[:3])
|
171
183
|
|
172
|
-
if isinstance(
|
173
|
-
|
174
|
-
raise_error(
|
175
|
-
"The mask dictionary must have only one key, "
|
176
|
-
"the name of the mask."
|
177
|
-
)
|
178
|
-
mask_name = list(mask.keys())[0]
|
179
|
-
mask_params = mask[mask_name]
|
180
|
-
else:
|
181
|
-
mask_name = mask
|
182
|
-
mask_params = None
|
184
|
+
if not isinstance(masks, list):
|
185
|
+
masks = [masks]
|
183
186
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
raise_error("Cannot pass callable params to a non-callable mask.")
|
194
|
-
mask_img = resample_to_img(
|
195
|
-
mask_object,
|
196
|
-
target_img,
|
197
|
-
interpolation="nearest",
|
198
|
-
copy=True,
|
187
|
+
# Check that dicts have only one key
|
188
|
+
invalid_elements = [
|
189
|
+
x for x in masks if isinstance(x, dict) and len(x) != 1
|
190
|
+
]
|
191
|
+
if len(invalid_elements) > 0:
|
192
|
+
raise_error(
|
193
|
+
"Each of the masks dictionary must have only one key, "
|
194
|
+
"the name of the mask. The following dictionaries are invalid: "
|
195
|
+
f"{invalid_elements}"
|
199
196
|
)
|
200
197
|
|
198
|
+
# Check params for the intersection function
|
199
|
+
intersect_params = {}
|
200
|
+
true_masks = []
|
201
|
+
for t_mask in masks:
|
202
|
+
if isinstance(t_mask, dict):
|
203
|
+
if "threshold" in t_mask:
|
204
|
+
intersect_params["threshold"] = t_mask["threshold"]
|
205
|
+
continue
|
206
|
+
elif "connected" in t_mask:
|
207
|
+
intersect_params["connected"] = t_mask["connected"]
|
208
|
+
continue
|
209
|
+
# All the other elements are masks
|
210
|
+
true_masks.append(t_mask)
|
211
|
+
|
212
|
+
if len(true_masks) == 0:
|
213
|
+
raise_error("No mask was passed. At least one mask is required.")
|
214
|
+
# Get all the masks
|
215
|
+
all_masks = []
|
216
|
+
for t_mask in true_masks:
|
217
|
+
if isinstance(t_mask, dict):
|
218
|
+
mask_name = list(t_mask.keys())[0]
|
219
|
+
mask_params = t_mask[mask_name]
|
220
|
+
else:
|
221
|
+
mask_name = t_mask
|
222
|
+
mask_params = None
|
223
|
+
|
224
|
+
if mask_name == "inherit":
|
225
|
+
if extra_input is None:
|
226
|
+
raise_error(
|
227
|
+
"Cannot inherit mask from another data item "
|
228
|
+
"because no extra data was passed."
|
229
|
+
)
|
230
|
+
if inherited_mask_item is None:
|
231
|
+
raise_error(
|
232
|
+
"Cannot inherit mask from another data item "
|
233
|
+
"because no mask item was specified "
|
234
|
+
"(missing `mask_item` key in the data object)."
|
235
|
+
)
|
236
|
+
if inherited_mask_item not in extra_input:
|
237
|
+
raise_error(
|
238
|
+
"Cannot inherit mask from another data item "
|
239
|
+
f"because the item ({inherited_mask_item}) does not exist."
|
240
|
+
)
|
241
|
+
mask_img = extra_input[inherited_mask_item]["data"]
|
242
|
+
else:
|
243
|
+
mask_object, _ = load_mask(
|
244
|
+
mask_name, path_only=False, resolution=resolution
|
245
|
+
)
|
246
|
+
if callable(mask_object):
|
247
|
+
if mask_params is None:
|
248
|
+
mask_params = {}
|
249
|
+
mask_img = mask_object(target_img, **mask_params)
|
250
|
+
else: # Mask is a Nifti1Image
|
251
|
+
if mask_params is not None:
|
252
|
+
raise_error(
|
253
|
+
"Cannot pass callable params to a non-callable mask."
|
254
|
+
)
|
255
|
+
mask_img = resample_to_img(
|
256
|
+
mask_object,
|
257
|
+
target_img,
|
258
|
+
interpolation="nearest",
|
259
|
+
copy=True,
|
260
|
+
)
|
261
|
+
all_masks.append(mask_img)
|
262
|
+
if len(all_masks) > 1:
|
263
|
+
mask_img = intersect_masks(all_masks, **intersect_params)
|
264
|
+
else:
|
265
|
+
if len(intersect_params) > 0:
|
266
|
+
# Yes, I'm this strict!
|
267
|
+
raise_error(
|
268
|
+
"Cannot pass parameters to the intersection function "
|
269
|
+
"when there is only one mask."
|
270
|
+
)
|
271
|
+
mask_img = all_masks[0]
|
272
|
+
|
201
273
|
return mask_img
|
202
274
|
|
203
275
|
|
junifer/data/tests/test_masks.py
CHANGED
@@ -6,8 +6,9 @@
|
|
6
6
|
# License: AGPL
|
7
7
|
|
8
8
|
from pathlib import Path
|
9
|
-
from typing import Callable, Dict, Union
|
9
|
+
from typing import Callable, Dict, List, Union
|
10
10
|
|
11
|
+
import numpy as np
|
11
12
|
import pytest
|
12
13
|
from nilearn.datasets import fetch_icbm152_brain_gm_mask
|
13
14
|
from nilearn.image import resample_to_img
|
@@ -15,6 +16,7 @@ from nilearn.masking import (
|
|
15
16
|
compute_background_mask,
|
16
17
|
compute_brain_mask,
|
17
18
|
compute_epi_mask,
|
19
|
+
intersect_masks,
|
18
20
|
)
|
19
21
|
from numpy.testing import assert_array_almost_equal, assert_array_equal
|
20
22
|
|
@@ -56,7 +58,9 @@ def test_register_mask_already_registered() -> None:
|
|
56
58
|
name="testmask",
|
57
59
|
mask_path="testmask.nii.gz",
|
58
60
|
)
|
59
|
-
|
61
|
+
out = load_mask("testmask", path_only=True)
|
62
|
+
assert out[1] is not None
|
63
|
+
assert out[1].name == "testmask.nii.gz"
|
60
64
|
|
61
65
|
# Try registering again
|
62
66
|
with pytest.raises(ValueError, match=r"already registered."):
|
@@ -70,7 +74,9 @@ def test_register_mask_already_registered() -> None:
|
|
70
74
|
overwrite=True,
|
71
75
|
)
|
72
76
|
|
73
|
-
|
77
|
+
out = load_mask("testmask", path_only=True)
|
78
|
+
assert out[1] is not None
|
79
|
+
assert out[1].name == "testmask2.nii.gz"
|
74
80
|
|
75
81
|
|
76
82
|
@pytest.mark.parametrize(
|
@@ -110,6 +116,7 @@ def test_register_mask(
|
|
110
116
|
# Load registered mask
|
111
117
|
_, fname = load_mask(name=name, path_only=True)
|
112
118
|
# Check values for registered mask
|
119
|
+
assert fname is not None
|
113
120
|
assert fname.name == f"{name}.nii.gz"
|
114
121
|
|
115
122
|
|
@@ -146,6 +153,7 @@ def test_vickery_patil() -> None:
|
|
146
153
|
mask.header["pixdim"][1:4], [1.5, 1.5, 1.5] # type: ignore
|
147
154
|
)
|
148
155
|
|
156
|
+
assert fname is not None
|
149
157
|
assert fname.name == "CAT12_IXI555_MNI152_TMP_GS_GMprob0.2_clean.nii.gz"
|
150
158
|
|
151
159
|
mask, fname = load_mask("GM_prob0.2", resolution=3)
|
@@ -153,6 +161,7 @@ def test_vickery_patil() -> None:
|
|
153
161
|
mask.header["pixdim"][1:4], [3.0, 3.0, 3.0] # type: ignore
|
154
162
|
)
|
155
163
|
|
164
|
+
assert fname is not None
|
156
165
|
assert (
|
157
166
|
fname.name == "CAT12_IXI555_MNI152_TMP_GS_GMprob0.2_clean_3mm.nii.gz"
|
158
167
|
)
|
@@ -162,6 +171,7 @@ def test_vickery_patil() -> None:
|
|
162
171
|
mask.header["pixdim"][1:4], [3.0, 3.0, 3.0] # type: ignore
|
163
172
|
)
|
164
173
|
|
174
|
+
assert fname is not None
|
165
175
|
assert fname.name == "GMprob0.2_cortex_3mm_NA_rm.nii.gz"
|
166
176
|
|
167
177
|
with pytest.raises(ValueError, match=r"find a Vickery-Patil mask "):
|
@@ -176,7 +186,7 @@ def test_get_mask() -> None:
|
|
176
186
|
input = reader.fit_transform(input)
|
177
187
|
vbm_gm = input["VBM_GM"]
|
178
188
|
vbm_gm_img = vbm_gm["data"]
|
179
|
-
mask = get_mask(
|
189
|
+
mask = get_mask(masks="GM_prob0.2", target_data=vbm_gm)
|
180
190
|
|
181
191
|
assert mask.shape == vbm_gm_img.shape
|
182
192
|
assert_array_equal(mask.affine, vbm_gm_img.affine)
|
@@ -204,7 +214,7 @@ def test_mask_callable() -> None:
|
|
204
214
|
input = reader.fit_transform(input)
|
205
215
|
vbm_gm = input["VBM_GM"]
|
206
216
|
vbm_gm_img = vbm_gm["data"]
|
207
|
-
mask = get_mask(
|
217
|
+
mask = get_mask(masks="identity", target_data=vbm_gm)
|
208
218
|
|
209
219
|
assert_array_equal(mask.get_fdata(), vbm_gm_img.get_fdata())
|
210
220
|
|
@@ -218,11 +228,48 @@ def test_get_mask_errors() -> None:
|
|
218
228
|
input = dg["sub-01"]
|
219
229
|
input = reader.fit_transform(input)
|
220
230
|
vbm_gm = input["VBM_GM"]
|
231
|
+
# Test wrong masks definitions (more than one key per dict)
|
221
232
|
with pytest.raises(ValueError, match=r"only one key"):
|
222
|
-
get_mask(
|
233
|
+
get_mask(masks={"GM_prob0.2": {}, "Other": {}}, target_data=vbm_gm)
|
223
234
|
|
235
|
+
# Test wrong masks definitions (pass paramaeters to non-callable mask)
|
224
236
|
with pytest.raises(ValueError, match=r"callable params"):
|
225
|
-
get_mask(
|
237
|
+
get_mask(masks={"GM_prob0.2": {"param": 1}}, target_data=vbm_gm)
|
238
|
+
|
239
|
+
# Pass only parametesr to the intersection function
|
240
|
+
with pytest.raises(
|
241
|
+
ValueError, match=r" At least one mask is required."
|
242
|
+
):
|
243
|
+
get_mask(masks={"threshold": 1}, target_data=vbm_gm)
|
244
|
+
|
245
|
+
# Pass parameters to the intersection function when only one mask
|
246
|
+
with pytest.raises(
|
247
|
+
ValueError, match=r"parameters to the intersection"
|
248
|
+
):
|
249
|
+
get_mask(
|
250
|
+
masks=["GM_prob0.2", {"threshold": 1}], target_data=vbm_gm
|
251
|
+
)
|
252
|
+
|
253
|
+
# Test "inherited" masks errors
|
254
|
+
|
255
|
+
# 1) No extra_data parameter
|
256
|
+
with pytest.raises(ValueError, match=r"no extra data was passed"):
|
257
|
+
get_mask(masks="inherit", target_data=vbm_gm)
|
258
|
+
|
259
|
+
extra_input = {"VBM_MASK": {}}
|
260
|
+
|
261
|
+
# 2) No mask_item key in target_data
|
262
|
+
with pytest.raises(ValueError, match=r"no mask item was specified"):
|
263
|
+
get_mask(
|
264
|
+
masks="inherit", target_data=vbm_gm, extra_input=extra_input
|
265
|
+
)
|
266
|
+
|
267
|
+
# 3) mask_item not in extra data
|
268
|
+
with pytest.raises(ValueError, match=r"does not exist"):
|
269
|
+
vbm_gm["mask_item"] = "wrong"
|
270
|
+
get_mask(
|
271
|
+
masks="inherit", target_data=vbm_gm, extra_input=extra_input
|
272
|
+
)
|
226
273
|
|
227
274
|
|
228
275
|
@pytest.mark.parametrize(
|
@@ -271,7 +318,7 @@ def test_nilearn_compute_masks(
|
|
271
318
|
else:
|
272
319
|
mask_spec = {mask_name: params}
|
273
320
|
|
274
|
-
mask = get_mask(
|
321
|
+
mask = get_mask(masks=mask_spec, target_data=bold)
|
275
322
|
|
276
323
|
assert_array_equal(mask.affine, bold_img.affine)
|
277
324
|
|
@@ -287,3 +334,114 @@ def test_nilearn_compute_masks(
|
|
287
334
|
copy=True,
|
288
335
|
)
|
289
336
|
assert_array_equal(mask.get_fdata(), ni_mask.get_fdata())
|
337
|
+
|
338
|
+
|
339
|
+
def test_get_mask_inherit() -> None:
|
340
|
+
"""Test using the inherit mask functionality."""
|
341
|
+
reader = DefaultDataReader()
|
342
|
+
with SPMAuditoryTestingDatagrabber() as dg:
|
343
|
+
input = dg["sub001"]
|
344
|
+
input = reader.fit_transform(input)
|
345
|
+
# Compute brain mask using nilearn
|
346
|
+
gm_mask = compute_brain_mask(input["BOLD"]["data"], threshold=0.2)
|
347
|
+
|
348
|
+
# Get mask using the compute_brain_mask function
|
349
|
+
mask1 = get_mask(
|
350
|
+
masks={"compute_brain_mask": {"threshold": 0.2}},
|
351
|
+
target_data=input["BOLD"],
|
352
|
+
)
|
353
|
+
|
354
|
+
# Now get the mask using the inherit functionality, passing the
|
355
|
+
# computed mask as extra data
|
356
|
+
extra_input = {"BOLD_MASK": {"data": gm_mask}}
|
357
|
+
input["BOLD"]["mask_item"] = "BOLD_MASK"
|
358
|
+
mask2 = get_mask(
|
359
|
+
masks="inherit", target_data=input["BOLD"], extra_input=extra_input
|
360
|
+
)
|
361
|
+
|
362
|
+
# Both masks should be equal
|
363
|
+
assert_array_equal(mask1.get_fdata(), mask2.get_fdata())
|
364
|
+
|
365
|
+
|
366
|
+
@pytest.mark.parametrize(
|
367
|
+
"masks,params",
|
368
|
+
[
|
369
|
+
(["GM_prob0.2", "compute_brain_mask"], {}),
|
370
|
+
(
|
371
|
+
["GM_prob0.2", "compute_brain_mask"],
|
372
|
+
{"threshold": 0.2},
|
373
|
+
),
|
374
|
+
(
|
375
|
+
[
|
376
|
+
"GM_prob0.2",
|
377
|
+
"compute_brain_mask",
|
378
|
+
"fetch_icbm152_brain_gm_mask",
|
379
|
+
],
|
380
|
+
{"threshold": 1, "connected": True},
|
381
|
+
),
|
382
|
+
],
|
383
|
+
)
|
384
|
+
def test_get_mask_multiple(
|
385
|
+
masks: Union[str, Dict, List[Union[Dict, str]]], params: Dict
|
386
|
+
) -> None:
|
387
|
+
"""Test getting multiple masks.
|
388
|
+
|
389
|
+
Parameters
|
390
|
+
----------
|
391
|
+
masks : str, dict, list of str or dict
|
392
|
+
Masks to get, junifer style.
|
393
|
+
params : dict
|
394
|
+
Parameters to pass to the intersect_masks function.
|
395
|
+
"""
|
396
|
+
reader = DefaultDataReader()
|
397
|
+
with SPMAuditoryTestingDatagrabber() as dg:
|
398
|
+
input = dg["sub001"]
|
399
|
+
input = reader.fit_transform(input)
|
400
|
+
if not isinstance(masks, list):
|
401
|
+
junifer_masks = [masks]
|
402
|
+
else:
|
403
|
+
junifer_masks = masks.copy()
|
404
|
+
if len(params) > 0:
|
405
|
+
# Convert params to junifer style (one dict per param)
|
406
|
+
junifer_params = [{k: params[k]} for k in params.keys()]
|
407
|
+
junifer_masks.extend(junifer_params)
|
408
|
+
target_img = input["BOLD"]["data"]
|
409
|
+
resolution = np.min(target_img.header.get_zooms()[:3])
|
410
|
+
|
411
|
+
computed = get_mask(masks=junifer_masks, target_data=input["BOLD"])
|
412
|
+
|
413
|
+
masks_names = [
|
414
|
+
list(x.keys())[0] if isinstance(x, dict) else x for x in masks
|
415
|
+
]
|
416
|
+
|
417
|
+
mask_funcs = [
|
418
|
+
x
|
419
|
+
for x in masks_names
|
420
|
+
if _available_masks[x]["family"] == "Callable"
|
421
|
+
]
|
422
|
+
mask_files = [
|
423
|
+
x
|
424
|
+
for x in masks_names
|
425
|
+
if _available_masks[x]["family"] != "Callable"
|
426
|
+
]
|
427
|
+
|
428
|
+
mask_imgs = [
|
429
|
+
load_mask(t_mask, path_only=False, resolution=resolution)[0]
|
430
|
+
for t_mask in mask_files
|
431
|
+
]
|
432
|
+
|
433
|
+
for t_func in mask_funcs:
|
434
|
+
mask_imgs.append(_available_masks[t_func]["func"](target_img))
|
435
|
+
|
436
|
+
mask_imgs = [
|
437
|
+
resample_to_img(
|
438
|
+
t_mask,
|
439
|
+
target_img,
|
440
|
+
interpolation="nearest",
|
441
|
+
copy=True,
|
442
|
+
)
|
443
|
+
for t_mask in mask_imgs
|
444
|
+
]
|
445
|
+
|
446
|
+
expected = intersect_masks(mask_imgs, **params)
|
447
|
+
assert_array_equal(computed.get_fdata(), expected.get_fdata())
|
@@ -7,7 +7,7 @@
|
|
7
7
|
# License: AGPL
|
8
8
|
|
9
9
|
from pathlib import Path
|
10
|
-
from typing import Union
|
10
|
+
from typing import Union, Dict
|
11
11
|
|
12
12
|
from junifer.datagrabber import PatternDataladDataGrabber
|
13
13
|
|
@@ -34,7 +34,9 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
|
|
34
34
|
types = [
|
35
35
|
"BOLD",
|
36
36
|
"BOLD_confounds",
|
37
|
+
"BOLD_mask",
|
37
38
|
"T1w",
|
39
|
+
"T1w_mask",
|
38
40
|
"probseg_CSF",
|
39
41
|
"probseg_GM",
|
40
42
|
"probseg_WM",
|
@@ -52,11 +54,22 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
|
|
52
54
|
"sub-{subject}_task-moviewatching_"
|
53
55
|
"desc-confounds_regressors.tsv"
|
54
56
|
),
|
57
|
+
"BOLD_mask": (
|
58
|
+
"derivatives/fmriprep/sub-{subject}/func/"
|
59
|
+
"sub-{subject}_task-moviewatching_"
|
60
|
+
"space-MNI152NLin2009cAsym_"
|
61
|
+
"desc-brain_mask.nii.gz"
|
62
|
+
),
|
55
63
|
"T1w": (
|
56
64
|
"derivatives/fmriprep/sub-{subject}/anat/"
|
57
65
|
"sub-{subject}_space-MNI152NLin2009cAsym_"
|
58
66
|
"desc-preproc_T1w.nii.gz"
|
59
67
|
),
|
68
|
+
"T1w_mask": (
|
69
|
+
"derivatives/fmriprep/sub-{subject}/anat/"
|
70
|
+
"sub-{subject}_space-MNI152NLin2009cAsym_"
|
71
|
+
"desc-brain_mask.nii.gz"
|
72
|
+
),
|
60
73
|
"probseg_CSF": (
|
61
74
|
"derivatives/fmriprep/sub-{subject}/anat/"
|
62
75
|
"sub-{subject}_space-MNI152NLin2009cAsym_label-"
|
@@ -88,3 +101,22 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
|
|
88
101
|
replacements=replacements,
|
89
102
|
confounds_format="fmriprep",
|
90
103
|
)
|
104
|
+
|
105
|
+
def get_item(self, subject: str) -> Dict:
|
106
|
+
"""Index one element in the dataset.
|
107
|
+
|
108
|
+
Parameters
|
109
|
+
----------
|
110
|
+
subject : str
|
111
|
+
The subject ID.
|
112
|
+
|
113
|
+
Returns
|
114
|
+
-------
|
115
|
+
out : dict
|
116
|
+
Dictionary of paths for each type of data required for the
|
117
|
+
specified element.
|
118
|
+
"""
|
119
|
+
out = super().get_item(subject=subject)
|
120
|
+
out["BOLD"]["mask_item"] = "BOLD_mask"
|
121
|
+
out["T1w"]["mask_item"] = "T1w_mask"
|
122
|
+
return out
|
@@ -41,7 +41,9 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
|
|
41
41
|
types = [
|
42
42
|
"BOLD",
|
43
43
|
"BOLD_confounds",
|
44
|
+
"BOLD_mask",
|
44
45
|
"T1w",
|
46
|
+
"T1w_mask",
|
45
47
|
"probseg_CSF",
|
46
48
|
"probseg_GM",
|
47
49
|
"probseg_WM",
|
@@ -83,11 +85,21 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
|
|
83
85
|
"sub-{subject}_task-{task}_"
|
84
86
|
"desc-confounds_regressors.tsv"
|
85
87
|
),
|
88
|
+
"BOLD_mask": (
|
89
|
+
"derivatives/fmriprep/sub-{subject}/func/"
|
90
|
+
"sub-{subject}_task-{task}_"
|
91
|
+
"space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
|
92
|
+
),
|
86
93
|
"T1w": (
|
87
94
|
"derivatives/fmriprep/sub-{subject}/anat/"
|
88
95
|
"sub-{subject}_space-MNI152NLin2009cAsym_"
|
89
96
|
"desc-preproc_T1w.nii.gz"
|
90
97
|
),
|
98
|
+
"T1w_mask": (
|
99
|
+
"derivatives/fmriprep/sub-{subject}/anat/"
|
100
|
+
"sub-{subject}_space-MNI152NLin2009cAsym_"
|
101
|
+
"desc-brain_mask.nii.gz"
|
102
|
+
),
|
91
103
|
"probseg_CSF": (
|
92
104
|
"derivatives/fmriprep/sub-{subject}/anat/"
|
93
105
|
"sub-{subject}_space-MNI152NLin2009cAsym_label-"
|
@@ -149,6 +161,8 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
|
|
149
161
|
new_task = f"{task}_acq-{acq}"
|
150
162
|
|
151
163
|
out = super().get_item(subject=subject, task=new_task)
|
164
|
+
out["BOLD"]["mask_item"] = "BOLD_mask"
|
165
|
+
out["T1w"]["mask_item"] = "T1w_mask"
|
152
166
|
return out
|
153
167
|
|
154
168
|
def get_elements(self) -> List:
|
@@ -7,7 +7,7 @@
|
|
7
7
|
# License: AGPL
|
8
8
|
|
9
9
|
from pathlib import Path
|
10
|
-
from typing import List, Union
|
10
|
+
from typing import List, Union, Dict
|
11
11
|
|
12
12
|
from junifer.datagrabber import PatternDataladDataGrabber
|
13
13
|
|
@@ -40,7 +40,9 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
|
|
40
40
|
types = [
|
41
41
|
"BOLD",
|
42
42
|
"BOLD_confounds",
|
43
|
+
"BOLD_mask",
|
43
44
|
"T1w",
|
45
|
+
"T1w_mask",
|
44
46
|
"probseg_CSF",
|
45
47
|
"probseg_GM",
|
46
48
|
"probseg_WM",
|
@@ -80,11 +82,21 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
|
|
80
82
|
"sub-{subject}_task-{task}_acq-seq_"
|
81
83
|
"desc-confounds_regressors.tsv"
|
82
84
|
),
|
85
|
+
"BOLD_mask": (
|
86
|
+
"derivatives/fmriprep/sub-{subject}/func/"
|
87
|
+
"sub-{subject}_task-{task}_acq-seq_space"
|
88
|
+
"-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
|
89
|
+
),
|
83
90
|
"T1w": (
|
84
91
|
"derivatives/fmriprep/sub-{subject}/anat/"
|
85
92
|
"sub-{subject}_space-MNI152NLin2009cAsym_"
|
86
93
|
"desc-preproc_T1w.nii.gz"
|
87
94
|
),
|
95
|
+
"T1w_mask": (
|
96
|
+
"derivatives/fmriprep/sub-{subject}/anat/"
|
97
|
+
"sub-{subject}_space-MNI152NLin2009cAsym_"
|
98
|
+
"desc-brain_mask.nii.gz"
|
99
|
+
),
|
88
100
|
"probseg_CSF": (
|
89
101
|
"derivatives/fmriprep/sub-{subject}/anat/"
|
90
102
|
"sub-{subject}_space-MNI152NLin2009cAsym_label-"
|
@@ -127,3 +139,25 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
|
|
127
139
|
"""
|
128
140
|
all_elements = super().get_elements()
|
129
141
|
return [x for x in all_elements if x[1] in self.tasks]
|
142
|
+
|
143
|
+
def get_item(self, subject: str, task: str) -> Dict:
|
144
|
+
"""Index one element in the dataset.
|
145
|
+
|
146
|
+
Parameters
|
147
|
+
----------
|
148
|
+
subject : str
|
149
|
+
The subject ID.
|
150
|
+
task : str
|
151
|
+
The task to get. Possible values are:
|
152
|
+
{"restingstate", "stopsignal", "emomatching", "workingmemory"}
|
153
|
+
|
154
|
+
Returns
|
155
|
+
-------
|
156
|
+
out : dict
|
157
|
+
Dictionary of paths for each type of data required for the
|
158
|
+
specified element.
|
159
|
+
"""
|
160
|
+
out = super().get_item(subject=subject, task=task)
|
161
|
+
out["BOLD"]["mask_item"] = "BOLD_mask"
|
162
|
+
out["T1w"]["mask_item"] = "T1w_mask"
|
163
|
+
return out
|
@@ -51,6 +51,9 @@ def test_aomic1000_datagrabber() -> None:
|
|
51
51
|
assert out["BOLD_confounds"]["path"].exists()
|
52
52
|
assert out["BOLD_confounds"]["path"].is_file()
|
53
53
|
|
54
|
+
# assert BOLD_mask
|
55
|
+
assert out["BOLD_mask"]["path"].exists()
|
56
|
+
|
54
57
|
# asserts type "T1w"
|
55
58
|
assert "T1w" in out
|
56
59
|
|
@@ -63,6 +66,9 @@ def test_aomic1000_datagrabber() -> None:
|
|
63
66
|
assert out["T1w"]["path"].exists()
|
64
67
|
assert out["T1w"]["path"].is_file()
|
65
68
|
|
69
|
+
# asserts T1w_mask
|
70
|
+
assert out["T1w_mask"]["path"].exists()
|
71
|
+
|
66
72
|
# asserts type "probseg_CSF"
|
67
73
|
assert "probseg_CSF" in out
|
68
74
|
|
@@ -66,6 +66,9 @@ def test_aomic_piop1_datagrabber() -> None:
|
|
66
66
|
assert out["BOLD_confounds"]["path"].exists()
|
67
67
|
assert out["BOLD_confounds"]["path"].is_file()
|
68
68
|
|
69
|
+
# assert BOLD_mask
|
70
|
+
assert out["BOLD_mask"]["path"].exists()
|
71
|
+
|
69
72
|
# asserts type "T1w"
|
70
73
|
assert "T1w" in out
|
71
74
|
|
@@ -78,6 +81,9 @@ def test_aomic_piop1_datagrabber() -> None:
|
|
78
81
|
assert out["T1w"]["path"].exists()
|
79
82
|
assert out["T1w"]["path"].is_file()
|
80
83
|
|
84
|
+
# asserts T1w_mask
|
85
|
+
assert out["T1w_mask"]["path"].exists()
|
86
|
+
|
81
87
|
# asserts type "probseg_CSF"
|
82
88
|
assert "probseg_CSF" in out
|
83
89
|
|
@@ -35,7 +35,6 @@ def test_aomic_piop2_datagrabber() -> None:
|
|
35
35
|
|
36
36
|
test_element = all_elements[0]
|
37
37
|
sub, task = test_element
|
38
|
-
|
39
38
|
out = dg[test_element]
|
40
39
|
|
41
40
|
# asserts type "BOLD"
|
@@ -62,6 +61,9 @@ def test_aomic_piop2_datagrabber() -> None:
|
|
62
61
|
assert out["BOLD_confounds"]["path"].exists()
|
63
62
|
assert out["BOLD_confounds"]["path"].is_file()
|
64
63
|
|
64
|
+
# assert BOLD_mask
|
65
|
+
assert out["BOLD_mask"]["path"].exists()
|
66
|
+
|
65
67
|
# asserts type "T1w"
|
66
68
|
assert "T1w" in out
|
67
69
|
|
@@ -74,6 +76,9 @@ def test_aomic_piop2_datagrabber() -> None:
|
|
74
76
|
assert out["T1w"]["path"].exists()
|
75
77
|
assert out["T1w"]["path"].is_file()
|
76
78
|
|
79
|
+
# asserts T1w_mask
|
80
|
+
assert out["T1w_mask"]["path"].exists()
|
81
|
+
|
77
82
|
# asserts type "probseg_CSF"
|
78
83
|
assert "probseg_CSF" in out
|
79
84
|
|