junifer 0.0.5.dev39__py3-none-any.whl → 0.0.5.dev48__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/api/functions.py +8 -6
- junifer/data/coordinates.py +1 -18
- junifer/data/masks.py +2 -65
- junifer/data/tests/test_masks.py +0 -8
- junifer/preprocess/__init__.py +0 -1
- {junifer-0.0.5.dev39.dist-info → junifer-0.0.5.dev48.dist-info}/METADATA +1 -1
- {junifer-0.0.5.dev39.dist-info → junifer-0.0.5.dev48.dist-info}/RECORD +13 -21
- junifer/preprocess/ants/__init__.py +0 -4
- junifer/preprocess/ants/ants_apply_transforms_warper.py +0 -185
- junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +0 -56
- junifer/preprocess/bold_warper.py +0 -265
- junifer/preprocess/fsl/__init__.py +0 -4
- junifer/preprocess/fsl/apply_warper.py +0 -179
- junifer/preprocess/fsl/tests/test_apply_warper.py +0 -45
- junifer/preprocess/tests/test_bold_warper.py +0 -159
- {junifer-0.0.5.dev39.dist-info → junifer-0.0.5.dev48.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dev39.dist-info → junifer-0.0.5.dev48.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.5.dev39.dist-info → junifer-0.0.5.dev48.dist-info}/WHEEL +0 -0
- {junifer-0.0.5.dev39.dist-info → junifer-0.0.5.dev48.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.5.dev39.dist-info → junifer-0.0.5.dev48.dist-info}/top_level.txt +0 -0
junifer/_version.py
CHANGED
@@ -12,5 +12,5 @@ __version__: str
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
13
13
|
version_tuple: VERSION_TUPLE
|
14
14
|
|
15
|
-
__version__ = version = '0.0.5.
|
16
|
-
__version_tuple__ = version_tuple = (0, 0, 5, '
|
15
|
+
__version__ = version = '0.0.5.dev48'
|
16
|
+
__version_tuple__ = version_tuple = (0, 0, 5, 'dev48')
|
junifer/api/functions.py
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
# License: AGPL
|
7
7
|
|
8
|
+
import os
|
8
9
|
import shutil
|
9
10
|
import typing
|
10
11
|
from pathlib import Path
|
@@ -339,12 +340,12 @@ def reset(config: Dict) -> None:
|
|
339
340
|
storage = config["storage"]
|
340
341
|
storage_uri = Path(storage["uri"])
|
341
342
|
logger.info(f"Deleting {storage_uri.resolve()!s}")
|
342
|
-
# Delete storage
|
343
|
+
# Delete storage
|
343
344
|
if storage_uri.exists():
|
344
|
-
# Delete files in the directory
|
345
|
-
for file in storage_uri.iterdir():
|
345
|
+
# Delete files in the job storage directory
|
346
|
+
for file in storage_uri.parent.iterdir():
|
346
347
|
file.unlink(missing_ok=True)
|
347
|
-
# Remove directory
|
348
|
+
# Remove job storage directory
|
348
349
|
storage_uri.parent.rmdir()
|
349
350
|
|
350
351
|
# Fetch job name (if present)
|
@@ -359,8 +360,9 @@ def reset(config: Dict) -> None:
|
|
359
360
|
if job_dir.exists():
|
360
361
|
# Remove files and directories
|
361
362
|
shutil.rmtree(job_dir)
|
362
|
-
# Remove directory
|
363
|
-
job_dir.parent
|
363
|
+
# Remove parent directory (if empty)
|
364
|
+
if not next(os.scandir(job_dir.parent), None):
|
365
|
+
job_dir.parent.rmdir()
|
364
366
|
|
365
367
|
|
366
368
|
def list_elements(
|
junifer/data/coordinates.py
CHANGED
@@ -13,7 +13,7 @@ import pandas as pd
|
|
13
13
|
from numpy.typing import ArrayLike
|
14
14
|
|
15
15
|
from ..pipeline import WorkDirManager
|
16
|
-
from ..utils import logger, raise_error, run_ext_cmd
|
16
|
+
from ..utils import logger, raise_error, run_ext_cmd
|
17
17
|
|
18
18
|
|
19
19
|
# Path to the VOIs
|
@@ -377,11 +377,6 @@ def load_coordinates(name: str) -> Tuple[ArrayLike, List[str], str]:
|
|
377
377
|
ValueError
|
378
378
|
If ``name`` is invalid.
|
379
379
|
|
380
|
-
Warns
|
381
|
-
-----
|
382
|
-
DeprecationWarning
|
383
|
-
If ``Power`` is provided as the ``name``.
|
384
|
-
|
385
380
|
"""
|
386
381
|
# Check for valid coordinates name
|
387
382
|
if name not in _available_coordinates:
|
@@ -389,18 +384,6 @@ def load_coordinates(name: str) -> Tuple[ArrayLike, List[str], str]:
|
|
389
384
|
f"Coordinates {name} not found. "
|
390
385
|
f"Valid options are: {list_coordinates()}"
|
391
386
|
)
|
392
|
-
|
393
|
-
# Put up deprecation notice
|
394
|
-
if name == "Power":
|
395
|
-
warn_with_log(
|
396
|
-
msg=(
|
397
|
-
"`Power` has been replaced with `Power2011` and will be "
|
398
|
-
"removed in the next release. For now, it's available for "
|
399
|
-
"backward compatibility."
|
400
|
-
),
|
401
|
-
category=DeprecationWarning,
|
402
|
-
)
|
403
|
-
|
404
387
|
# Load coordinates
|
405
388
|
t_coord = _available_coordinates[name]
|
406
389
|
if isinstance(t_coord.get("path"), Path):
|
junifer/data/masks.py
CHANGED
@@ -19,7 +19,6 @@ from typing import (
|
|
19
19
|
|
20
20
|
import nibabel as nib
|
21
21
|
import numpy as np
|
22
|
-
from nilearn.datasets import fetch_icbm152_brain_gm_mask
|
23
22
|
from nilearn.image import get_data, new_img_like, resample_to_img
|
24
23
|
from nilearn.masking import (
|
25
24
|
compute_background_mask,
|
@@ -28,7 +27,7 @@ from nilearn.masking import (
|
|
28
27
|
)
|
29
28
|
|
30
29
|
from ..pipeline import WorkDirManager
|
31
|
-
from ..utils import logger, raise_error, run_ext_cmd
|
30
|
+
from ..utils import logger, raise_error, run_ext_cmd
|
32
31
|
from .template_spaces import get_template, get_xfm
|
33
32
|
from .utils import closest_resolution
|
34
33
|
|
@@ -121,46 +120,6 @@ def compute_brain_mask(
|
|
121
120
|
return new_img_like(target_img, mask) # type: ignore
|
122
121
|
|
123
122
|
|
124
|
-
def _fetch_icbm152_brain_gm_mask(
|
125
|
-
target_img: "Nifti1Image",
|
126
|
-
**kwargs,
|
127
|
-
) -> "Nifti1Image":
|
128
|
-
"""Fetch ICBM152 brain mask and resample.
|
129
|
-
|
130
|
-
Parameters
|
131
|
-
----------
|
132
|
-
target_img : nibabel.Nifti1Image
|
133
|
-
The image to which the mask will be resampled.
|
134
|
-
**kwargs : dict
|
135
|
-
Keyword arguments to be passed to
|
136
|
-
:func:`nilearn.datasets.fetch_icbm152_brain_gm_mask`.
|
137
|
-
|
138
|
-
Returns
|
139
|
-
-------
|
140
|
-
nibabel.Nifti1Image
|
141
|
-
The resampled mask.
|
142
|
-
|
143
|
-
Warns
|
144
|
-
-----
|
145
|
-
DeprecationWarning
|
146
|
-
If this function is used.
|
147
|
-
|
148
|
-
"""
|
149
|
-
warn_with_log(
|
150
|
-
msg=(
|
151
|
-
"It is recommended to use ``compute_brain_mask`` with "
|
152
|
-
"``mask_type='gm'``. This function will be removed in the next "
|
153
|
-
"release. For now, it's available for backward compatibility."
|
154
|
-
),
|
155
|
-
category=DeprecationWarning,
|
156
|
-
)
|
157
|
-
mask = fetch_icbm152_brain_gm_mask(**kwargs)
|
158
|
-
mask = resample_to_img(
|
159
|
-
mask, target_img, interpolation="nearest", copy=True
|
160
|
-
)
|
161
|
-
return mask
|
162
|
-
|
163
|
-
|
164
123
|
# A dictionary containing all supported masks and their respective file or
|
165
124
|
# data.
|
166
125
|
|
@@ -194,11 +153,6 @@ _available_masks: Dict[str, Dict[str, Any]] = {
|
|
194
153
|
"func": compute_epi_mask,
|
195
154
|
"space": "inherit",
|
196
155
|
},
|
197
|
-
"fetch_icbm152_brain_gm_mask": {
|
198
|
-
"family": "Callable",
|
199
|
-
"func": _fetch_icbm152_brain_gm_mask,
|
200
|
-
"space": "MNI152NLin2009aAsym",
|
201
|
-
},
|
202
156
|
}
|
203
157
|
|
204
158
|
|
@@ -292,9 +246,7 @@ def get_mask( # noqa: C901
|
|
292
246
|
Raises
|
293
247
|
------
|
294
248
|
RuntimeError
|
295
|
-
If warp / transformation file extension is not ".mat" or ".h5"
|
296
|
-
if fetch_icbm152_brain_gm_mask is used and requires warping to
|
297
|
-
other template space.
|
249
|
+
If warp / transformation file extension is not ".mat" or ".h5".
|
298
250
|
ValueError
|
299
251
|
If extra key is provided in addition to mask name in ``masks`` or
|
300
252
|
if no mask is provided or
|
@@ -402,21 +354,6 @@ def get_mask( # noqa: C901
|
|
402
354
|
mask_img = extra_input[inherited_mask_item]["data"]
|
403
355
|
# Starting with new mask
|
404
356
|
else:
|
405
|
-
# Restrict fetch_icbm152_brain_gm_mask if target std space doesn't
|
406
|
-
# match
|
407
|
-
if (
|
408
|
-
mask_name == "fetch_icbm152_brain_gm_mask"
|
409
|
-
and target_std_space != "MNI152NLin2009aAsym"
|
410
|
-
):
|
411
|
-
raise_error(
|
412
|
-
(
|
413
|
-
"``fetch_icbm152_brain_gm_mask`` is deprecated and "
|
414
|
-
"space transformation to any other template space is "
|
415
|
-
"prohibited as it will lead to unforeseen errors. "
|
416
|
-
"``compute_brain_mask`` is a better alternative."
|
417
|
-
),
|
418
|
-
klass=RuntimeError,
|
419
|
-
)
|
420
357
|
# Load mask
|
421
358
|
mask_object, _, mask_space = load_mask(
|
422
359
|
mask_name, path_only=False, resolution=resolution
|
junifer/data/tests/test_masks.py
CHANGED
@@ -386,14 +386,6 @@ def test_get_mask_errors() -> None:
|
|
386
386
|
masks="inherit", target_data=vbm_gm, extra_input=extra_input
|
387
387
|
)
|
388
388
|
|
389
|
-
# Block fetch_icbm152_brain_gm_mask space transformation
|
390
|
-
with pytest.raises(RuntimeError, match="prohibited"):
|
391
|
-
get_mask(
|
392
|
-
masks="fetch_icbm152_brain_gm_mask",
|
393
|
-
target_data=vbm_gm,
|
394
|
-
extra_input=extra_input,
|
395
|
-
)
|
396
|
-
|
397
389
|
|
398
390
|
@pytest.mark.parametrize(
|
399
391
|
"mask_name,function,params,resample",
|
junifer/preprocess/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: junifer
|
3
|
-
Version: 0.0.5.
|
3
|
+
Version: 0.0.5.dev48
|
4
4
|
Summary: JUelich NeuroImaging FEature extractoR
|
5
5
|
Author-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
Maintainer-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
|
@@ -1,10 +1,10 @@
|
|
1
1
|
junifer/__init__.py,sha256=x1UR2jUcrUdm2HNl-3Qvyi4UUrU6ms5qm2qcmNY7zZk,391
|
2
|
-
junifer/_version.py,sha256=
|
2
|
+
junifer/_version.py,sha256=EyYigB7-PzZ_TCv16ateewbga35csyccbEi_liFHPpY,426
|
3
3
|
junifer/stats.py,sha256=jN22_qFvWYBU9ZIMnCSzN4iOscWnWrcrUPIdLeDkV64,6163
|
4
4
|
junifer/api/__init__.py,sha256=pSj8V8tmwOAQ3sshWJfRfB-n3z5bcJj3pHOBX4-8ONc,251
|
5
5
|
junifer/api/cli.py,sha256=wtU7Rv9tDIT-4KQAkG6WxiE6mop3cuz6XxGDewceHPs,15329
|
6
6
|
junifer/api/decorators.py,sha256=8bnwHPAe7VgzKxl--M_e0umdAlTVSzaJQHEJZ5kof5k,2580
|
7
|
-
junifer/api/functions.py,sha256=
|
7
|
+
junifer/api/functions.py,sha256=zCWLXDZ_cAqRZ5bFeky0KeqBztuoa6L3-djI65tqtpY,13055
|
8
8
|
junifer/api/parser.py,sha256=a3SSC2xO-PF1pqXZXFq8Sh9aVd-dmHolJbCkGyOUTAM,4416
|
9
9
|
junifer/api/utils.py,sha256=dyjTdPMwX9qeCrn8SQT2Pjshfnu-y1FEyujV7lCzvm0,3333
|
10
10
|
junifer/api/queue_context/__init__.py,sha256=_yXJ8woTxLNLoSR3yLxAW7MtC5sa-oCRxewsZ9D3j98,271
|
@@ -52,8 +52,8 @@ junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py,sha256=8jxpNZelXwpJG
|
|
52
52
|
junifer/configs/juseless/datagrabbers/tests/test_ucla.py,sha256=fFxllR0yvt7hiQYdSXJkl9_05UwemKfcp1vC6xf0X-U,3315
|
53
53
|
junifer/configs/juseless/datagrabbers/tests/test_ukb_vbm.py,sha256=b9hjc1mgO--PSRC3id2EzzfE2yWNsuZ2UI47a6sfGZU,1025
|
54
54
|
junifer/data/__init__.py,sha256=Z3CdIXpXK3Avxm2Qj7MsuNNZSM8Pc5KBa9D51DYd1v0,602
|
55
|
-
junifer/data/coordinates.py,sha256=
|
56
|
-
junifer/data/masks.py,sha256=
|
55
|
+
junifer/data/coordinates.py,sha256=AovvAdPhl9oQoH4T24jhzW0UuNL8wRYtkYrYHhvtRC8,12381
|
56
|
+
junifer/data/masks.py,sha256=x2vjMLRRGWt0fRGJ67_TjAdrrHZLE0VVnr3KizSbMnI,21427
|
57
57
|
junifer/data/parcellations.py,sha256=reNi0YdxP0sQYnB_tnxabP73FkvkdXXGsDLn68-hnfM,65225
|
58
58
|
junifer/data/template_spaces.py,sha256=2dD9GIBgsd764ol3ZvmHL11VrsaBC78CwrMaMh4TCGQ,5756
|
59
59
|
junifer/data/utils.py,sha256=Jmbc7SLzy4nLP_zkWv_aJzb1MZ27tutJ98ifsECCamM,1295
|
@@ -81,7 +81,7 @@ junifer/data/masks/vickery-patil/CAT12_IXI555_MNI152_TMP_GS_GMprob0.2_clean_3mm.
|
|
81
81
|
junifer/data/masks/vickery-patil/GMprob0.2_cortex_3mm_NA_rm.nii.gz,sha256=jfMe_4H9XEnArYms5bSQbqS2V1_HbLHTfI5amQa_Pes,8700
|
82
82
|
junifer/data/tests/test_coordinates.py,sha256=BNkz9qFbnwAI0oVlIm_XrT-z4Vsia_rMtMVaoFXT6mU,4328
|
83
83
|
junifer/data/tests/test_data_utils.py,sha256=_DaiC8K79gs9HFHxr-udNeE2YTM6JA0-1i-K2cqK9qA,1087
|
84
|
-
junifer/data/tests/test_masks.py,sha256=
|
84
|
+
junifer/data/tests/test_masks.py,sha256=JVg-9ZNkOGaATihLVxg0LAW4DJnvnhln7EJtB3glqLo,15878
|
85
85
|
junifer/data/tests/test_parcellations.py,sha256=ZEU1VHIK0AyxpclcJhG_0rQU0phaBU_dHP7Erfi3mN8,38222
|
86
86
|
junifer/data/tests/test_template_spaces.py,sha256=PJulN7xHpAcSOTY-UzTG_WPywZEBSlAZGiNG4gzk1_8,3144
|
87
87
|
junifer/datagrabber/__init__.py,sha256=fhHKsZyBeqCFJJMr53VF6EUkNrFuUZkNR8QZbaoHTNg,680
|
@@ -202,25 +202,17 @@ junifer/pipeline/tests/test_pipeline_step_mixin.py,sha256=_ykZzyNzREXy-r_yv1gY_j
|
|
202
202
|
junifer/pipeline/tests/test_registry.py,sha256=rYN0pO3gSueQ6XsasEM9VU5BkLyaNl8WaCZiaO8Rno0,4105
|
203
203
|
junifer/pipeline/tests/test_update_meta_mixin.py,sha256=UeWwpUi-Q5WVd36Fgfn_utXplSVXMSjLcdO2mR2xLTk,1355
|
204
204
|
junifer/pipeline/tests/test_workdir_manager.py,sha256=E1WY4C-GDsx2c49sePqr1WR_Y3nZ1kiRn4Veu506uTs,2801
|
205
|
-
junifer/preprocess/__init__.py,sha256=
|
205
|
+
junifer/preprocess/__init__.py,sha256=lpkT_mhsRjkmk676u-jWDMlPTp1Kdls-KLsXHrhiDyw,392
|
206
206
|
junifer/preprocess/base.py,sha256=Bn1VdonQ1f_DDPwFMpdaeyfLfNSnROulr-U8HuGQ81A,6697
|
207
|
-
junifer/preprocess/bold_warper.py,sha256=pEQ1GaWTV2Ili9WyqJgtq0PGHm4hNztXyY9ixoLNZnw,9060
|
208
|
-
junifer/preprocess/ants/__init__.py,sha256=Uobmbhh6_gOowkF2hQNSQOh3AYeaXzarBXEcLJzhERE,112
|
209
|
-
junifer/preprocess/ants/ants_apply_transforms_warper.py,sha256=1qkTq4NoW-c8CDEvh8j4uuN_HtneXSpG0mqRc6_qrNk,5556
|
210
|
-
junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py,sha256=IIwzo7iTFR2xy00S59ubXb0JSPukdPiRv6mdd25oeBA,1678
|
211
207
|
junifer/preprocess/confounds/__init__.py,sha256=EDlcD9jy8O9xluJr6XOnFXtjGCDVqwg6sDIRDMbM8ZU,235
|
212
208
|
junifer/preprocess/confounds/fmriprep_confound_remover.py,sha256=UN9B5P-Lqa5mA9jWi3gFJ7iBx1HSyfFrGuTZt4u4h1M,20841
|
213
209
|
junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py,sha256=noKP4YvghNzVvIRjDHnANCBFmbZiAKcDQG22dwqLvss,20757
|
214
|
-
junifer/preprocess/fsl/__init__.py,sha256=DerGFQ-dIuX5PT9a_BH6QkIXkJZVymjYy-woXF7tYGc,111
|
215
|
-
junifer/preprocess/fsl/apply_warper.py,sha256=k6ZzoDhXgsqcJZYYdx45Y3rN9xJERc02953_qhTqMtE,5144
|
216
|
-
junifer/preprocess/fsl/tests/test_apply_warper.py,sha256=eCrSPYIGTKFDiBtseZFkghjhU7j7np59TZeGdKHkhMs,1324
|
217
210
|
junifer/preprocess/smoothing/__init__.py,sha256=3l8nay8Zm_BIZLEj4CwmIye5-q7lQ_niGO_Cv4Hd21c,151
|
218
211
|
junifer/preprocess/smoothing/_afni_smoothing.py,sha256=FLJIrlYGxMT8rJdhV3LjALFIC9EPp902OuXt0FqAA_s,3266
|
219
212
|
junifer/preprocess/smoothing/_fsl_smoothing.py,sha256=ZBdP4VsaQEYD9JYUitAXSccwvP3GZ0FyqhriV8gJxyk,3035
|
220
213
|
junifer/preprocess/smoothing/_nilearn_smoothing.py,sha256=bshMj2DKEFkNiUbpaBoBfFFI6O80FIN49Oa3nc6FgaA,1928
|
221
214
|
junifer/preprocess/smoothing/smoothing.py,sha256=Bb9_0wvt1CfwzpxN_svPiQ2euOZkAT9S--4qr8omhyQ,5355
|
222
215
|
junifer/preprocess/smoothing/tests/test_smoothing.py,sha256=t1j3zEvJk5XLO4fzcb-wQyBMH-xuvR1k6WYm8zriwik,2390
|
223
|
-
junifer/preprocess/tests/test_bold_warper.py,sha256=U_r7DwPWoO_it1LIkhuQWBe20a-6X5c8o0AvTOnWKEc,4636
|
224
216
|
junifer/preprocess/tests/test_preprocess_base.py,sha256=-0rpe8QjqYES36H6MHuDs3cv_6upHBdVHnFMgQsmEX4,2571
|
225
217
|
junifer/preprocess/warping/__init__.py,sha256=zW4DVt_RPJWT0-AsylGmh9wgFBDPkU-hx4VzV_qPayU,154
|
226
218
|
junifer/preprocess/warping/_ants_warper.py,sha256=Y1UzZ5jy1TvlLEkaQKW7jCNvEHufZMdQFbg2JpY3UaM,5690
|
@@ -256,10 +248,10 @@ junifer/utils/logging.py,sha256=furcU3XIUpUvnpe4PEwzWWIWgmH4j2ZA4MQdvSGWjj0,9216
|
|
256
248
|
junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
|
257
249
|
junifer/utils/tests/test_helpers.py,sha256=k5qqfxK8dFyuewTJyR1Qn6-nFaYNuVr0ysc18bfPjyU,929
|
258
250
|
junifer/utils/tests/test_logging.py,sha256=l8oo-AiBV7H6_IzlsNcj__cLeZBUvgIGoaMszD9VaJg,7754
|
259
|
-
junifer-0.0.5.
|
260
|
-
junifer-0.0.5.
|
261
|
-
junifer-0.0.5.
|
262
|
-
junifer-0.0.5.
|
263
|
-
junifer-0.0.5.
|
264
|
-
junifer-0.0.5.
|
265
|
-
junifer-0.0.5.
|
251
|
+
junifer-0.0.5.dev48.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
|
252
|
+
junifer-0.0.5.dev48.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
|
253
|
+
junifer-0.0.5.dev48.dist-info/METADATA,sha256=HcvOlaAOoZhs_ipslMx8_9IRDL4aDzQSLgIp4d0zx6o,8234
|
254
|
+
junifer-0.0.5.dev48.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
255
|
+
junifer-0.0.5.dev48.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
|
256
|
+
junifer-0.0.5.dev48.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
|
257
|
+
junifer-0.0.5.dev48.dist-info/RECORD,,
|
@@ -1,185 +0,0 @@
|
|
1
|
-
"""Provide class for warping via ANTs antsApplyTransforms."""
|
2
|
-
|
3
|
-
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
-
# License: AGPL
|
5
|
-
|
6
|
-
from pathlib import Path
|
7
|
-
from typing import (
|
8
|
-
TYPE_CHECKING,
|
9
|
-
Any,
|
10
|
-
ClassVar,
|
11
|
-
Dict,
|
12
|
-
List,
|
13
|
-
Optional,
|
14
|
-
Tuple,
|
15
|
-
Union,
|
16
|
-
)
|
17
|
-
|
18
|
-
import nibabel as nib
|
19
|
-
import numpy as np
|
20
|
-
|
21
|
-
from ...pipeline import WorkDirManager
|
22
|
-
from ...utils import logger, raise_error, run_ext_cmd
|
23
|
-
|
24
|
-
|
25
|
-
if TYPE_CHECKING:
|
26
|
-
from nibabel import Nifti1Image
|
27
|
-
|
28
|
-
|
29
|
-
class _AntsApplyTransformsWarper:
|
30
|
-
"""Class for warping NIfTI images via ANTs antsApplyTransforms.
|
31
|
-
|
32
|
-
Warps ANTs ``antsApplyTransforms``.
|
33
|
-
|
34
|
-
Parameters
|
35
|
-
----------
|
36
|
-
reference : str
|
37
|
-
The data type to use as reference for warping.
|
38
|
-
on : str
|
39
|
-
The data type to use for warping.
|
40
|
-
|
41
|
-
Raises
|
42
|
-
------
|
43
|
-
ValueError
|
44
|
-
If a list was passed for ``on``.
|
45
|
-
|
46
|
-
"""
|
47
|
-
|
48
|
-
_EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
|
49
|
-
{
|
50
|
-
"name": "ants",
|
51
|
-
"commands": ["ResampleImage", "antsApplyTransforms"],
|
52
|
-
},
|
53
|
-
]
|
54
|
-
|
55
|
-
def __init__(self, reference: str, on: str) -> None:
|
56
|
-
"""Initialize the class."""
|
57
|
-
self.ref = reference
|
58
|
-
# Check only single data type is passed
|
59
|
-
if isinstance(on, list):
|
60
|
-
raise_error("Can only work on single data type, list was passed.")
|
61
|
-
self.on = on
|
62
|
-
|
63
|
-
def _run_apply_transforms(
|
64
|
-
self,
|
65
|
-
input_data: Dict,
|
66
|
-
ref_path: Path,
|
67
|
-
warp_path: Path,
|
68
|
-
) -> Tuple["Nifti1Image", Path]:
|
69
|
-
"""Run ``antsApplyTransforms``.
|
70
|
-
|
71
|
-
Parameters
|
72
|
-
----------
|
73
|
-
input_data : dict
|
74
|
-
The input data.
|
75
|
-
ref_path : pathlib.Path
|
76
|
-
The path to the reference file.
|
77
|
-
warp_path : pathlib.Path
|
78
|
-
The path to the warp file.
|
79
|
-
|
80
|
-
Returns
|
81
|
-
-------
|
82
|
-
Niimg-like object
|
83
|
-
The warped input image.
|
84
|
-
pathlib.Path
|
85
|
-
The path to the resampled reference image.
|
86
|
-
|
87
|
-
"""
|
88
|
-
# Get the min of the voxel sizes from input and use it as the
|
89
|
-
# resolution
|
90
|
-
resolution = np.min(input_data["data"].header.get_zooms()[:3])
|
91
|
-
|
92
|
-
# Create element-specific tempdir for storing post-warping assets
|
93
|
-
tempdir = WorkDirManager().get_element_tempdir(
|
94
|
-
prefix="applytransforms"
|
95
|
-
)
|
96
|
-
|
97
|
-
# Create a tempfile for resampled reference output
|
98
|
-
resample_image_out_path = tempdir / "reference_resampled.nii.gz"
|
99
|
-
# Set ResampleImage command
|
100
|
-
resample_image_cmd = [
|
101
|
-
"ResampleImage",
|
102
|
-
"3", # image dimension
|
103
|
-
f"{ref_path.resolve()}",
|
104
|
-
f"{resample_image_out_path.resolve()}",
|
105
|
-
f"{resolution}x{resolution}x{resolution}",
|
106
|
-
"0", # option for spacing and not size
|
107
|
-
"3 3", # Lanczos windowed sinc
|
108
|
-
]
|
109
|
-
# Call ResampleImage
|
110
|
-
run_ext_cmd(name="ResampleImage", cmd=resample_image_cmd)
|
111
|
-
|
112
|
-
# Create a tempfile for warped output
|
113
|
-
apply_transforms_out_path = tempdir / "input_warped.nii.gz"
|
114
|
-
# Set antsApplyTransforms command
|
115
|
-
apply_transforms_cmd = [
|
116
|
-
"antsApplyTransforms",
|
117
|
-
"-d 3",
|
118
|
-
"-e 3",
|
119
|
-
"-n LanczosWindowedSinc",
|
120
|
-
f"-i {input_data['path'].resolve()}",
|
121
|
-
# use resampled reference
|
122
|
-
f"-r {resample_image_out_path.resolve()}",
|
123
|
-
f"-t {warp_path.resolve()}",
|
124
|
-
f"-o {apply_transforms_out_path.resolve()}",
|
125
|
-
]
|
126
|
-
# Call antsApplyTransforms
|
127
|
-
run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
|
128
|
-
|
129
|
-
# Load nifti
|
130
|
-
output_img = nib.load(apply_transforms_out_path)
|
131
|
-
|
132
|
-
return output_img, resample_image_out_path # type: ignore
|
133
|
-
|
134
|
-
def preprocess(
|
135
|
-
self,
|
136
|
-
input: Dict[str, Any],
|
137
|
-
extra_input: Optional[Dict[str, Any]] = None,
|
138
|
-
) -> Tuple[str, Dict[str, Any]]:
|
139
|
-
"""Preprocess.
|
140
|
-
|
141
|
-
Parameters
|
142
|
-
----------
|
143
|
-
input : dict
|
144
|
-
A single input from the Junifer Data object in which to preprocess.
|
145
|
-
extra_input : dict, optional
|
146
|
-
The other fields in the Junifer Data object. Must include the
|
147
|
-
``Warp`` and ``ref`` value's keys.
|
148
|
-
|
149
|
-
Returns
|
150
|
-
-------
|
151
|
-
str
|
152
|
-
The key to store the output in the Junifer Data object.
|
153
|
-
dict
|
154
|
-
The computed result as dictionary. This will be stored in the
|
155
|
-
Junifer Data object under the key ``data`` of the data type.
|
156
|
-
|
157
|
-
Raises
|
158
|
-
------
|
159
|
-
ValueError
|
160
|
-
If ``extra_input`` is None.
|
161
|
-
|
162
|
-
"""
|
163
|
-
logger.debug("Warping via ANTs using antsApplyTransforms")
|
164
|
-
# Check for extra inputs
|
165
|
-
if extra_input is None:
|
166
|
-
raise_error(
|
167
|
-
f"No extra input provided, requires `Warp` and `{self.ref}` "
|
168
|
-
"data types in particular."
|
169
|
-
)
|
170
|
-
# Retrieve data type info to warp
|
171
|
-
to_warp_input = input
|
172
|
-
# Retrieve data type info to use as reference
|
173
|
-
ref_input = extra_input[self.ref]
|
174
|
-
# Retrieve Warp data
|
175
|
-
warp = extra_input["Warp"]
|
176
|
-
# Replace original data with warped data and add resampled reference
|
177
|
-
# path
|
178
|
-
input["data"], input["reference_path"] = self._run_apply_transforms(
|
179
|
-
input_data=to_warp_input,
|
180
|
-
ref_path=ref_input["path"],
|
181
|
-
warp_path=warp["path"],
|
182
|
-
)
|
183
|
-
# Use reference input's space as warped input's space
|
184
|
-
input["space"] = ref_input["space"]
|
185
|
-
return self.on, input
|
@@ -1,56 +0,0 @@
|
|
1
|
-
"""Provide tests for AntsApplyTransformsWarper."""
|
2
|
-
|
3
|
-
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
-
# License: AGPL
|
5
|
-
|
6
|
-
import socket
|
7
|
-
|
8
|
-
import pytest
|
9
|
-
|
10
|
-
from junifer.datagrabber import DMCC13Benchmark
|
11
|
-
from junifer.datareader import DefaultDataReader
|
12
|
-
from junifer.pipeline.utils import _check_ants
|
13
|
-
from junifer.preprocess.ants.ants_apply_transforms_warper import (
|
14
|
-
_AntsApplyTransformsWarper,
|
15
|
-
)
|
16
|
-
|
17
|
-
|
18
|
-
def test_AntsApplyTransformsWarper_init() -> None:
|
19
|
-
"""Test AntsApplyTransformsWarper init."""
|
20
|
-
ants_apply_transforms_warper = _AntsApplyTransformsWarper(
|
21
|
-
reference="T1w", on="BOLD"
|
22
|
-
)
|
23
|
-
assert ants_apply_transforms_warper.ref == "T1w"
|
24
|
-
assert ants_apply_transforms_warper.on == "BOLD"
|
25
|
-
|
26
|
-
|
27
|
-
@pytest.mark.skipif(
|
28
|
-
_check_ants() is False, reason="requires ANTs to be in PATH"
|
29
|
-
)
|
30
|
-
@pytest.mark.skipif(
|
31
|
-
socket.gethostname() != "juseless",
|
32
|
-
reason="only for juseless",
|
33
|
-
)
|
34
|
-
def test_AntsApplyTransformsWarper_preprocess() -> None:
|
35
|
-
"""Test AntsApplyTransformsWarper preprocess."""
|
36
|
-
with DMCC13Benchmark(
|
37
|
-
types=["BOLD", "T1w", "Warp"],
|
38
|
-
sessions=["ses-wave1bas"],
|
39
|
-
tasks=["Rest"],
|
40
|
-
phase_encodings=["AP"],
|
41
|
-
runs=["1"],
|
42
|
-
native_t1w=True,
|
43
|
-
) as dg:
|
44
|
-
# Read data
|
45
|
-
element_data = DefaultDataReader().fit_transform(
|
46
|
-
dg[("sub-f9057kp", "ses-wave1bas", "Rest", "AP", "1")]
|
47
|
-
)
|
48
|
-
# Preprocess data
|
49
|
-
data_type, data = _AntsApplyTransformsWarper(
|
50
|
-
reference="T1w", on="BOLD"
|
51
|
-
).preprocess(
|
52
|
-
input=element_data["BOLD"],
|
53
|
-
extra_input=element_data,
|
54
|
-
)
|
55
|
-
assert isinstance(data_type, str)
|
56
|
-
assert isinstance(data, dict)
|
@@ -1,265 +0,0 @@
|
|
1
|
-
"""Provide class for warping BOLD to other template spaces."""
|
2
|
-
|
3
|
-
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
-
# License: AGPL
|
5
|
-
|
6
|
-
from typing import (
|
7
|
-
Any,
|
8
|
-
ClassVar,
|
9
|
-
Dict,
|
10
|
-
List,
|
11
|
-
Optional,
|
12
|
-
Tuple,
|
13
|
-
Type,
|
14
|
-
Union,
|
15
|
-
)
|
16
|
-
|
17
|
-
import nibabel as nib
|
18
|
-
from templateflow import api as tflow
|
19
|
-
|
20
|
-
from ..api.decorators import register_preprocessor
|
21
|
-
from ..data import get_template, get_xfm
|
22
|
-
from ..pipeline import WorkDirManager
|
23
|
-
from ..utils import logger, raise_error, run_ext_cmd
|
24
|
-
from .ants.ants_apply_transforms_warper import _AntsApplyTransformsWarper
|
25
|
-
from .base import BasePreprocessor
|
26
|
-
from .fsl.apply_warper import _ApplyWarper
|
27
|
-
|
28
|
-
|
29
|
-
@register_preprocessor
|
30
|
-
class BOLDWarper(BasePreprocessor):
|
31
|
-
"""Class for warping BOLD NIfTI images.
|
32
|
-
|
33
|
-
.. deprecated:: 0.0.3
|
34
|
-
`BOLDWarper` will be removed in v0.0.4, it is replaced by
|
35
|
-
`SpaceWarper` because the latter works also with T1w data.
|
36
|
-
|
37
|
-
Parameters
|
38
|
-
----------
|
39
|
-
using : {"fsl", "ants"}
|
40
|
-
Implementation to use for warping:
|
41
|
-
|
42
|
-
* "fsl" : Use FSL's ``applywarp``
|
43
|
-
* "afni" : Use ANTs' ``antsApplyTransforms``
|
44
|
-
|
45
|
-
reference : str
|
46
|
-
The data type to use as reference for warping, can be either a data
|
47
|
-
type like "T1w" or a template space like "MNI152NLin2009cAsym".
|
48
|
-
|
49
|
-
Raises
|
50
|
-
------
|
51
|
-
ValueError
|
52
|
-
If ``using`` is invalid or
|
53
|
-
if ``reference`` is invalid.
|
54
|
-
|
55
|
-
Notes
|
56
|
-
-----
|
57
|
-
If you are setting ``reference`` to a template space like
|
58
|
-
"MNI152NLin2009cAsym", make sure ANTs is available for the
|
59
|
-
transformation else it will fail during runtime. It is tricky to validate
|
60
|
-
this beforehand and difficult to enforce this as a requirement, hence the
|
61
|
-
heads-up.
|
62
|
-
|
63
|
-
"""
|
64
|
-
|
65
|
-
_CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [
|
66
|
-
{
|
67
|
-
"using": "fsl",
|
68
|
-
"depends_on": _ApplyWarper,
|
69
|
-
},
|
70
|
-
{
|
71
|
-
"using": "ants",
|
72
|
-
"depends_on": _AntsApplyTransformsWarper,
|
73
|
-
},
|
74
|
-
]
|
75
|
-
|
76
|
-
def __init__(self, using: str, reference: str) -> None:
|
77
|
-
"""Initialize the class."""
|
78
|
-
# Validate `using` parameter
|
79
|
-
valid_using = [dep["using"] for dep in self._CONDITIONAL_DEPENDENCIES]
|
80
|
-
if using not in valid_using:
|
81
|
-
raise_error(
|
82
|
-
f"Invalid value for `using`, should be one of: {valid_using}"
|
83
|
-
)
|
84
|
-
self.using = using
|
85
|
-
self.ref = reference
|
86
|
-
# Initialize superclass based on reference
|
87
|
-
if self.ref == "T1w":
|
88
|
-
super().__init__(
|
89
|
-
on="BOLD", required_data_types=["BOLD", self.ref, "Warp"]
|
90
|
-
)
|
91
|
-
elif self.ref in tflow.templates():
|
92
|
-
super().__init__(on="BOLD", required_data_types=["BOLD"])
|
93
|
-
else:
|
94
|
-
raise_error(f"Unknown reference: {self.ref}")
|
95
|
-
|
96
|
-
def get_valid_inputs(self) -> List[str]:
|
97
|
-
"""Get valid data types for input.
|
98
|
-
|
99
|
-
Returns
|
100
|
-
-------
|
101
|
-
list of str
|
102
|
-
The list of data types that can be used as input for this
|
103
|
-
preprocessor.
|
104
|
-
|
105
|
-
"""
|
106
|
-
return ["BOLD"]
|
107
|
-
|
108
|
-
def get_output_type(self, input_type: str) -> str:
|
109
|
-
"""Get output type.
|
110
|
-
|
111
|
-
Parameters
|
112
|
-
----------
|
113
|
-
input_type : str
|
114
|
-
The data type input to the preprocessor.
|
115
|
-
|
116
|
-
Returns
|
117
|
-
-------
|
118
|
-
str
|
119
|
-
The data type output by the preprocessor.
|
120
|
-
|
121
|
-
"""
|
122
|
-
# Does not add any new keys
|
123
|
-
return input_type
|
124
|
-
|
125
|
-
def preprocess(
|
126
|
-
self,
|
127
|
-
input: Dict[str, Any],
|
128
|
-
extra_input: Optional[Dict[str, Any]] = None,
|
129
|
-
) -> Tuple[Dict[str, Any], Optional[Dict[str, Dict[str, Any]]]]:
|
130
|
-
"""Preprocess.
|
131
|
-
|
132
|
-
Parameters
|
133
|
-
----------
|
134
|
-
input : dict
|
135
|
-
The BOLD input from the Junifer Data object.
|
136
|
-
extra_input : dict, optional
|
137
|
-
The other fields in the Junifer Data object. Must include the
|
138
|
-
``Warp`` and ``ref`` value's keys if native space transformation is
|
139
|
-
needed.
|
140
|
-
|
141
|
-
Returns
|
142
|
-
-------
|
143
|
-
dict
|
144
|
-
The computed result as dictionary.
|
145
|
-
None
|
146
|
-
Extra "helper" data types as dictionary to add to the Junifer Data
|
147
|
-
object.
|
148
|
-
|
149
|
-
Raises
|
150
|
-
------
|
151
|
-
ValueError
|
152
|
-
If ``extra_input`` is None when transforming to native space
|
153
|
-
i.e., using "T1w" as reference.
|
154
|
-
RuntimeError
|
155
|
-
If warp / transformation file extension is not ".mat" or ".h5"
|
156
|
-
when transforming to native space or
|
157
|
-
if the BOLD data is in the correct space and does not require
|
158
|
-
warping.
|
159
|
-
|
160
|
-
"""
|
161
|
-
logger.info(f"Warping BOLD to {self.ref} space using BOLDWarper")
|
162
|
-
# Transform to native space
|
163
|
-
if self.ref == "T1w":
|
164
|
-
# Check for extra inputs
|
165
|
-
if extra_input is None:
|
166
|
-
raise_error(
|
167
|
-
"No extra input provided, requires `Warp` and "
|
168
|
-
f"`{self.ref}` data types in particular."
|
169
|
-
)
|
170
|
-
# Check for warp file type to use correct tool
|
171
|
-
warp_file_ext = extra_input["Warp"]["path"].suffix
|
172
|
-
if warp_file_ext == ".mat":
|
173
|
-
logger.debug("Using FSL with BOLDWarper")
|
174
|
-
# Initialize ApplyWarper for computation
|
175
|
-
apply_warper = _ApplyWarper(reference=self.ref, on="BOLD")
|
176
|
-
# Replace original BOLD data with warped BOLD data
|
177
|
-
_, input = apply_warper.preprocess(
|
178
|
-
input=input,
|
179
|
-
extra_input=extra_input,
|
180
|
-
)
|
181
|
-
elif warp_file_ext == ".h5":
|
182
|
-
logger.debug("Using ANTs with BOLDWarper")
|
183
|
-
# Initialize AntsApplyTransformsWarper for computation
|
184
|
-
ants_apply_transforms_warper = _AntsApplyTransformsWarper(
|
185
|
-
reference=self.ref, on="BOLD"
|
186
|
-
)
|
187
|
-
# Replace original BOLD data with warped BOLD data
|
188
|
-
_, input = ants_apply_transforms_warper.preprocess(
|
189
|
-
input=input,
|
190
|
-
extra_input=extra_input,
|
191
|
-
)
|
192
|
-
else:
|
193
|
-
raise_error(
|
194
|
-
msg=(
|
195
|
-
"Unknown warp / transformation file extension: "
|
196
|
-
f"{warp_file_ext}"
|
197
|
-
),
|
198
|
-
klass=RuntimeError,
|
199
|
-
)
|
200
|
-
# Transform to template space
|
201
|
-
else:
|
202
|
-
# Check pre-requirements for space manipulation
|
203
|
-
if self.ref == input["space"]:
|
204
|
-
raise_error(
|
205
|
-
(
|
206
|
-
f"Skipped warping as the BOLD data is in {self.ref} "
|
207
|
-
"space which would mean that you can remove the "
|
208
|
-
"BOLDWarper from the preprocess step."
|
209
|
-
),
|
210
|
-
klass=RuntimeError,
|
211
|
-
)
|
212
|
-
else:
|
213
|
-
# Get xfm file
|
214
|
-
xfm_file_path = get_xfm(src=input["space"], dst=self.ref)
|
215
|
-
# Get template space image
|
216
|
-
template_space_img = get_template(
|
217
|
-
space=self.ref,
|
218
|
-
target_data=input,
|
219
|
-
extra_input=None,
|
220
|
-
)
|
221
|
-
|
222
|
-
# Create component-scoped tempdir
|
223
|
-
tempdir = WorkDirManager().get_tempdir(prefix="boldwarper")
|
224
|
-
# Create element-scoped tempdir so that warped BOLD is
|
225
|
-
# available later as nibabel stores file path reference for
|
226
|
-
# loading on computation
|
227
|
-
element_tempdir = WorkDirManager().get_element_tempdir(
|
228
|
-
prefix="boldwarper"
|
229
|
-
)
|
230
|
-
|
231
|
-
# Save template
|
232
|
-
template_space_img_path = tempdir / f"{self.ref}_T1w.nii.gz"
|
233
|
-
nib.save(template_space_img, template_space_img_path)
|
234
|
-
|
235
|
-
# Create a tempfile for warped output
|
236
|
-
warped_bold_path = (
|
237
|
-
element_tempdir
|
238
|
-
/ f"bold_warped_from_{input['space']}_to_{self.ref}.nii.gz"
|
239
|
-
)
|
240
|
-
|
241
|
-
logger.debug(
|
242
|
-
f"Using ANTs to warp BOLD "
|
243
|
-
f"from {input['space']} to {self.ref}"
|
244
|
-
)
|
245
|
-
# Set antsApplyTransforms command
|
246
|
-
apply_transforms_cmd = [
|
247
|
-
"antsApplyTransforms",
|
248
|
-
"-d 3",
|
249
|
-
"-e 3",
|
250
|
-
"-n LanczosWindowedSinc",
|
251
|
-
f"-i {input['path'].resolve()}",
|
252
|
-
f"-r {template_space_img_path.resolve()}",
|
253
|
-
f"-t {xfm_file_path.resolve()}",
|
254
|
-
f"-o {warped_bold_path.resolve()}",
|
255
|
-
]
|
256
|
-
# Call antsApplyTransforms
|
257
|
-
run_ext_cmd(
|
258
|
-
name="antsApplyTransforms", cmd=apply_transforms_cmd
|
259
|
-
)
|
260
|
-
|
261
|
-
# Modify target data
|
262
|
-
input["data"] = nib.load(warped_bold_path)
|
263
|
-
input["space"] = self.ref
|
264
|
-
|
265
|
-
return input, None
|
@@ -1,179 +0,0 @@
|
|
1
|
-
"""Provide class for warping via FSL FLIRT."""
|
2
|
-
|
3
|
-
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
-
# License: AGPL
|
5
|
-
|
6
|
-
from pathlib import Path
|
7
|
-
from typing import (
|
8
|
-
TYPE_CHECKING,
|
9
|
-
Any,
|
10
|
-
ClassVar,
|
11
|
-
Dict,
|
12
|
-
List,
|
13
|
-
Optional,
|
14
|
-
Tuple,
|
15
|
-
Union,
|
16
|
-
)
|
17
|
-
|
18
|
-
import nibabel as nib
|
19
|
-
import numpy as np
|
20
|
-
|
21
|
-
from ...pipeline import WorkDirManager
|
22
|
-
from ...utils import logger, raise_error, run_ext_cmd
|
23
|
-
|
24
|
-
|
25
|
-
if TYPE_CHECKING:
|
26
|
-
from nibabel import Nifti1Image
|
27
|
-
|
28
|
-
|
29
|
-
class _ApplyWarper:
|
30
|
-
"""Class for warping NIfTI images via FSL FLIRT.
|
31
|
-
|
32
|
-
Wraps FSL FLIRT ``applywarp``.
|
33
|
-
|
34
|
-
Parameters
|
35
|
-
----------
|
36
|
-
reference : str
|
37
|
-
The data type to use as reference for warping.
|
38
|
-
on : str
|
39
|
-
The data type to use for warping.
|
40
|
-
|
41
|
-
Raises
|
42
|
-
------
|
43
|
-
ValueError
|
44
|
-
If a list was passed for ``on``.
|
45
|
-
|
46
|
-
"""
|
47
|
-
|
48
|
-
_EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
|
49
|
-
{
|
50
|
-
"name": "fsl",
|
51
|
-
"commands": ["flirt", "applywarp"],
|
52
|
-
},
|
53
|
-
]
|
54
|
-
|
55
|
-
def __init__(self, reference: str, on: str) -> None:
|
56
|
-
"""Initialize the class."""
|
57
|
-
self.ref = reference
|
58
|
-
# Check only single data type is passed
|
59
|
-
if isinstance(on, list):
|
60
|
-
raise_error("Can only work on single data type, list was passed.")
|
61
|
-
self.on = on
|
62
|
-
|
63
|
-
def _run_applywarp(
|
64
|
-
self,
|
65
|
-
input_data: Dict,
|
66
|
-
ref_path: Path,
|
67
|
-
warp_path: Path,
|
68
|
-
) -> Tuple["Nifti1Image", Path]:
|
69
|
-
"""Run ``applywarp``.
|
70
|
-
|
71
|
-
Parameters
|
72
|
-
----------
|
73
|
-
input_data : dict
|
74
|
-
The input data.
|
75
|
-
ref_path : pathlib.Path
|
76
|
-
The path to the reference file.
|
77
|
-
warp_path : pathlib.Path
|
78
|
-
The path to the warp file.
|
79
|
-
|
80
|
-
Returns
|
81
|
-
-------
|
82
|
-
Niimg-like object
|
83
|
-
The warped input image.
|
84
|
-
pathlib.Path
|
85
|
-
The path to the resampled reference image.
|
86
|
-
|
87
|
-
"""
|
88
|
-
# Get the min of the voxel sizes from input and use it as the
|
89
|
-
# resolution
|
90
|
-
resolution = np.min(input_data["data"].header.get_zooms()[:3])
|
91
|
-
|
92
|
-
# Create element-specific tempdir for storing post-warping assets
|
93
|
-
tempdir = WorkDirManager().get_element_tempdir(prefix="applywarp")
|
94
|
-
|
95
|
-
# Create a tempfile for resampled reference output
|
96
|
-
flirt_out_path = tempdir / "reference_resampled.nii.gz"
|
97
|
-
# Set flirt command
|
98
|
-
flirt_cmd = [
|
99
|
-
"flirt",
|
100
|
-
"-interp spline",
|
101
|
-
f"-in {ref_path.resolve()}",
|
102
|
-
f"-ref {ref_path.resolve()}",
|
103
|
-
f"-applyisoxfm {resolution}",
|
104
|
-
f"-out {flirt_out_path.resolve()}",
|
105
|
-
]
|
106
|
-
# Call flirt
|
107
|
-
run_ext_cmd(name="flirt", cmd=flirt_cmd)
|
108
|
-
|
109
|
-
# Create a tempfile for warped output
|
110
|
-
applywarp_out_path = tempdir / "input_warped.nii.gz"
|
111
|
-
# Set applywarp command
|
112
|
-
applywarp_cmd = [
|
113
|
-
"applywarp",
|
114
|
-
"--interp=spline",
|
115
|
-
f"-i {input_data['path'].resolve()}",
|
116
|
-
f"-r {flirt_out_path.resolve()}", # use resampled reference
|
117
|
-
f"-w {warp_path.resolve()}",
|
118
|
-
f"-o {applywarp_out_path.resolve()}",
|
119
|
-
]
|
120
|
-
# Call applywarp
|
121
|
-
run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
|
122
|
-
|
123
|
-
# Load nifti
|
124
|
-
output_img = nib.load(applywarp_out_path)
|
125
|
-
|
126
|
-
return output_img, flirt_out_path # type: ignore
|
127
|
-
|
128
|
-
def preprocess(
|
129
|
-
self,
|
130
|
-
input: Dict[str, Any],
|
131
|
-
extra_input: Optional[Dict[str, Any]] = None,
|
132
|
-
) -> Tuple[str, Dict[str, Any]]:
|
133
|
-
"""Preprocess.
|
134
|
-
|
135
|
-
Parameters
|
136
|
-
----------
|
137
|
-
input : dict
|
138
|
-
A single input from the Junifer Data object in which to preprocess.
|
139
|
-
extra_input : dict, optional
|
140
|
-
The other fields in the Junifer Data object. Must include the
|
141
|
-
``Warp`` and ``ref`` value's keys.
|
142
|
-
|
143
|
-
Returns
|
144
|
-
-------
|
145
|
-
str
|
146
|
-
The key to store the output in the Junifer Data object.
|
147
|
-
dict
|
148
|
-
The computed result as dictionary. This will be stored in the
|
149
|
-
Junifer Data object under the key ``data`` of the data type.
|
150
|
-
|
151
|
-
Raises
|
152
|
-
------
|
153
|
-
ValueError
|
154
|
-
If ``extra_input`` is None.
|
155
|
-
|
156
|
-
"""
|
157
|
-
logger.debug("Warping via FSL using ApplyWarper")
|
158
|
-
# Check for extra inputs
|
159
|
-
if extra_input is None:
|
160
|
-
raise_error(
|
161
|
-
f"No extra input provided, requires `Warp` and `{self.ref}` "
|
162
|
-
"data types in particular."
|
163
|
-
)
|
164
|
-
# Retrieve data type info to warp
|
165
|
-
to_warp_input = input
|
166
|
-
# Retrieve data type info to use as reference
|
167
|
-
ref_input = extra_input[self.ref]
|
168
|
-
# Retrieve Warp data
|
169
|
-
warp = extra_input["Warp"]
|
170
|
-
# Replace original data with warped data and add resampled reference
|
171
|
-
# path
|
172
|
-
input["data"], input["reference_path"] = self._run_applywarp(
|
173
|
-
input_data=to_warp_input,
|
174
|
-
ref_path=ref_input["path"],
|
175
|
-
warp_path=warp["path"],
|
176
|
-
)
|
177
|
-
# Use reference input's space as warped input's space
|
178
|
-
input["space"] = ref_input["space"]
|
179
|
-
return self.on, input
|
@@ -1,45 +0,0 @@
|
|
1
|
-
"""Provide tests for ApplyWarper."""
|
2
|
-
|
3
|
-
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
-
# License: AGPL
|
5
|
-
|
6
|
-
import socket
|
7
|
-
|
8
|
-
import pytest
|
9
|
-
|
10
|
-
from junifer.datagrabber import DataladHCP1200
|
11
|
-
from junifer.datareader import DefaultDataReader
|
12
|
-
from junifer.pipeline.utils import _check_fsl
|
13
|
-
from junifer.preprocess.fsl.apply_warper import _ApplyWarper
|
14
|
-
|
15
|
-
|
16
|
-
def test_ApplyWarper_init() -> None:
|
17
|
-
"""Test ApplyWarper init."""
|
18
|
-
apply_warper = _ApplyWarper(reference="T1w", on="BOLD")
|
19
|
-
assert apply_warper.ref == "T1w"
|
20
|
-
assert apply_warper.on == "BOLD"
|
21
|
-
|
22
|
-
|
23
|
-
@pytest.mark.skipif(_check_fsl() is False, reason="requires FSL to be in PATH")
|
24
|
-
@pytest.mark.skipif(
|
25
|
-
socket.gethostname() != "juseless",
|
26
|
-
reason="only for juseless",
|
27
|
-
)
|
28
|
-
def test_ApplyWarper_preprocess() -> None:
|
29
|
-
"""Test ApplyWarper preprocess."""
|
30
|
-
with DataladHCP1200(
|
31
|
-
tasks=["REST1"],
|
32
|
-
phase_encodings=["LR"],
|
33
|
-
ica_fix=True,
|
34
|
-
) as dg:
|
35
|
-
# Read data
|
36
|
-
element_data = DefaultDataReader().fit_transform(
|
37
|
-
dg[("100206", "REST1", "LR")]
|
38
|
-
)
|
39
|
-
# Preprocess data
|
40
|
-
data_type, data = _ApplyWarper(reference="T1w", on="BOLD").preprocess(
|
41
|
-
input=element_data["BOLD"],
|
42
|
-
extra_input=element_data,
|
43
|
-
)
|
44
|
-
assert isinstance(data_type, str)
|
45
|
-
assert isinstance(data, dict)
|
@@ -1,159 +0,0 @@
|
|
1
|
-
"""Provide tests for BOLDWarper."""
|
2
|
-
|
3
|
-
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
-
# License: AGPL
|
5
|
-
|
6
|
-
import socket
|
7
|
-
from typing import TYPE_CHECKING, Tuple
|
8
|
-
|
9
|
-
import pytest
|
10
|
-
from numpy.testing import assert_array_equal, assert_raises
|
11
|
-
|
12
|
-
from junifer.datagrabber import DataladHCP1200, DMCC13Benchmark
|
13
|
-
from junifer.datareader import DefaultDataReader
|
14
|
-
from junifer.pipeline.utils import _check_ants, _check_fsl
|
15
|
-
from junifer.preprocess import BOLDWarper
|
16
|
-
|
17
|
-
|
18
|
-
if TYPE_CHECKING:
|
19
|
-
from junifer.datagrabber import BaseDataGrabber
|
20
|
-
|
21
|
-
|
22
|
-
def test_BOLDWarper_init() -> None:
|
23
|
-
"""Test BOLDWarper init."""
|
24
|
-
bold_warper = BOLDWarper(using="ants", reference="T1w")
|
25
|
-
assert bold_warper._on == ["BOLD"]
|
26
|
-
|
27
|
-
|
28
|
-
def test_BOLDWarper_get_valid_inputs() -> None:
|
29
|
-
"""Test BOLDWarper get_valid_inputs."""
|
30
|
-
bold_warper = BOLDWarper(using="ants", reference="T1w")
|
31
|
-
assert bold_warper.get_valid_inputs() == ["BOLD"]
|
32
|
-
|
33
|
-
|
34
|
-
def test_BOLDWarper_get_output_type() -> None:
|
35
|
-
"""Test BOLDWarper get_output_type."""
|
36
|
-
bold_warper = BOLDWarper(using="ants", reference="T1w")
|
37
|
-
assert bold_warper.get_output_type("BOLD") == "BOLD"
|
38
|
-
|
39
|
-
|
40
|
-
@pytest.mark.parametrize(
|
41
|
-
"datagrabber, element",
|
42
|
-
[
|
43
|
-
[
|
44
|
-
DMCC13Benchmark(
|
45
|
-
types=["BOLD", "T1w", "Warp"],
|
46
|
-
sessions=["ses-wave1bas"],
|
47
|
-
tasks=["Rest"],
|
48
|
-
phase_encodings=["AP"],
|
49
|
-
runs=["1"],
|
50
|
-
native_t1w=True,
|
51
|
-
),
|
52
|
-
("sub-f9057kp", "ses-wave1bas", "Rest", "AP", "1"),
|
53
|
-
],
|
54
|
-
[
|
55
|
-
DataladHCP1200(
|
56
|
-
tasks=["REST1"],
|
57
|
-
phase_encodings=["LR"],
|
58
|
-
ica_fix=True,
|
59
|
-
),
|
60
|
-
("100206", "REST1", "LR"),
|
61
|
-
],
|
62
|
-
],
|
63
|
-
)
|
64
|
-
@pytest.mark.skipif(_check_fsl() is False, reason="requires FSL to be in PATH")
|
65
|
-
@pytest.mark.skipif(
|
66
|
-
_check_ants() is False, reason="requires ANTs to be in PATH"
|
67
|
-
)
|
68
|
-
@pytest.mark.skipif(
|
69
|
-
socket.gethostname() != "juseless",
|
70
|
-
reason="only for juseless",
|
71
|
-
)
|
72
|
-
def test_BOLDWarper_preprocess_to_native(
|
73
|
-
datagrabber: "BaseDataGrabber", element: Tuple[str, ...]
|
74
|
-
) -> None:
|
75
|
-
"""Test BOLDWarper preprocess.
|
76
|
-
|
77
|
-
Parameters
|
78
|
-
----------
|
79
|
-
datagrabber : DataGrabber-like object
|
80
|
-
The parametrized DataGrabber objects.
|
81
|
-
element : tuple of str
|
82
|
-
The parametrized elements.
|
83
|
-
|
84
|
-
"""
|
85
|
-
with datagrabber as dg:
|
86
|
-
# Read data
|
87
|
-
element_data = DefaultDataReader().fit_transform(dg[element])
|
88
|
-
# Preprocess data
|
89
|
-
data, _ = BOLDWarper(reference="T1w").preprocess(
|
90
|
-
input=element_data["BOLD"],
|
91
|
-
extra_input=element_data,
|
92
|
-
)
|
93
|
-
assert isinstance(data, dict)
|
94
|
-
|
95
|
-
|
96
|
-
@pytest.mark.parametrize(
|
97
|
-
"datagrabber, element, space",
|
98
|
-
[
|
99
|
-
[
|
100
|
-
DMCC13Benchmark(
|
101
|
-
types=["BOLD"],
|
102
|
-
sessions=["ses-wave1bas"],
|
103
|
-
tasks=["Rest"],
|
104
|
-
phase_encodings=["AP"],
|
105
|
-
runs=["1"],
|
106
|
-
native_t1w=False,
|
107
|
-
),
|
108
|
-
("sub-f9057kp", "ses-wave1bas", "Rest", "AP", "1"),
|
109
|
-
"MNI152NLin2009aAsym",
|
110
|
-
],
|
111
|
-
[
|
112
|
-
DMCC13Benchmark(
|
113
|
-
types=["BOLD"],
|
114
|
-
sessions=["ses-wave1bas"],
|
115
|
-
tasks=["Rest"],
|
116
|
-
phase_encodings=["AP"],
|
117
|
-
runs=["1"],
|
118
|
-
native_t1w=False,
|
119
|
-
),
|
120
|
-
("sub-f9057kp", "ses-wave1bas", "Rest", "AP", "1"),
|
121
|
-
"MNI152NLin6Asym",
|
122
|
-
],
|
123
|
-
],
|
124
|
-
)
|
125
|
-
@pytest.mark.skipif(
|
126
|
-
_check_ants() is False, reason="requires ANTs to be in PATH"
|
127
|
-
)
|
128
|
-
@pytest.mark.skipif(
|
129
|
-
socket.gethostname() != "juseless",
|
130
|
-
reason="only for juseless",
|
131
|
-
)
|
132
|
-
def test_BOLDWarper_preprocess_to_multi_mni(
|
133
|
-
datagrabber: "BaseDataGrabber", element: Tuple[str, ...], space: str
|
134
|
-
) -> None:
|
135
|
-
"""Test BOLDWarper preprocess.
|
136
|
-
|
137
|
-
Parameters
|
138
|
-
----------
|
139
|
-
datagrabber : DataGrabber-like object
|
140
|
-
The parametrized DataGrabber objects.
|
141
|
-
element : tuple of str
|
142
|
-
The parametrized elements.
|
143
|
-
space : str
|
144
|
-
The parametrized template space to transform to.
|
145
|
-
|
146
|
-
"""
|
147
|
-
with datagrabber as dg:
|
148
|
-
# Read data
|
149
|
-
element_data = DefaultDataReader().fit_transform(dg[element])
|
150
|
-
pre_xfm_data = element_data["BOLD"]["data"].get_fdata().copy()
|
151
|
-
# Preprocess data
|
152
|
-
data, _ = BOLDWarper(reference=space).preprocess(
|
153
|
-
input=element_data["BOLD"],
|
154
|
-
extra_input=element_data,
|
155
|
-
)
|
156
|
-
assert isinstance(data, dict)
|
157
|
-
assert data["space"] == space
|
158
|
-
with assert_raises(AssertionError):
|
159
|
-
assert_array_equal(pre_xfm_data, data["data"])
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|