junifer 0.0.5.dev242__py3-none-any.whl → 0.0.6__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/__init__.py +2 -31
- junifer/__init__.pyi +37 -0
- junifer/_version.py +9 -4
- junifer/api/__init__.py +3 -5
- junifer/api/__init__.pyi +4 -0
- junifer/api/decorators.py +14 -19
- junifer/api/functions.py +165 -109
- junifer/api/py.typed +0 -0
- junifer/api/queue_context/__init__.py +2 -4
- junifer/api/queue_context/__init__.pyi +5 -0
- junifer/api/queue_context/gnu_parallel_local_adapter.py +22 -6
- junifer/api/queue_context/htcondor_adapter.py +23 -6
- junifer/api/queue_context/py.typed +0 -0
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +3 -3
- junifer/api/queue_context/tests/test_htcondor_adapter.py +3 -3
- junifer/api/tests/test_functions.py +168 -74
- junifer/cli/__init__.py +24 -0
- junifer/cli/__init__.pyi +3 -0
- junifer/{api → cli}/cli.py +141 -125
- junifer/cli/parser.py +235 -0
- junifer/cli/py.typed +0 -0
- junifer/{api → cli}/tests/test_cli.py +8 -8
- junifer/{api/tests/test_api_utils.py → cli/tests/test_cli_utils.py} +5 -4
- junifer/{api → cli}/tests/test_parser.py +2 -2
- junifer/{api → cli}/utils.py +6 -16
- junifer/configs/juseless/__init__.py +2 -2
- junifer/configs/juseless/__init__.pyi +3 -0
- junifer/configs/juseless/datagrabbers/__init__.py +2 -12
- junifer/configs/juseless/datagrabbers/__init__.pyi +13 -0
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +2 -2
- junifer/configs/juseless/datagrabbers/py.typed +0 -0
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -2
- junifer/configs/juseless/datagrabbers/ucla.py +4 -4
- junifer/configs/juseless/py.typed +0 -0
- junifer/conftest.py +25 -0
- junifer/data/__init__.py +2 -42
- junifer/data/__init__.pyi +29 -0
- junifer/data/_dispatch.py +248 -0
- junifer/data/coordinates/__init__.py +9 -0
- junifer/data/coordinates/__init__.pyi +5 -0
- junifer/data/coordinates/_ants_coordinates_warper.py +104 -0
- junifer/data/coordinates/_coordinates.py +385 -0
- junifer/data/coordinates/_fsl_coordinates_warper.py +81 -0
- junifer/data/{tests → coordinates/tests}/test_coordinates.py +26 -33
- junifer/data/masks/__init__.py +9 -0
- junifer/data/masks/__init__.pyi +6 -0
- junifer/data/masks/_ants_mask_warper.py +177 -0
- junifer/data/masks/_fsl_mask_warper.py +106 -0
- junifer/data/masks/_masks.py +802 -0
- junifer/data/{tests → masks/tests}/test_masks.py +67 -63
- junifer/data/parcellations/__init__.py +9 -0
- junifer/data/parcellations/__init__.pyi +6 -0
- junifer/data/parcellations/_ants_parcellation_warper.py +166 -0
- junifer/data/parcellations/_fsl_parcellation_warper.py +89 -0
- junifer/data/parcellations/_parcellations.py +1388 -0
- junifer/data/{tests → parcellations/tests}/test_parcellations.py +165 -295
- junifer/data/pipeline_data_registry_base.py +76 -0
- junifer/data/py.typed +0 -0
- junifer/data/template_spaces.py +44 -79
- junifer/data/tests/test_data_utils.py +1 -2
- junifer/data/tests/test_template_spaces.py +8 -4
- junifer/data/utils.py +109 -4
- junifer/datagrabber/__init__.py +2 -26
- junifer/datagrabber/__init__.pyi +27 -0
- junifer/datagrabber/aomic/__init__.py +2 -4
- junifer/datagrabber/aomic/__init__.pyi +5 -0
- junifer/datagrabber/aomic/id1000.py +81 -52
- junifer/datagrabber/aomic/piop1.py +83 -55
- junifer/datagrabber/aomic/piop2.py +85 -56
- junifer/datagrabber/aomic/py.typed +0 -0
- junifer/datagrabber/aomic/tests/test_id1000.py +19 -12
- junifer/datagrabber/aomic/tests/test_piop1.py +52 -18
- junifer/datagrabber/aomic/tests/test_piop2.py +50 -17
- junifer/datagrabber/base.py +22 -18
- junifer/datagrabber/datalad_base.py +71 -34
- junifer/datagrabber/dmcc13_benchmark.py +31 -18
- junifer/datagrabber/hcp1200/__init__.py +2 -3
- junifer/datagrabber/hcp1200/__init__.pyi +4 -0
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -3
- junifer/datagrabber/hcp1200/hcp1200.py +26 -15
- junifer/datagrabber/hcp1200/py.typed +0 -0
- junifer/datagrabber/hcp1200/tests/test_hcp1200.py +8 -2
- junifer/datagrabber/multiple.py +14 -9
- junifer/datagrabber/pattern.py +132 -96
- junifer/datagrabber/pattern_validation_mixin.py +206 -94
- junifer/datagrabber/py.typed +0 -0
- junifer/datagrabber/tests/test_datalad_base.py +27 -12
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +28 -11
- junifer/datagrabber/tests/test_multiple.py +48 -2
- junifer/datagrabber/tests/test_pattern_datalad.py +1 -1
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +6 -6
- junifer/datareader/__init__.py +2 -2
- junifer/datareader/__init__.pyi +3 -0
- junifer/datareader/default.py +6 -6
- junifer/datareader/py.typed +0 -0
- junifer/external/nilearn/__init__.py +2 -3
- junifer/external/nilearn/__init__.pyi +4 -0
- junifer/external/nilearn/junifer_connectivity_measure.py +25 -17
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +4 -4
- junifer/external/nilearn/py.typed +0 -0
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +17 -16
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +2 -3
- junifer/markers/__init__.py +2 -38
- junifer/markers/__init__.pyi +37 -0
- junifer/markers/base.py +11 -14
- junifer/markers/brainprint.py +12 -14
- junifer/markers/complexity/__init__.py +2 -18
- junifer/markers/complexity/__init__.pyi +17 -0
- junifer/markers/complexity/complexity_base.py +9 -11
- junifer/markers/complexity/hurst_exponent.py +7 -7
- junifer/markers/complexity/multiscale_entropy_auc.py +7 -7
- junifer/markers/complexity/perm_entropy.py +7 -7
- junifer/markers/complexity/py.typed +0 -0
- junifer/markers/complexity/range_entropy.py +7 -7
- junifer/markers/complexity/range_entropy_auc.py +7 -7
- junifer/markers/complexity/sample_entropy.py +7 -7
- junifer/markers/complexity/tests/test_complexity_base.py +1 -1
- junifer/markers/complexity/tests/test_hurst_exponent.py +5 -5
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +5 -5
- junifer/markers/complexity/tests/test_perm_entropy.py +5 -5
- junifer/markers/complexity/tests/test_range_entropy.py +5 -5
- junifer/markers/complexity/tests/test_range_entropy_auc.py +5 -5
- junifer/markers/complexity/tests/test_sample_entropy.py +5 -5
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +5 -5
- junifer/markers/complexity/weighted_perm_entropy.py +7 -7
- junifer/markers/ets_rss.py +12 -11
- junifer/markers/falff/__init__.py +2 -3
- junifer/markers/falff/__init__.pyi +4 -0
- junifer/markers/falff/_afni_falff.py +38 -45
- junifer/markers/falff/_junifer_falff.py +16 -19
- junifer/markers/falff/falff_base.py +7 -11
- junifer/markers/falff/falff_parcels.py +9 -9
- junifer/markers/falff/falff_spheres.py +8 -8
- junifer/markers/falff/py.typed +0 -0
- junifer/markers/falff/tests/test_falff_spheres.py +3 -1
- junifer/markers/functional_connectivity/__init__.py +2 -12
- junifer/markers/functional_connectivity/__init__.pyi +13 -0
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +9 -8
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +8 -8
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +7 -7
- junifer/markers/functional_connectivity/functional_connectivity_base.py +13 -12
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +8 -8
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +7 -7
- junifer/markers/functional_connectivity/py.typed +0 -0
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +1 -2
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +1 -2
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +6 -6
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +5 -5
- junifer/markers/parcel_aggregation.py +22 -17
- junifer/markers/py.typed +0 -0
- junifer/markers/reho/__init__.py +2 -3
- junifer/markers/reho/__init__.pyi +4 -0
- junifer/markers/reho/_afni_reho.py +29 -35
- junifer/markers/reho/_junifer_reho.py +13 -14
- junifer/markers/reho/py.typed +0 -0
- junifer/markers/reho/reho_base.py +7 -11
- junifer/markers/reho/reho_parcels.py +10 -10
- junifer/markers/reho/reho_spheres.py +9 -9
- junifer/markers/sphere_aggregation.py +22 -17
- junifer/markers/temporal_snr/__init__.py +2 -3
- junifer/markers/temporal_snr/__init__.pyi +4 -0
- junifer/markers/temporal_snr/py.typed +0 -0
- junifer/markers/temporal_snr/temporal_snr_base.py +11 -10
- junifer/markers/temporal_snr/temporal_snr_parcels.py +8 -8
- junifer/markers/temporal_snr/temporal_snr_spheres.py +7 -7
- junifer/markers/tests/test_ets_rss.py +3 -3
- junifer/markers/tests/test_parcel_aggregation.py +24 -24
- junifer/markers/tests/test_sphere_aggregation.py +6 -6
- junifer/markers/utils.py +3 -3
- junifer/onthefly/__init__.py +2 -1
- junifer/onthefly/_brainprint.py +138 -0
- junifer/onthefly/read_transform.py +5 -8
- junifer/pipeline/__init__.py +2 -10
- junifer/pipeline/__init__.pyi +13 -0
- junifer/{markers/collection.py → pipeline/marker_collection.py} +8 -14
- junifer/pipeline/pipeline_component_registry.py +294 -0
- junifer/pipeline/pipeline_step_mixin.py +15 -11
- junifer/pipeline/py.typed +0 -0
- junifer/{markers/tests/test_collection.py → pipeline/tests/test_marker_collection.py} +2 -3
- junifer/pipeline/tests/test_pipeline_component_registry.py +200 -0
- junifer/pipeline/tests/test_pipeline_step_mixin.py +36 -37
- junifer/pipeline/tests/test_update_meta_mixin.py +4 -4
- junifer/pipeline/tests/test_workdir_manager.py +43 -0
- junifer/pipeline/update_meta_mixin.py +21 -17
- junifer/pipeline/utils.py +6 -6
- junifer/pipeline/workdir_manager.py +19 -5
- junifer/preprocess/__init__.py +2 -10
- junifer/preprocess/__init__.pyi +11 -0
- junifer/preprocess/base.py +10 -10
- junifer/preprocess/confounds/__init__.py +2 -2
- junifer/preprocess/confounds/__init__.pyi +3 -0
- junifer/preprocess/confounds/fmriprep_confound_remover.py +243 -64
- junifer/preprocess/confounds/py.typed +0 -0
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +121 -14
- junifer/preprocess/py.typed +0 -0
- junifer/preprocess/smoothing/__init__.py +2 -2
- junifer/preprocess/smoothing/__init__.pyi +3 -0
- junifer/preprocess/smoothing/_afni_smoothing.py +40 -40
- junifer/preprocess/smoothing/_fsl_smoothing.py +22 -32
- junifer/preprocess/smoothing/_nilearn_smoothing.py +35 -14
- junifer/preprocess/smoothing/py.typed +0 -0
- junifer/preprocess/smoothing/smoothing.py +11 -13
- junifer/preprocess/warping/__init__.py +2 -2
- junifer/preprocess/warping/__init__.pyi +3 -0
- junifer/preprocess/warping/_ants_warper.py +136 -32
- junifer/preprocess/warping/_fsl_warper.py +73 -22
- junifer/preprocess/warping/py.typed +0 -0
- junifer/preprocess/warping/space_warper.py +39 -11
- junifer/preprocess/warping/tests/test_space_warper.py +5 -9
- junifer/py.typed +0 -0
- junifer/stats.py +5 -5
- junifer/storage/__init__.py +2 -10
- junifer/storage/__init__.pyi +11 -0
- junifer/storage/base.py +47 -13
- junifer/storage/hdf5.py +95 -33
- junifer/storage/pandas_base.py +12 -11
- junifer/storage/py.typed +0 -0
- junifer/storage/sqlite.py +11 -11
- junifer/storage/tests/test_hdf5.py +86 -4
- junifer/storage/tests/test_sqlite.py +2 -2
- junifer/storage/tests/test_storage_base.py +5 -2
- junifer/storage/tests/test_utils.py +33 -7
- junifer/storage/utils.py +95 -9
- junifer/testing/__init__.py +2 -3
- junifer/testing/__init__.pyi +4 -0
- junifer/testing/datagrabbers.py +10 -11
- junifer/testing/py.typed +0 -0
- junifer/testing/registry.py +4 -7
- junifer/testing/tests/test_testing_registry.py +9 -17
- junifer/tests/test_stats.py +2 -2
- junifer/typing/__init__.py +9 -0
- junifer/typing/__init__.pyi +31 -0
- junifer/typing/_typing.py +68 -0
- junifer/utils/__init__.py +2 -12
- junifer/utils/__init__.pyi +18 -0
- junifer/utils/_config.py +110 -0
- junifer/utils/_yaml.py +16 -0
- junifer/utils/helpers.py +6 -6
- junifer/utils/logging.py +117 -8
- junifer/utils/py.typed +0 -0
- junifer/{pipeline → utils}/singleton.py +19 -14
- junifer/utils/tests/test_config.py +59 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
- junifer-0.0.6.dist-info/RECORD +350 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/WHEEL +1 -1
- junifer-0.0.6.dist-info/entry_points.txt +2 -0
- junifer/api/parser.py +0 -118
- junifer/data/coordinates.py +0 -408
- junifer/data/masks.py +0 -670
- junifer/data/parcellations.py +0 -1828
- junifer/pipeline/registry.py +0 -177
- junifer/pipeline/tests/test_registry.py +0 -150
- junifer-0.0.5.dev242.dist-info/RECORD +0 -275
- junifer-0.0.5.dev242.dist-info/entry_points.txt +0 -2
- /junifer/{api → cli}/tests/data/gmd_mean.yaml +0 -0
- /junifer/{api → cli}/tests/data/gmd_mean_htcondor.yaml +0 -0
- /junifer/{api → cli}/tests/data/partly_cloudy_agg_mean_tian.yml +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/AutobiographicalMemory_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAC_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAR_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/DMNBuckner_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Dosenbach2010_MNI_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Empathy_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Motor_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/MultiTask_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/PhysioStress_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2011_MNI_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2013_MNI_VOIs.tsv +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Rew_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Somatosensory_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/ToM_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/VigAtt_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/WM_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/eMDN_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/eSAD_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/extDMN_VOIs.txt +0 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
"""Provide class for mask space warping via ANTs."""
|
2
|
+
|
3
|
+
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
+
# License: AGPL
|
5
|
+
|
6
|
+
import uuid
|
7
|
+
from typing import TYPE_CHECKING, Any, Optional
|
8
|
+
|
9
|
+
import nibabel as nib
|
10
|
+
import numpy as np
|
11
|
+
|
12
|
+
from ...pipeline import WorkDirManager
|
13
|
+
from ...utils import logger, raise_error, run_ext_cmd
|
14
|
+
from ..template_spaces import get_template, get_xfm
|
15
|
+
|
16
|
+
|
17
|
+
if TYPE_CHECKING:
|
18
|
+
from nibabel.nifti1 import Nifti1Image
|
19
|
+
|
20
|
+
|
21
|
+
__all__ = ["ANTsMaskWarper"]
|
22
|
+
|
23
|
+
|
24
|
+
def _get_interpolation_method(img: "Nifti1Image") -> str:
|
25
|
+
"""Get correct interpolation method for `img`.
|
26
|
+
|
27
|
+
Parameters
|
28
|
+
----------
|
29
|
+
img : nibabel.nifti1.Nifti1Image
|
30
|
+
The image.
|
31
|
+
|
32
|
+
Returns
|
33
|
+
-------
|
34
|
+
str
|
35
|
+
The interpolation method.
|
36
|
+
|
37
|
+
"""
|
38
|
+
if np.array_equal(np.unique(img.get_fdata()), [0, 1]):
|
39
|
+
return "'GenericLabel[NearestNeighbor]'"
|
40
|
+
else:
|
41
|
+
return "LanczosWindowedSinc"
|
42
|
+
|
43
|
+
|
44
|
+
class ANTsMaskWarper:
|
45
|
+
"""Class for mask space warping via ANTs.
|
46
|
+
|
47
|
+
This class uses ANTs ``antsApplyTransforms`` for transformation.
|
48
|
+
|
49
|
+
"""
|
50
|
+
|
51
|
+
def warp(
|
52
|
+
self,
|
53
|
+
mask_name: str,
|
54
|
+
mask_img: "Nifti1Image",
|
55
|
+
src: str,
|
56
|
+
dst: str,
|
57
|
+
target_data: dict[str, Any],
|
58
|
+
warp_data: Optional[dict[str, Any]],
|
59
|
+
) -> "Nifti1Image":
|
60
|
+
"""Warp ``mask_img`` to correct space.
|
61
|
+
|
62
|
+
Parameters
|
63
|
+
----------
|
64
|
+
mask_name : str
|
65
|
+
The name of the mask.
|
66
|
+
mask_img : nibabel.nifti1.Nifti1Image
|
67
|
+
The mask image to transform.
|
68
|
+
src : str
|
69
|
+
The data type or template space to warp from.
|
70
|
+
It should be empty string if ``dst="native"``.
|
71
|
+
dst : str
|
72
|
+
The data type or template space to warp to.
|
73
|
+
`"native"` is the only allowed data type and it uses the resampled
|
74
|
+
T1w found in ``target_data.reference``. The
|
75
|
+
``"reference"`` key is added when :class:`.SpaceWarper` is
|
76
|
+
used or if the data is provided native space.
|
77
|
+
target_data : dict
|
78
|
+
The corresponding item of the data object to which the mask
|
79
|
+
will be applied.
|
80
|
+
warp_data : dict or None
|
81
|
+
The warp data item of the data object. The value is unused if
|
82
|
+
``dst!="native"``.
|
83
|
+
|
84
|
+
Returns
|
85
|
+
-------
|
86
|
+
nibabel.nifti1.Nifti1Image
|
87
|
+
The transformed mask image.
|
88
|
+
|
89
|
+
Raises
|
90
|
+
------
|
91
|
+
RuntimeError
|
92
|
+
If ``warp_data`` is None when ``dst="T1w"``.
|
93
|
+
|
94
|
+
"""
|
95
|
+
# Create element-scoped tempdir so that warped mask is
|
96
|
+
# available later as nibabel stores file path reference for
|
97
|
+
# loading on computation
|
98
|
+
prefix = (
|
99
|
+
f"ants_mask_warper_{mask_name}"
|
100
|
+
f"{'' if not src else f'_from_{src}'}_to_{dst}_"
|
101
|
+
f"{uuid.uuid1()}"
|
102
|
+
)
|
103
|
+
element_tempdir = WorkDirManager().get_element_tempdir(
|
104
|
+
prefix=prefix,
|
105
|
+
)
|
106
|
+
|
107
|
+
# Native space warping
|
108
|
+
if dst == "native":
|
109
|
+
# Warp data check
|
110
|
+
if warp_data is None:
|
111
|
+
raise_error("No `warp_data` provided")
|
112
|
+
if "reference" not in target_data:
|
113
|
+
raise_error("No `reference` provided")
|
114
|
+
if "path" not in target_data["reference"]:
|
115
|
+
raise_error("No `path` provided in `reference`")
|
116
|
+
|
117
|
+
logger.debug("Using ANTs for mask transformation")
|
118
|
+
|
119
|
+
# Save existing mask image to a tempfile
|
120
|
+
prewarp_mask_path = element_tempdir / "prewarp_mask.nii.gz"
|
121
|
+
nib.save(mask_img, prewarp_mask_path)
|
122
|
+
|
123
|
+
# Create a tempfile for warped output
|
124
|
+
warped_mask_path = element_tempdir / "mask_warped.nii.gz"
|
125
|
+
# Set antsApplyTransforms command
|
126
|
+
apply_transforms_cmd = [
|
127
|
+
"antsApplyTransforms",
|
128
|
+
"-d 3",
|
129
|
+
"-e 3",
|
130
|
+
"-n 'GenericLabel[NearestNeighbor]'",
|
131
|
+
f"-i {prewarp_mask_path.resolve()}",
|
132
|
+
# use resampled reference
|
133
|
+
f"-r {target_data['reference']['path'].resolve()}",
|
134
|
+
f"-t {warp_data['path'].resolve()}",
|
135
|
+
f"-o {warped_mask_path.resolve()}",
|
136
|
+
]
|
137
|
+
# Call antsApplyTransforms
|
138
|
+
run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
|
139
|
+
|
140
|
+
# Template space warping
|
141
|
+
else:
|
142
|
+
logger.debug(f"Using ANTs to warp mask from {src} to {dst}")
|
143
|
+
|
144
|
+
# Get xfm file
|
145
|
+
xfm_file_path = get_xfm(src=src, dst=dst)
|
146
|
+
# Get template space image
|
147
|
+
template_space_img = get_template(
|
148
|
+
space=dst,
|
149
|
+
target_img=mask_img,
|
150
|
+
extra_input=None,
|
151
|
+
)
|
152
|
+
# Save template to a tempfile
|
153
|
+
template_space_img_path = element_tempdir / f"{dst}_T1w.nii.gz"
|
154
|
+
nib.save(template_space_img, template_space_img_path)
|
155
|
+
|
156
|
+
# Save existing mask image to a tempfile
|
157
|
+
prewarp_mask_path = element_tempdir / "prewarp_mask.nii.gz"
|
158
|
+
nib.save(mask_img, prewarp_mask_path)
|
159
|
+
|
160
|
+
# Create a tempfile for warped output
|
161
|
+
warped_mask_path = element_tempdir / "mask_warped.nii.gz"
|
162
|
+
# Set antsApplyTransforms command
|
163
|
+
apply_transforms_cmd = [
|
164
|
+
"antsApplyTransforms",
|
165
|
+
"-d 3",
|
166
|
+
"-e 3",
|
167
|
+
f"-n {_get_interpolation_method(mask_img)}",
|
168
|
+
f"-i {prewarp_mask_path.resolve()}",
|
169
|
+
f"-r {template_space_img_path.resolve()}",
|
170
|
+
f"-t {xfm_file_path.resolve()}",
|
171
|
+
f"-o {warped_mask_path.resolve()}",
|
172
|
+
]
|
173
|
+
# Call antsApplyTransforms
|
174
|
+
run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
|
175
|
+
|
176
|
+
# Load nifti
|
177
|
+
return nib.load(warped_mask_path)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
"""Provide class for mask space warping via FSL FLIRT."""
|
2
|
+
|
3
|
+
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
+
# License: AGPL
|
5
|
+
|
6
|
+
import uuid
|
7
|
+
from typing import TYPE_CHECKING, Any
|
8
|
+
|
9
|
+
import nibabel as nib
|
10
|
+
import numpy as np
|
11
|
+
|
12
|
+
from ...pipeline import WorkDirManager
|
13
|
+
from ...utils import logger, run_ext_cmd
|
14
|
+
|
15
|
+
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from nibabel.nifti1 import Nifti1Image
|
18
|
+
|
19
|
+
|
20
|
+
__all__ = ["FSLMaskWarper"]
|
21
|
+
|
22
|
+
|
23
|
+
def _get_interpolation_method(img: "Nifti1Image") -> str:
|
24
|
+
"""Get correct interpolation method for `img`.
|
25
|
+
|
26
|
+
Parameters
|
27
|
+
----------
|
28
|
+
img : nibabel.nifti1.Nifti1Image
|
29
|
+
The image.
|
30
|
+
|
31
|
+
Returns
|
32
|
+
-------
|
33
|
+
str
|
34
|
+
The interpolation method.
|
35
|
+
|
36
|
+
"""
|
37
|
+
if np.array_equal(np.unique(img.get_fdata()), [0, 1]):
|
38
|
+
return "nn"
|
39
|
+
else:
|
40
|
+
return "spline"
|
41
|
+
|
42
|
+
|
43
|
+
class FSLMaskWarper:
|
44
|
+
"""Class for mask space warping via FSL FLIRT.
|
45
|
+
|
46
|
+
This class uses FSL FLIRT's ``applywarp`` for transformation.
|
47
|
+
|
48
|
+
"""
|
49
|
+
|
50
|
+
def warp(
|
51
|
+
self,
|
52
|
+
mask_name: str,
|
53
|
+
mask_img: "Nifti1Image",
|
54
|
+
target_data: dict[str, Any],
|
55
|
+
warp_data: dict[str, Any],
|
56
|
+
) -> "Nifti1Image":
|
57
|
+
"""Warp ``mask_img`` to correct space.
|
58
|
+
|
59
|
+
Parameters
|
60
|
+
----------
|
61
|
+
mask_name : str
|
62
|
+
The name of the mask.
|
63
|
+
mask_img : nibabel.nifti1.Nifti1Image
|
64
|
+
The mask image to transform.
|
65
|
+
target_data : dict
|
66
|
+
The corresponding item of the data object to which the mask
|
67
|
+
will be applied.
|
68
|
+
warp_data : dict
|
69
|
+
The warp data item of the data object.
|
70
|
+
|
71
|
+
Returns
|
72
|
+
-------
|
73
|
+
nibabel.nifti1.Nifti1Image
|
74
|
+
The transformed mask image.
|
75
|
+
|
76
|
+
"""
|
77
|
+
logger.debug("Using FSL for mask transformation")
|
78
|
+
|
79
|
+
# Create element-scoped tempdir so that warped mask is
|
80
|
+
# available later as nibabel stores file path reference for
|
81
|
+
# loading on computation
|
82
|
+
element_tempdir = WorkDirManager().get_element_tempdir(
|
83
|
+
prefix=f"fsl_mask_warper_{mask_name}_{uuid.uuid1()}"
|
84
|
+
)
|
85
|
+
|
86
|
+
# Save existing mask image to a tempfile
|
87
|
+
prewarp_mask_path = element_tempdir / "prewarp_mask.nii.gz"
|
88
|
+
nib.save(mask_img, prewarp_mask_path)
|
89
|
+
|
90
|
+
# Create a tempfile for warped output
|
91
|
+
warped_mask_path = element_tempdir / "mask_warped.nii.gz"
|
92
|
+
# Set applywarp command
|
93
|
+
applywarp_cmd = [
|
94
|
+
"applywarp",
|
95
|
+
f"--interp={_get_interpolation_method(mask_img)}",
|
96
|
+
f"-i {prewarp_mask_path.resolve()}",
|
97
|
+
# use resampled reference
|
98
|
+
f"-r {target_data['reference']['path'].resolve()}",
|
99
|
+
f"-w {warp_data['path'].resolve()}",
|
100
|
+
f"-o {warped_mask_path.resolve()}",
|
101
|
+
]
|
102
|
+
# Call applywarp
|
103
|
+
run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
|
104
|
+
|
105
|
+
# Load nifti
|
106
|
+
return nib.load(warped_mask_path)
|