junifer 0.0.7.dev332__py3-none-any.whl → 0.0.8__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 +9 -19
- junifer/api/__init__.pyi +17 -2
- junifer/api/functions.py +222 -39
- junifer/api/queue_context/__init__.pyi +11 -3
- junifer/api/queue_context/gnu_parallel_local_adapter.py +81 -120
- junifer/api/queue_context/htcondor_adapter.py +118 -181
- junifer/api/queue_context/queue_context_adapter.py +51 -7
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +10 -35
- junifer/api/queue_context/tests/test_htcondor_adapter.py +13 -50
- junifer/api/res/fsl/run_fsl_docker.sh +4 -0
- junifer/api/tests/test_functions.py +863 -36
- junifer/cli/__init__.py +1 -7
- junifer/cli/cli.py +41 -22
- junifer/cli/parser.py +23 -147
- junifer/cli/tests/data/gmd_mean.yaml +6 -6
- junifer/cli/tests/data/gmd_mean_htcondor.yaml +6 -5
- junifer/cli/tests/data/partly_cloudy_agg_mean_tian.yml +1 -0
- junifer/cli/tests/test_cli.py +120 -4
- junifer/cli/tests/test_cli_utils.py +23 -6
- junifer/cli/utils.py +14 -9
- junifer/configs/__init__.py +5 -0
- junifer/configs/__init__.pyi +0 -0
- junifer/configs/juseless/datagrabbers/__init__.pyi +4 -2
- junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +18 -24
- junifer/configs/juseless/datagrabbers/camcan_vbm.py +20 -27
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +44 -52
- junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py +0 -7
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -19
- junifer/configs/juseless/datagrabbers/ucla.py +111 -104
- junifer/configs/juseless/datagrabbers/ukb_vbm.py +19 -25
- junifer/configs/py.typed +0 -0
- junifer/conftest.py +63 -24
- junifer/data/_dispatch.py +9 -19
- junifer/data/coordinates/_ants_coordinates_warper.py +4 -1
- junifer/data/coordinates/_coordinates.py +51 -6
- junifer/data/coordinates/_fsl_coordinates_warper.py +4 -1
- junifer/data/coordinates/tests/test_coordinates.py +15 -3
- junifer/data/coordinates/tests/test_coordinates_names.py +37 -0
- junifer/data/maps/_ants_maps_warper.py +18 -12
- junifer/data/maps/_fsl_maps_warper.py +7 -3
- junifer/data/maps/_maps.py +12 -8
- junifer/data/maps/tests/test_maps.py +13 -21
- junifer/data/masks/_ants_mask_warper.py +18 -12
- junifer/data/masks/_fsl_mask_warper.py +7 -3
- junifer/data/masks/_masks.py +15 -12
- junifer/data/masks/tests/test_masks.py +20 -17
- junifer/data/parcellations/_ants_parcellation_warper.py +18 -12
- junifer/data/parcellations/_fsl_parcellation_warper.py +7 -5
- junifer/data/parcellations/_parcellations.py +125 -91
- junifer/data/parcellations/tests/test_parcellations.py +122 -1
- junifer/data/template_spaces.py +117 -50
- junifer/data/tests/test_template_spaces.py +10 -7
- junifer/data/utils.py +10 -8
- junifer/datagrabber/__init__.pyi +38 -5
- junifer/datagrabber/aomic/__init__.pyi +8 -1
- junifer/datagrabber/aomic/_types.py +22 -0
- junifer/datagrabber/aomic/id1000.py +193 -183
- junifer/datagrabber/aomic/piop1.py +215 -259
- junifer/datagrabber/aomic/piop2.py +211 -244
- junifer/datagrabber/aomic/tests/test_id1000.py +70 -53
- junifer/datagrabber/aomic/tests/test_piop1.py +98 -102
- junifer/datagrabber/aomic/tests/test_piop2.py +88 -85
- junifer/datagrabber/base.py +253 -79
- junifer/datagrabber/datalad_base.py +127 -76
- junifer/datagrabber/dmcc13_benchmark.py +204 -289
- junifer/datagrabber/hcp1200/__init__.pyi +7 -2
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +61 -40
- junifer/datagrabber/hcp1200/hcp1200.py +151 -164
- junifer/datagrabber/hcp1200/tests/test_hcp1200.py +116 -128
- junifer/datagrabber/multiple.py +183 -63
- junifer/datagrabber/pattern.py +358 -227
- junifer/datagrabber/pattern_datalad.py +84 -124
- junifer/datagrabber/pattern_validation_mixin.py +22 -50
- junifer/datagrabber/tests/test_base.py +17 -4
- junifer/datagrabber/tests/test_datalad_base.py +20 -27
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +110 -122
- junifer/datagrabber/tests/test_multiple.py +293 -31
- junifer/datagrabber/tests/test_pattern.py +577 -18
- junifer/datagrabber/tests/test_pattern_datalad.py +177 -107
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +9 -51
- junifer/datareader/default.py +8 -5
- junifer/datareader/tests/test_default_reader.py +1 -1
- junifer/external/BrainPrint/.codecov.yml +2 -0
- junifer/external/BrainPrint/.codespellignore +2 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/bug-report.md +45 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/documentation.md +12 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/feature-request.md +24 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/questions-help-support.md +28 -0
- junifer/external/BrainPrint/.github/dependabot.yml +6 -0
- junifer/external/BrainPrint/.github/workflows/build.yml +53 -0
- junifer/external/BrainPrint/.github/workflows/code-style.yml +44 -0
- junifer/external/BrainPrint/.github/workflows/doc.yml +65 -0
- junifer/external/BrainPrint/.github/workflows/publish.yml +31 -0
- junifer/external/BrainPrint/.github/workflows/pytest.yml +54 -0
- junifer/external/BrainPrint/.gitignore +123 -0
- junifer/external/BrainPrint/LICENSE +21 -0
- junifer/external/BrainPrint/README.md +108 -0
- junifer/external/BrainPrint/brainprint/cli/__init__.py +11 -0
- junifer/external/BrainPrint/brainprint/cli/help_text.py +169 -0
- junifer/external/BrainPrint/brainprint/cli/parser.py +150 -0
- junifer/external/BrainPrint/brainprint/cli/utils.py +14 -0
- junifer/external/BrainPrint/brainprint/commands/__init__.py +0 -0
- junifer/external/BrainPrint/brainprint/commands/sys_info.py +18 -0
- junifer/external/BrainPrint/brainprint/utils/tests/__init__.py +0 -0
- junifer/external/BrainPrint/brainprint/utils/tests/test_config.py +33 -0
- junifer/external/BrainPrint/doc/Makefile +20 -0
- junifer/external/BrainPrint/doc/_static/.gitkeep +0 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/class.rst +10 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/function.rst +8 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/module.rst +6 -0
- junifer/external/BrainPrint/doc/api/index.rst +11 -0
- junifer/external/BrainPrint/doc/conf.py +272 -0
- junifer/external/BrainPrint/doc/index.rst +140 -0
- junifer/external/BrainPrint/doc/links.inc +36 -0
- junifer/external/BrainPrint/doc/make.bat +35 -0
- junifer/external/BrainPrint/doc/references.bib +23 -0
- junifer/external/BrainPrint/pyproject.toml +170 -0
- junifer/external/BrainPrint/setup.py +3 -0
- junifer/external/__init__.py +5 -0
- junifer/external/__init__.pyi +0 -0
- junifer/external/nilearn/junifer_connectivity_measure.py +95 -39
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +226 -67
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +39 -27
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +231 -21
- junifer/external/py.typed +0 -0
- junifer/markers/__init__.pyi +6 -3
- junifer/markers/base.py +126 -76
- junifer/markers/brainprint.py +30 -39
- junifer/markers/complexity/__init__.py +20 -3
- junifer/markers/complexity/complexity_base.py +40 -41
- junifer/markers/complexity/hurst_exponent.py +22 -35
- junifer/markers/complexity/multiscale_entropy_auc.py +53 -41
- junifer/markers/complexity/perm_entropy.py +22 -36
- junifer/markers/complexity/range_entropy.py +22 -35
- junifer/markers/complexity/range_entropy_auc.py +27 -36
- junifer/markers/complexity/sample_entropy.py +22 -36
- junifer/markers/complexity/tests/test_complexity_registry.py +48 -0
- junifer/markers/complexity/tests/test_hurst_exponent.py +47 -36
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +50 -36
- junifer/markers/complexity/tests/test_perm_entropy.py +48 -36
- junifer/markers/complexity/tests/test_range_entropy.py +47 -36
- junifer/markers/complexity/tests/test_range_entropy_auc.py +47 -36
- junifer/markers/complexity/tests/test_sample_entropy.py +48 -36
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +50 -36
- junifer/markers/complexity/weighted_perm_entropy.py +22 -36
- junifer/markers/ets_rss.py +35 -31
- junifer/markers/falff/__init__.pyi +7 -1
- junifer/markers/falff/_afni_falff.py +22 -9
- junifer/markers/falff/_junifer_falff.py +47 -31
- junifer/markers/falff/falff_base.py +80 -60
- junifer/markers/falff/falff_maps.py +17 -41
- junifer/markers/falff/falff_parcels.py +26 -51
- junifer/markers/falff/falff_spheres.py +34 -61
- junifer/markers/falff/tests/test_falff_maps.py +20 -23
- junifer/markers/falff/tests/test_falff_mask.py +99 -0
- junifer/markers/falff/tests/test_falff_parcels.py +14 -10
- junifer/markers/falff/tests/test_falff_spheres.py +14 -10
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +32 -34
- junifer/markers/functional_connectivity/edge_functional_connectivity_maps.py +12 -25
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +19 -34
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +24 -44
- junifer/markers/functional_connectivity/functional_connectivity_base.py +50 -40
- junifer/markers/functional_connectivity/functional_connectivity_maps.py +12 -25
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +19 -34
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +24 -45
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +21 -22
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_maps.py +8 -7
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +8 -4
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +8 -4
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_maps.py +8 -7
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +9 -5
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +8 -12
- junifer/markers/maps_aggregation.py +77 -55
- junifer/markers/parcel_aggregation.py +91 -70
- junifer/markers/reho/__init__.pyi +7 -1
- junifer/markers/reho/_afni_reho.py +23 -14
- junifer/markers/reho/_junifer_reho.py +112 -123
- junifer/markers/reho/reho_base.py +115 -37
- junifer/markers/reho/reho_maps.py +18 -32
- junifer/markers/reho/reho_parcels.py +26 -41
- junifer/markers/reho/reho_spheres.py +33 -54
- junifer/markers/reho/tests/test_junifer_reho.py +178 -0
- junifer/markers/reho/tests/test_reho_maps.py +27 -25
- junifer/markers/reho/tests/test_reho_parcels.py +28 -22
- junifer/markers/reho/tests/test_reho_spheres.py +16 -12
- junifer/markers/sphere_aggregation.py +88 -72
- junifer/markers/temporal_snr/temporal_snr_base.py +32 -30
- junifer/markers/temporal_snr/temporal_snr_maps.py +9 -18
- junifer/markers/temporal_snr/temporal_snr_parcels.py +19 -27
- junifer/markers/temporal_snr/temporal_snr_spheres.py +27 -41
- junifer/markers/temporal_snr/tests/test_temporal_snr_base.py +2 -2
- junifer/markers/temporal_snr/tests/test_temporal_snr_maps.py +17 -22
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +11 -3
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +9 -9
- junifer/markers/tests/test_brainprint.py +10 -9
- junifer/markers/tests/test_ets_rss.py +7 -3
- junifer/markers/tests/test_lost_regions.py +279 -0
- junifer/markers/tests/test_maps_aggregation.py +67 -114
- junifer/markers/tests/test_marker_utils.py +40 -1
- junifer/markers/tests/test_markers_base.py +275 -6
- junifer/markers/tests/test_parcel_aggregation.py +91 -53
- junifer/markers/tests/test_sphere_aggregation.py +53 -47
- junifer/markers/utils.py +267 -5
- junifer/onthefly/__init__.py +2 -3
- junifer/onthefly/__init__.pyi +4 -0
- junifer/onthefly/_brainprint.py +3 -5
- junifer/onthefly/py.typed +0 -0
- junifer/onthefly/read_transform.py +11 -9
- junifer/onthefly/tests/test_read_transform.py +7 -7
- junifer/pipeline/__init__.pyi +4 -2
- junifer/pipeline/marker_collection.py +14 -10
- junifer/pipeline/pipeline_component_registry.py +25 -6
- junifer/pipeline/pipeline_step_mixin.py +5 -12
- junifer/pipeline/tests/test_data_object_dumper.py +10 -10
- junifer/pipeline/tests/test_marker_collection.py +145 -168
- junifer/pipeline/tests/test_pipeline_component_registry.py +52 -8
- junifer/pipeline/tests/test_pipeline_step_mixin.py +12 -26
- junifer/pipeline/tests/test_update_meta_mixin.py +4 -5
- junifer/pipeline/tests/test_workdir_manager.py +39 -0
- junifer/pipeline/update_meta_mixin.py +13 -10
- junifer/pipeline/utils.py +22 -17
- junifer/pipeline/workdir_manager.py +41 -32
- junifer/preprocess/__init__.pyi +9 -4
- junifer/preprocess/_temporal_filter.py +34 -33
- junifer/preprocess/_temporal_slicer.py +17 -30
- junifer/preprocess/base.py +99 -55
- junifer/preprocess/confounds/__init__.pyi +10 -2
- junifer/preprocess/confounds/fmriprep_confound_remover.py +87 -109
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +64 -45
- junifer/preprocess/smoothing/__init__.pyi +2 -2
- junifer/preprocess/smoothing/_afni_smoothing.py +8 -7
- junifer/preprocess/smoothing/_fsl_smoothing.py +6 -4
- junifer/preprocess/smoothing/_nilearn_smoothing.py +7 -5
- junifer/preprocess/smoothing/smoothing.py +59 -40
- junifer/preprocess/smoothing/tests/test_smoothing.py +28 -8
- junifer/preprocess/tests/test_preprocess_base.py +17 -9
- junifer/preprocess/tests/test_temporal_filter.py +37 -16
- junifer/preprocess/tests/test_temporal_slicer.py +12 -12
- junifer/preprocess/warping/__init__.pyi +2 -2
- junifer/preprocess/warping/_ants_warper.py +56 -40
- junifer/preprocess/warping/_fsl_warper.py +49 -36
- junifer/preprocess/warping/_utils.py +106 -0
- junifer/preprocess/warping/space_warper.py +99 -98
- junifer/preprocess/warping/tests/test_space_warper.py +46 -41
- junifer/preprocess/warping/tests/test_warping_utils.py +163 -0
- junifer/stats.py +46 -34
- junifer/storage/__init__.pyi +8 -4
- junifer/storage/base.py +129 -64
- junifer/storage/hdf5.py +307 -199
- junifer/storage/pandas_base.py +46 -24
- junifer/storage/sqlite.py +99 -62
- junifer/storage/tests/data/collected_h5io_fork.hdf5 +0 -0
- junifer/storage/tests/test_hdf5.py +147 -12
- junifer/storage/tests/test_repeated_storage.py +293 -0
- junifer/storage/tests/test_sqlite.py +9 -20
- junifer/storage/tests/test_storage_base.py +18 -21
- junifer/storage/tests/test_utils.py +83 -22
- junifer/storage/utils.py +58 -38
- junifer/testing/__init__.pyi +2 -2
- junifer/testing/datagrabbers.py +480 -44
- junifer/testing/registry.py +12 -0
- junifer/testing/tests/test_adhdtesting_datagrabber.py +24 -0
- junifer/testing/tests/test_oasisvmbtesting_datagrabber.py +5 -0
- junifer/testing/tests/test_partlycloudytesting_datagrabber.py +52 -0
- junifer/testing/tests/test_spmauditory_datagrabber.py +16 -0
- junifer/testing/tests/test_testing_registry.py +31 -0
- junifer/testing/tests/test_testing_utils.py +35 -0
- junifer/testing/tests/test_uclacnpvbmtesting_datagrabber.py +81 -0
- junifer/testing/utils.py +33 -1
- junifer/tests/test_stats.py +1 -5
- junifer/typing/__init__.pyi +2 -0
- junifer/typing/_typing.py +34 -19
- junifer/typing/py.typed +0 -0
- junifer/utils/__init__.pyi +10 -1
- junifer/utils/_config.py +1 -2
- junifer/utils/helpers.py +68 -2
- junifer/utils/logging.py +31 -7
- junifer/utils/tests/test_helpers.py +36 -1
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/METADATA +43 -35
- junifer-0.0.8.dist-info/RECORD +402 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/WHEEL +1 -1
- junifer/cli/tests/test_parser.py +0 -280
- junifer/external/h5io/h5io/__init__.py +0 -15
- junifer/external/h5io/h5io/_h5io.py +0 -767
- junifer/external/h5io/h5io/_version.py +0 -1
- junifer/external/h5io/h5io/chunked_array.py +0 -94
- junifer/external/h5io/h5io/chunked_list.py +0 -65
- junifer/markers/complexity/__init__.pyi +0 -17
- junifer-0.0.7.dev332.dist-info/RECORD +0 -353
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/AUTHORS.rst +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/LICENSE.md +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/top_level.txt +0 -0
|
@@ -12,9 +12,11 @@ import nibabel as nib
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
|
|
14
14
|
from ...data import get_template, get_xfm
|
|
15
|
-
from ...pipeline import WorkDirManager
|
|
16
|
-
from ...typing import Dependencies, ExternalDependencies
|
|
17
|
-
from ...utils import
|
|
15
|
+
from ...pipeline import ExtDep, WorkDirManager
|
|
16
|
+
from ...typing import Dependencies, ExternalDependencies, SpaceLike
|
|
17
|
+
from ...utils import raise_error, run_ext_cmd
|
|
18
|
+
from ..base import logger
|
|
19
|
+
from ._utils import warp_in_chunks
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
__all__ = ["ANTsWarper"]
|
|
@@ -30,7 +32,7 @@ class ANTsWarper:
|
|
|
30
32
|
|
|
31
33
|
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
|
|
32
34
|
{
|
|
33
|
-
"name":
|
|
35
|
+
"name": ExtDep.ANTs,
|
|
34
36
|
"commands": ["ResampleImage", "antsApplyTransforms"],
|
|
35
37
|
},
|
|
36
38
|
]
|
|
@@ -41,7 +43,7 @@ class ANTsWarper:
|
|
|
41
43
|
self,
|
|
42
44
|
input: dict[str, Any],
|
|
43
45
|
extra_input: dict[str, Any],
|
|
44
|
-
reference:
|
|
46
|
+
reference: SpaceLike,
|
|
45
47
|
) -> dict[str, Any]:
|
|
46
48
|
"""Preprocess using ANTs.
|
|
47
49
|
|
|
@@ -52,7 +54,7 @@ class ANTsWarper:
|
|
|
52
54
|
extra_input : dict
|
|
53
55
|
The other fields in the Junifer Data object. Should have ``T1w``
|
|
54
56
|
and ``Warp`` data types.
|
|
55
|
-
reference : str
|
|
57
|
+
reference : str or Enum
|
|
56
58
|
The data type or template space to use as reference for warping.
|
|
57
59
|
|
|
58
60
|
Returns
|
|
@@ -92,7 +94,7 @@ class ANTsWarper:
|
|
|
92
94
|
|
|
93
95
|
# Create a tempfile for resampled reference output
|
|
94
96
|
resample_image_out_path = (
|
|
95
|
-
element_tempdir / "resampled_reference.nii
|
|
97
|
+
element_tempdir / "resampled_reference.nii"
|
|
96
98
|
)
|
|
97
99
|
# Set ResampleImage command
|
|
98
100
|
resample_image_cmd = [
|
|
@@ -108,21 +110,27 @@ class ANTsWarper:
|
|
|
108
110
|
run_ext_cmd(name="ResampleImage", cmd=resample_image_cmd)
|
|
109
111
|
|
|
110
112
|
# Create a tempfile for warped output
|
|
111
|
-
apply_transforms_out_path = element_tempdir / "warped_data.nii
|
|
112
|
-
#
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
apply_transforms_out_path = element_tempdir / "warped_data.nii"
|
|
114
|
+
# Call antsApplyTransforms in single precision, in chunks of
|
|
115
|
+
# volumes
|
|
116
|
+
warp_in_chunks(
|
|
117
|
+
name="antsApplyTransforms",
|
|
118
|
+
input_path=input["path"].resolve(),
|
|
119
|
+
output_path=apply_transforms_out_path.resolve(),
|
|
120
|
+
cmd=lambda in_path, out_path: [
|
|
121
|
+
"antsApplyTransforms",
|
|
122
|
+
"-d 3",
|
|
123
|
+
"-e 3",
|
|
124
|
+
"-n LanczosWindowedSinc",
|
|
125
|
+
"--float 1",
|
|
126
|
+
f"-i {in_path}",
|
|
127
|
+
# use resampled reference
|
|
128
|
+
f"-r {resample_image_out_path.resolve()}",
|
|
129
|
+
f"-t {warp_file_path.resolve()}",
|
|
130
|
+
f"-o {out_path}",
|
|
131
|
+
],
|
|
132
|
+
tempdir=element_tempdir,
|
|
133
|
+
)
|
|
126
134
|
|
|
127
135
|
logger.debug("Updating warped data")
|
|
128
136
|
input.update(
|
|
@@ -144,7 +152,7 @@ class ANTsWarper:
|
|
|
144
152
|
if input.get("mask") is not None:
|
|
145
153
|
# Create a tempfile for warped mask output
|
|
146
154
|
apply_transforms_mask_out_path = (
|
|
147
|
-
element_tempdir / "warped_mask.nii
|
|
155
|
+
element_tempdir / "warped_mask.nii"
|
|
148
156
|
)
|
|
149
157
|
# Set antsApplyTransforms command
|
|
150
158
|
apply_transforms_mask_cmd = [
|
|
@@ -152,6 +160,7 @@ class ANTsWarper:
|
|
|
152
160
|
"-d 3",
|
|
153
161
|
"-e 3",
|
|
154
162
|
"-n 'GenericLabel[NearestNeighbor]'",
|
|
163
|
+
"--float 1",
|
|
155
164
|
f"-i {input['mask']['path'].resolve()}",
|
|
156
165
|
# use resampled reference
|
|
157
166
|
f"-r {input['reference']['path'].resolve()}",
|
|
@@ -211,7 +220,7 @@ class ANTsWarper:
|
|
|
211
220
|
# Create a tempfile for resampled reference output
|
|
212
221
|
ref_path = (
|
|
213
222
|
element_tempdir
|
|
214
|
-
/ f"resampled_reference-{reference}.nii
|
|
223
|
+
/ f"resampled_reference-{reference}.nii"
|
|
215
224
|
)
|
|
216
225
|
# Set ResampleImage command
|
|
217
226
|
resample_image_cmd = [
|
|
@@ -242,27 +251,33 @@ class ANTsWarper:
|
|
|
242
251
|
extra_input=None,
|
|
243
252
|
)
|
|
244
253
|
# Save template
|
|
245
|
-
ref_path = element_tempdir / f"{reference}_T1w.nii
|
|
254
|
+
ref_path = element_tempdir / f"{reference}_T1w.nii"
|
|
246
255
|
nib.save(template_space_img, ref_path)
|
|
247
256
|
|
|
248
257
|
# Create a tempfile for warped output
|
|
249
258
|
warped_output_path = element_tempdir / (
|
|
250
|
-
f"warped_data_from_{input_space}_to_{reference}.nii
|
|
259
|
+
f"warped_data_from_{input_space}_to_{reference}.nii"
|
|
251
260
|
)
|
|
252
261
|
|
|
253
|
-
#
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"
|
|
257
|
-
"
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
# Call antsApplyTransforms in single precision, in chunks of
|
|
263
|
+
# volumes
|
|
264
|
+
warp_in_chunks(
|
|
265
|
+
name="antsApplyTransforms",
|
|
266
|
+
input_path=input["path"].resolve(),
|
|
267
|
+
output_path=warped_output_path.resolve(),
|
|
268
|
+
cmd=lambda in_path, out_path: [
|
|
269
|
+
"antsApplyTransforms",
|
|
270
|
+
"-d 3",
|
|
271
|
+
"-e 3",
|
|
272
|
+
"-n LanczosWindowedSinc",
|
|
273
|
+
"--float 1",
|
|
274
|
+
f"-i {in_path}",
|
|
275
|
+
f"-r {ref_path.resolve()}",
|
|
276
|
+
f"-t {xfm_file_path.resolve()}",
|
|
277
|
+
f"-o {out_path}",
|
|
278
|
+
],
|
|
279
|
+
tempdir=element_tempdir,
|
|
280
|
+
)
|
|
266
281
|
|
|
267
282
|
logger.debug("Updating warped data")
|
|
268
283
|
input.update(
|
|
@@ -286,7 +301,7 @@ class ANTsWarper:
|
|
|
286
301
|
logger.debug("Warping associated mask")
|
|
287
302
|
# Create a tempfile for warped mask output
|
|
288
303
|
apply_transforms_mask_out_path = element_tempdir / (
|
|
289
|
-
f"warped_mask_from_{input_space}_to_{reference}.nii
|
|
304
|
+
f"warped_mask_from_{input_space}_to_{reference}.nii"
|
|
290
305
|
)
|
|
291
306
|
# Set antsApplyTransforms command
|
|
292
307
|
apply_transforms_mask_cmd = [
|
|
@@ -294,6 +309,7 @@ class ANTsWarper:
|
|
|
294
309
|
"-d 3",
|
|
295
310
|
"-e 3",
|
|
296
311
|
"-n 'GenericLabel[NearestNeighbor]'",
|
|
312
|
+
"--float 1",
|
|
297
313
|
f"-i {input['mask']['path'].resolve()}",
|
|
298
314
|
# use resampled reference or original
|
|
299
315
|
f"-r {ref_path.resolve()}",
|
|
@@ -11,9 +11,11 @@ from typing import (
|
|
|
11
11
|
import nibabel as nib
|
|
12
12
|
import numpy as np
|
|
13
13
|
|
|
14
|
-
from ...pipeline import WorkDirManager
|
|
14
|
+
from ...pipeline import ExtDep, WorkDirManager
|
|
15
15
|
from ...typing import Dependencies, ExternalDependencies
|
|
16
|
-
from ...utils import
|
|
16
|
+
from ...utils import raise_error, run_ext_cmd
|
|
17
|
+
from ..base import logger
|
|
18
|
+
from ._utils import warp_in_chunks
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
__all__ = ["FSLWarper"]
|
|
@@ -29,7 +31,7 @@ class FSLWarper:
|
|
|
29
31
|
|
|
30
32
|
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
|
|
31
33
|
{
|
|
32
|
-
"name":
|
|
34
|
+
"name": ExtDep.FSL,
|
|
33
35
|
"commands": ["flirt", "applywarp"],
|
|
34
36
|
},
|
|
35
37
|
]
|
|
@@ -92,9 +94,10 @@ class FSLWarper:
|
|
|
92
94
|
)
|
|
93
95
|
|
|
94
96
|
# Create a tempfile for resampled reference output
|
|
95
|
-
flirt_out_path = element_tempdir / "resampled_reference.nii
|
|
97
|
+
flirt_out_path = element_tempdir / "resampled_reference.nii"
|
|
96
98
|
# Set flirt command
|
|
97
99
|
flirt_cmd = [
|
|
100
|
+
"FSLOUTPUTTYPE=NIFTI",
|
|
98
101
|
"flirt",
|
|
99
102
|
"-interp spline",
|
|
100
103
|
f"-in {extra_input['T1w']['path'].resolve()}",
|
|
@@ -106,19 +109,24 @@ class FSLWarper:
|
|
|
106
109
|
run_ext_cmd(name="flirt", cmd=flirt_cmd)
|
|
107
110
|
|
|
108
111
|
# Create a tempfile for warped output
|
|
109
|
-
applywarp_out_path = element_tempdir / "warped_data.nii
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
"applywarp",
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
112
|
+
applywarp_out_path = element_tempdir / "warped_data.nii"
|
|
113
|
+
# Call applywarp in chunks of volumes
|
|
114
|
+
warp_in_chunks(
|
|
115
|
+
name="applywarp",
|
|
116
|
+
input_path=input["path"].resolve(),
|
|
117
|
+
output_path=applywarp_out_path.resolve(),
|
|
118
|
+
cmd=lambda in_path, out_path: [
|
|
119
|
+
"FSLOUTPUTTYPE=NIFTI",
|
|
120
|
+
"applywarp",
|
|
121
|
+
"--interp=spline",
|
|
122
|
+
f"-i {in_path}",
|
|
123
|
+
# use resampled reference
|
|
124
|
+
f"-r {flirt_out_path.resolve()}",
|
|
125
|
+
f"-w {warp_file_path.resolve()}",
|
|
126
|
+
f"-o {out_path}",
|
|
127
|
+
],
|
|
128
|
+
tempdir=element_tempdir,
|
|
129
|
+
)
|
|
122
130
|
|
|
123
131
|
logger.debug("Updating warped data")
|
|
124
132
|
input.update(
|
|
@@ -139,11 +147,10 @@ class FSLWarper:
|
|
|
139
147
|
# Check for data type's mask and warp if found
|
|
140
148
|
if input.get("mask") is not None:
|
|
141
149
|
# Create a tempfile for warped mask output
|
|
142
|
-
applywarp_mask_out_path =
|
|
143
|
-
element_tempdir / "warped_mask.nii.gz"
|
|
144
|
-
)
|
|
150
|
+
applywarp_mask_out_path = element_tempdir / "warped_mask.nii"
|
|
145
151
|
# Set applywarp command
|
|
146
152
|
applywarp_mask_cmd = [
|
|
153
|
+
"FSLOUTPUTTYPE=NIFTI",
|
|
147
154
|
"applywarp",
|
|
148
155
|
"--interp=nn",
|
|
149
156
|
f"-i {input['mask']['path'].resolve()}",
|
|
@@ -200,10 +207,11 @@ class FSLWarper:
|
|
|
200
207
|
logger.debug("Resampling reference to match input resolution")
|
|
201
208
|
# Create a tempfile for resampled reference output
|
|
202
209
|
ref_path = (
|
|
203
|
-
element_tempdir / f"resampled_reference-{reference}.nii
|
|
210
|
+
element_tempdir / f"resampled_reference-{reference}.nii"
|
|
204
211
|
)
|
|
205
212
|
# Set flirt command
|
|
206
213
|
flirt_cmd = [
|
|
214
|
+
"FSLOUTPUTTYPE=NIFTI",
|
|
207
215
|
"flirt",
|
|
208
216
|
"-interp spline",
|
|
209
217
|
f"-in {input['reference']['path'].resolve()}",
|
|
@@ -219,21 +227,25 @@ class FSLWarper:
|
|
|
219
227
|
|
|
220
228
|
# Create a tempfile for warped output
|
|
221
229
|
applywarp_out_path = (
|
|
222
|
-
element_tempdir
|
|
223
|
-
|
|
230
|
+
element_tempdir / f"warped_data_from_native_to_{reference}.nii"
|
|
231
|
+
)
|
|
232
|
+
# Call applywarp in chunks of volumes
|
|
233
|
+
warp_in_chunks(
|
|
234
|
+
name="applywarp",
|
|
235
|
+
input_path=input["path"].resolve(),
|
|
236
|
+
output_path=applywarp_out_path.resolve(),
|
|
237
|
+
cmd=lambda in_path, out_path: [
|
|
238
|
+
"FSLOUTPUTTYPE=NIFTI",
|
|
239
|
+
"applywarp",
|
|
240
|
+
"--interp=spline",
|
|
241
|
+
f"-i {in_path}",
|
|
242
|
+
# use resampled reference or original
|
|
243
|
+
f"-r {ref_path.resolve()}",
|
|
244
|
+
f"-w {warp_file_path.resolve()}",
|
|
245
|
+
f"-o {out_path}",
|
|
246
|
+
],
|
|
247
|
+
tempdir=element_tempdir,
|
|
224
248
|
)
|
|
225
|
-
# Set applywarp command
|
|
226
|
-
applywarp_cmd = [
|
|
227
|
-
"applywarp",
|
|
228
|
-
"--interp=spline",
|
|
229
|
-
f"-i {input['path'].resolve()}",
|
|
230
|
-
# use resampled reference or original
|
|
231
|
-
f"-r {ref_path.resolve()}",
|
|
232
|
-
f"-w {warp_file_path.resolve()}",
|
|
233
|
-
f"-o {applywarp_out_path.resolve()}",
|
|
234
|
-
]
|
|
235
|
-
# Call applywarp
|
|
236
|
-
run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
|
|
237
249
|
|
|
238
250
|
logger.debug("Updating warped data")
|
|
239
251
|
input.update(
|
|
@@ -257,10 +269,11 @@ class FSLWarper:
|
|
|
257
269
|
# Create a tempfile for warped mask output
|
|
258
270
|
applywarp_mask_out_path = (
|
|
259
271
|
element_tempdir
|
|
260
|
-
/ f"warped_mask_from_native_to_{reference}.nii
|
|
272
|
+
/ f"warped_mask_from_native_to_{reference}.nii"
|
|
261
273
|
)
|
|
262
274
|
# Set applywarp command
|
|
263
275
|
applywarp_mask_cmd = [
|
|
276
|
+
"FSLOUTPUTTYPE=NIFTI",
|
|
264
277
|
"applywarp",
|
|
265
278
|
"--interp=nn",
|
|
266
279
|
f"-i {input['mask']['path'].resolve()}",
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Provide utilities for warping."""
|
|
2
|
+
|
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
|
+
# License: AGPL
|
|
5
|
+
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import nibabel as nib
|
|
10
|
+
import numpy as np
|
|
11
|
+
from tqdm import tqdm
|
|
12
|
+
|
|
13
|
+
from ...utils import config, raise_error, run_ext_cmd
|
|
14
|
+
from ..base import logger
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = ["warp_in_chunks"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def warp_in_chunks(
|
|
21
|
+
name: str,
|
|
22
|
+
input_path: Path,
|
|
23
|
+
output_path: Path,
|
|
24
|
+
cmd: Callable[[Path, Path], list[str]],
|
|
25
|
+
tempdir: Path,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Warp an image, in chunks of volumes if it is 4D.
|
|
28
|
+
|
|
29
|
+
The memory used by the warping commands grows with the number of volumes,
|
|
30
|
+
so the volumes of a 4D image are warped in chunks of
|
|
31
|
+
``preprocessing.warping.chunksize`` volumes (default 100), which are then
|
|
32
|
+
concatenated. The volumes are warped independently, so the result is the
|
|
33
|
+
same as warping the whole image.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
name : str
|
|
38
|
+
The name of the warping command.
|
|
39
|
+
input_path : pathlib.Path
|
|
40
|
+
The path of the image to warp.
|
|
41
|
+
output_path : pathlib.Path
|
|
42
|
+
The path of the warped image.
|
|
43
|
+
cmd : callable
|
|
44
|
+
A function that returns the command to warp an image, given the paths
|
|
45
|
+
of the image to warp and of the warped image.
|
|
46
|
+
tempdir : pathlib.Path
|
|
47
|
+
The directory for the chunks.
|
|
48
|
+
|
|
49
|
+
Raises
|
|
50
|
+
------
|
|
51
|
+
ValueError
|
|
52
|
+
If ``preprocessing.warping.chunksize`` is not a positive integer.
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
chunk_size = config.get("preprocessing.warping.chunksize", 100)
|
|
56
|
+
if (
|
|
57
|
+
isinstance(chunk_size, bool)
|
|
58
|
+
or not isinstance(chunk_size, int)
|
|
59
|
+
or chunk_size < 1
|
|
60
|
+
):
|
|
61
|
+
raise_error(
|
|
62
|
+
"`preprocessing.warping.chunksize` must be a positive integer, "
|
|
63
|
+
f"but is {chunk_size}"
|
|
64
|
+
)
|
|
65
|
+
img = nib.load(input_path)
|
|
66
|
+
if img.ndim != 4 or img.shape[3] <= chunk_size:
|
|
67
|
+
run_ext_cmd(name=name, cmd=cmd(input_path, output_path))
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
n_volumes = img.shape[3]
|
|
71
|
+
starts = range(0, n_volumes, chunk_size)
|
|
72
|
+
logger.info(
|
|
73
|
+
f"Warping {n_volumes} volumes in {len(starts)} chunks of up to "
|
|
74
|
+
f"{chunk_size} volumes"
|
|
75
|
+
)
|
|
76
|
+
warped_chunks = []
|
|
77
|
+
for i, start in enumerate(tqdm(starts, desc=f"{name} chunks")):
|
|
78
|
+
# Uncompressed, as they are deleted right after being read
|
|
79
|
+
chunk_path = tempdir / f"chunk{i}_input_{output_path.stem}.nii"
|
|
80
|
+
warped_chunk_path = tempdir / f"chunk{i}_{output_path.stem}.nii"
|
|
81
|
+
chunk = img.slicer[..., start : start + chunk_size]
|
|
82
|
+
# The data is read scaled, so save it as float instead of scaling it
|
|
83
|
+
# again (with a different scaling) in its data type
|
|
84
|
+
if img.dataobj.slope != 1 or img.dataobj.inter != 0:
|
|
85
|
+
chunk.set_data_dtype(np.float32)
|
|
86
|
+
nib.save(chunk, chunk_path)
|
|
87
|
+
run_ext_cmd(name=name, cmd=cmd(chunk_path, warped_chunk_path))
|
|
88
|
+
chunk_path.unlink()
|
|
89
|
+
warped_chunks.append(warped_chunk_path)
|
|
90
|
+
|
|
91
|
+
# Fill the data of the warped image with the warped chunks (instead of
|
|
92
|
+
# concatenating them, which needs twice the memory)
|
|
93
|
+
data = None
|
|
94
|
+
for start, warped_chunk_path in zip(starts, warped_chunks, strict=True):
|
|
95
|
+
warped_chunk = nib.load(warped_chunk_path)
|
|
96
|
+
chunk_data = np.asanyarray(warped_chunk.dataobj)
|
|
97
|
+
if data is None:
|
|
98
|
+
first = warped_chunk
|
|
99
|
+
data = np.empty(
|
|
100
|
+
(*chunk_data.shape[:3], n_volumes), dtype=chunk_data.dtype
|
|
101
|
+
)
|
|
102
|
+
data[..., start : start + chunk_data.shape[3]] = chunk_data
|
|
103
|
+
warped_chunk_path.unlink()
|
|
104
|
+
warped = nib.Nifti1Image(data, first.affine, first.header)
|
|
105
|
+
warped.set_data_dtype(data.dtype)
|
|
106
|
+
nib.save(warped, output_path)
|