[ENH]: Refactor Preprocessors to sync data and their paths #408
9 changed files with 290 additions and 118 deletions
1
docs/changes/newsfragments/408.enh
Normal file
1
docs/changes/newsfragments/408.enh
Normal file
|
|
@ -0,0 +1 @@
|
|||
Update Preprocessors to sync data their paths so that the results are idempotent by `Synchon Mandal`_
|
||||
1
docs/changes/newsfragments/408.feature
Normal file
1
docs/changes/newsfragments/408.feature
Normal file
|
|
@ -0,0 +1 @@
|
|||
Allow masks to be warped, if found, in :class:`.SpaceWarper` by `Synchon Mandal`_
|
||||
|
|
@ -12,6 +12,7 @@ from typing import (
|
|||
Union,
|
||||
)
|
||||
|
||||
import nibabel as nib
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from nilearn import image as nimg
|
||||
|
|
@ -19,6 +20,7 @@ from nilearn._utils.niimg_conversions import check_niimg_4d
|
|||
|
||||
from ...api.decorators import register_preprocessor
|
||||
from ...data import get_data
|
||||
from ...pipeline import WorkDirManager
|
||||
from ...typing import Dependencies
|
||||
from ...utils import logger, raise_error
|
||||
from ..base import BasePreprocessor
|
||||
|
|
@ -539,9 +541,17 @@ class fMRIPrepConfoundRemover(BasePreprocessor):
|
|||
logger.info(
|
||||
f"Read t_r from NIfTI header: {t_r}",
|
||||
)
|
||||
|
||||
# Create element-specific tempdir for storing generated data
|
||||
# and / or mask
|
||||
element_tempdir = WorkDirManager().get_element_tempdir(
|
||||
prefix="fmriprep_confound_remover"
|
||||
)
|
||||
|
||||
# Set mask data
|
||||
mask_img = None
|
||||
if self.masks is not None:
|
||||
# Generate mask
|
||||
logger.debug(f"Masking with {self.masks}")
|
||||
mask_img = get_data(
|
||||
kind="mask",
|
||||
|
|
@ -549,13 +559,21 @@ class fMRIPrepConfoundRemover(BasePreprocessor):
|
|||
target_data=input,
|
||||
extra_input=extra_input,
|
||||
)
|
||||
# Return the BOLD mask and link it to the BOLD data type dict;
|
||||
# Save generated mask for use later
|
||||
generated_mask_img_path = element_tempdir / "generated_mask.nii.gz"
|
||||
nib.save(mask_img, generated_mask_img_path)
|
||||
|
||||
# Save BOLD mask and link it to the BOLD data type dict;
|
||||
# this allows to use "inherit" down the pipeline
|
||||
logger.debug("Setting `BOLD.mask`")
|
||||
input.update(
|
||||
{
|
||||
"mask": {
|
||||
# Update path to sync with "data"
|
||||
"path": generated_mask_img_path,
|
||||
# Update data
|
||||
"data": mask_img,
|
||||
# Should be in the same space as target data
|
||||
"space": input["space"],
|
||||
}
|
||||
}
|
||||
|
|
@ -566,7 +584,9 @@ class fMRIPrepConfoundRemover(BasePreprocessor):
|
|||
logger.debug(f"\tstandardize: {self.standardize}")
|
||||
logger.debug(f"\tlow_pass: {self.low_pass}")
|
||||
logger.debug(f"\thigh_pass: {self.high_pass}")
|
||||
input["data"] = nimg.clean_img(
|
||||
|
||||
# Deconfound data
|
||||
cleaned_img = nimg.clean_img(
|
||||
imgs=bold_img,
|
||||
detrend=self.detrend,
|
||||
standardize=self.standardize,
|
||||
|
|
@ -576,5 +596,18 @@ class fMRIPrepConfoundRemover(BasePreprocessor):
|
|||
t_r=t_r,
|
||||
mask_img=mask_img,
|
||||
)
|
||||
# Save deconfounded data
|
||||
deconfounded_img_path = element_tempdir / "deconfounded_data.nii.gz"
|
||||
nib.save(cleaned_img, deconfounded_img_path)
|
||||
|
||||
logger.debug("Updating `BOLD`")
|
||||
input.update(
|
||||
{
|
||||
# Update path to sync with "data"
|
||||
"path": deconfounded_img_path,
|
||||
# Update data
|
||||
"data": cleaned_img,
|
||||
}
|
||||
)
|
||||
|
||||
return input, None
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# License: AGPL
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
ClassVar,
|
||||
Union,
|
||||
)
|
||||
|
|
@ -16,10 +16,6 @@ from ...typing import Dependencies, ExternalDependencies
|
|||
from ...utils import logger, run_ext_cmd
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from nibabel.nifti1 import Nifti1Image
|
||||
|
||||
|
||||
__all__ = ["AFNISmoothing"]
|
||||
|
||||
|
||||
|
|
@ -41,23 +37,23 @@ class AFNISmoothing:
|
|||
|
||||
def preprocess(
|
||||
self,
|
||||
data: "Nifti1Image",
|
||||
input: dict[str, Any],
|
||||
fwhm: Union[int, float],
|
||||
) -> "Nifti1Image":
|
||||
) -> dict[str, Any]:
|
||||
"""Preprocess using AFNI.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : Niimg-like object
|
||||
Image(s) to preprocess.
|
||||
input : dict
|
||||
A single input from the Junifer Data object in which to preprocess.
|
||||
fwhm : int or float
|
||||
Smooth until the value. AFNI estimates the smoothing and then
|
||||
applies smoothing to reach ``fwhm``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Niimg-like object
|
||||
The preprocessed image(s).
|
||||
dict
|
||||
The ``input`` dictionary with updated values.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
|
@ -71,18 +67,18 @@ class AFNISmoothing:
|
|||
"""
|
||||
logger.info("Smoothing using AFNI")
|
||||
|
||||
# Create component-scoped tempdir
|
||||
tempdir = WorkDirManager().get_tempdir(prefix="afni_smoothing")
|
||||
|
||||
# Save target data to a component-scoped tempfile
|
||||
nifti_in_file_path = tempdir / "input.nii" # needs to be .nii
|
||||
nib.save(data, nifti_in_file_path)
|
||||
# Create element-scoped tempdir so that the output is
|
||||
# available later as nibabel stores file path reference for
|
||||
# loading on computation
|
||||
element_tempdir = WorkDirManager().get_element_tempdir(
|
||||
prefix="afni_smoothing"
|
||||
)
|
||||
|
||||
# Set 3dBlurToFWHM command
|
||||
blur_out_path_prefix = tempdir / "blur"
|
||||
blur_out_path_prefix = element_tempdir / "blur"
|
||||
blur_cmd = [
|
||||
"3dBlurToFWHM",
|
||||
f"-input {nifti_in_file_path.resolve()}",
|
||||
f"-input {input['path'].resolve()}",
|
||||
f"-prefix {blur_out_path_prefix.resolve()}",
|
||||
"-automask",
|
||||
f"-FWHM {fwhm}",
|
||||
|
|
@ -90,28 +86,34 @@ class AFNISmoothing:
|
|||
# Call 3dBlurToFWHM
|
||||
run_ext_cmd(name="3dBlurToFWHM", cmd=blur_cmd)
|
||||
|
||||
# Create element-scoped tempdir so that the blurred output is
|
||||
# available later as nibabel stores file path reference for
|
||||
# loading on computation
|
||||
element_tempdir = WorkDirManager().get_element_tempdir(
|
||||
prefix="afni_blur"
|
||||
)
|
||||
# Read header to get output suffix
|
||||
header = input["data"].header
|
||||
sform_code = header.get_sform(coded=True)[1]
|
||||
if sform_code == 4:
|
||||
output_suffix = "tlrc"
|
||||
else:
|
||||
output_suffix = "orig"
|
||||
|
||||
# Convert afni to nifti
|
||||
blur_afni_to_nifti_out_path = (
|
||||
element_tempdir / "output.nii" # needs to be .nii
|
||||
blur_nifti_out_path = (
|
||||
element_tempdir / "smoothed_data.nii" # needs to be .nii
|
||||
)
|
||||
convert_cmd = [
|
||||
"3dAFNItoNIFTI",
|
||||
f"-prefix {blur_afni_to_nifti_out_path.resolve()}",
|
||||
f"{blur_out_path_prefix}+orig.BRIK",
|
||||
f"-prefix {blur_nifti_out_path.resolve()}",
|
||||
f"{blur_out_path_prefix}+{output_suffix}.BRIK",
|
||||
]
|
||||
# Call 3dAFNItoNIFTI
|
||||
run_ext_cmd(name="3dAFNItoNIFTI", cmd=convert_cmd)
|
||||
|
||||
logger.debug("Updating smoothed data")
|
||||
input.update(
|
||||
{
|
||||
# Update path to sync with "data"
|
||||
"path": blur_nifti_out_path,
|
||||
# Load nifti
|
||||
output_data = nib.load(blur_afni_to_nifti_out_path)
|
||||
"data": nib.load(blur_nifti_out_path),
|
||||
}
|
||||
)
|
||||
|
||||
# Delete tempdir
|
||||
WorkDirManager().delete_tempdir(tempdir)
|
||||
|
||||
return output_data # type: ignore
|
||||
return input
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# License: AGPL
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
ClassVar,
|
||||
)
|
||||
|
||||
|
|
@ -15,10 +15,6 @@ from ...typing import Dependencies, ExternalDependencies
|
|||
from ...utils import logger, run_ext_cmd
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from nibabel.nifti1 import Nifti1Image
|
||||
|
||||
|
||||
__all__ = ["FSLSmoothing"]
|
||||
|
||||
|
||||
|
|
@ -40,16 +36,16 @@ class FSLSmoothing:
|
|||
|
||||
def preprocess(
|
||||
self,
|
||||
data: "Nifti1Image",
|
||||
input: dict[str, Any],
|
||||
brightness_threshold: float,
|
||||
fwhm: float,
|
||||
) -> "Nifti1Image":
|
||||
) -> dict[str, Any]:
|
||||
"""Preprocess using FSL.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : Niimg-like object
|
||||
Image(s) to preprocess.
|
||||
input : dict
|
||||
A single input from the Junifer Data object in which to preprocess.
|
||||
brightness_threshold : float
|
||||
Threshold to discriminate between noise and the underlying image.
|
||||
The value should be set greater than the noise level and less than
|
||||
|
|
@ -59,8 +55,8 @@ class FSLSmoothing:
|
|||
|
||||
Returns
|
||||
-------
|
||||
Niimg-like object
|
||||
The preprocessed image(s).
|
||||
dict
|
||||
The ``input`` dictionary with updated values.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
|
@ -76,24 +72,17 @@ class FSLSmoothing:
|
|||
"""
|
||||
logger.info("Smoothing using FSL")
|
||||
|
||||
# Create component-scoped tempdir
|
||||
tempdir = WorkDirManager().get_tempdir(prefix="fsl_smoothing")
|
||||
|
||||
# Save target data to a component-scoped tempfile
|
||||
nifti_in_file_path = tempdir / "input.nii.gz"
|
||||
nib.save(data, nifti_in_file_path)
|
||||
|
||||
# Create element-scoped tempdir so that the output is
|
||||
# available later as nibabel stores file path reference for
|
||||
# loading on computation
|
||||
element_tempdir = WorkDirManager().get_element_tempdir(
|
||||
prefix="fsl_susan"
|
||||
)
|
||||
susan_out_path = element_tempdir / "output.nii.gz"
|
||||
susan_out_path = element_tempdir / "smoothed_data.nii.gz"
|
||||
# Set susan command
|
||||
susan_cmd = [
|
||||
"susan",
|
||||
f"{nifti_in_file_path.resolve()}",
|
||||
f"{input['path'].resolve()}",
|
||||
f"{brightness_threshold}",
|
||||
f"{fwhm}",
|
||||
"3", # dimension
|
||||
|
|
@ -104,10 +93,14 @@ class FSLSmoothing:
|
|||
# Call susan
|
||||
run_ext_cmd(name="susan", cmd=susan_cmd)
|
||||
|
||||
logger.debug("Updating smoothed data")
|
||||
input.update(
|
||||
{
|
||||
# Update path to sync with "data"
|
||||
"path": susan_out_path,
|
||||
# Load nifti
|
||||
output_data = nib.load(susan_out_path)
|
||||
"data": nib.load(susan_out_path),
|
||||
}
|
||||
)
|
||||
|
||||
# Delete tempdir
|
||||
WorkDirManager().delete_tempdir(tempdir)
|
||||
|
||||
return output_data # type: ignore
|
||||
return input
|
||||
|
|
|
|||
|
|
@ -4,23 +4,21 @@
|
|||
# License: AGPL
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
ClassVar,
|
||||
Literal,
|
||||
Union,
|
||||
)
|
||||
|
||||
import nibabel as nib
|
||||
from nilearn import image as nimg
|
||||
from numpy.typing import ArrayLike
|
||||
|
||||
from ...pipeline import WorkDirManager
|
||||
from ...typing import Dependencies
|
||||
from ...utils import logger
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from nibabel.nifti1 import Nifti1Image
|
||||
|
||||
|
||||
__all__ = ["NilearnSmoothing"]
|
||||
|
||||
|
||||
|
|
@ -35,15 +33,15 @@ class NilearnSmoothing:
|
|||
|
||||
def preprocess(
|
||||
self,
|
||||
data: "Nifti1Image",
|
||||
input: dict[str, Any],
|
||||
fwhm: Union[int, float, ArrayLike, Literal["fast"], None],
|
||||
) -> "Nifti1Image":
|
||||
) -> dict[str, Any]:
|
||||
"""Preprocess using nilearn.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : Niimg-like object
|
||||
Image(s) to preprocess.
|
||||
input : dict
|
||||
A single input from the Junifer Data object in which to preprocess.
|
||||
fwhm : scalar, ``numpy.ndarray``, tuple or list of scalar, "fast" or \
|
||||
None
|
||||
Smoothing strength, as a full-width at half maximum, in
|
||||
|
|
@ -61,9 +59,32 @@ class NilearnSmoothing:
|
|||
|
||||
Returns
|
||||
-------
|
||||
Niimg-like object
|
||||
The preprocessed image(s).
|
||||
dict
|
||||
The ``input`` dictionary with updated values.
|
||||
|
||||
"""
|
||||
logger.info("Smoothing using nilearn")
|
||||
return nimg.smooth_img(imgs=data, fwhm=fwhm) # type: ignore
|
||||
|
||||
# Create element-scoped tempdir so that the output is
|
||||
# available later as nibabel stores file path reference for
|
||||
# loading on computation
|
||||
element_tempdir = WorkDirManager().get_element_tempdir(
|
||||
prefix="nilearn_smoothing"
|
||||
)
|
||||
|
||||
smoothed_img = nimg.smooth_img(imgs=input["data"], fwhm=fwhm)
|
||||
|
||||
# Save smoothed output
|
||||
smoothed_img_path = element_tempdir / "smoothed_data.nii.gz"
|
||||
nib.save(smoothed_img, smoothed_img_path)
|
||||
|
||||
logger.debug("Updating smoothed data")
|
||||
input.update(
|
||||
{
|
||||
# Update path to sync with "data"
|
||||
"path": smoothed_img_path,
|
||||
"data": smoothed_img,
|
||||
}
|
||||
)
|
||||
|
||||
return input
|
||||
|
|
|
|||
|
|
@ -164,12 +164,9 @@ class Smoothing(BasePreprocessor):
|
|||
elif self.using == "fsl":
|
||||
preprocessor = FSLSmoothing()
|
||||
# Smooth
|
||||
output = preprocessor.preprocess( # type: ignore
|
||||
data=input["data"],
|
||||
input = preprocessor.preprocess(
|
||||
input=input,
|
||||
**self.smoothing_params,
|
||||
)
|
||||
|
||||
# Modify target data
|
||||
input["data"] = output
|
||||
|
||||
return input, None
|
||||
|
|
|
|||
|
|
@ -58,9 +58,7 @@ class ANTsWarper:
|
|||
Returns
|
||||
-------
|
||||
dict
|
||||
The ``input`` dictionary with modified ``data`` and ``space`` key
|
||||
values and new ``reference`` key whose value points to the
|
||||
reference file used for warping.
|
||||
The ``input`` dictionary with updated values.
|
||||
|
||||
Raises
|
||||
------
|
||||
|
|
@ -110,7 +108,7 @@ class ANTsWarper:
|
|||
run_ext_cmd(name="ResampleImage", cmd=resample_image_cmd)
|
||||
|
||||
# Create a tempfile for warped output
|
||||
apply_transforms_out_path = element_tempdir / "output.nii.gz"
|
||||
apply_transforms_out_path = element_tempdir / "warped_data.nii.gz"
|
||||
# Set antsApplyTransforms command
|
||||
apply_transforms_cmd = [
|
||||
"antsApplyTransforms",
|
||||
|
|
@ -126,14 +124,59 @@ class ANTsWarper:
|
|||
# Call antsApplyTransforms
|
||||
run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
|
||||
|
||||
logger.debug("Updating warped data")
|
||||
input.update(
|
||||
{
|
||||
# Update path to sync with "data"
|
||||
"path": apply_transforms_out_path,
|
||||
# Load nifti
|
||||
input["data"] = nib.load(apply_transforms_out_path)
|
||||
# Save resampled reference path
|
||||
input["reference"] = {"path": resample_image_out_path}
|
||||
# Keep pre-warp space for further operations
|
||||
input["prewarp_space"] = input["space"]
|
||||
"data": nib.load(apply_transforms_out_path),
|
||||
# Use reference input's space as warped input's space
|
||||
input["space"] = extra_input["T1w"]["space"]
|
||||
"space": extra_input["T1w"]["space"],
|
||||
# Save resampled reference path
|
||||
"reference": {"path": resample_image_out_path},
|
||||
# Keep pre-warp space for further operations
|
||||
"prewarp_space": input["space"],
|
||||
}
|
||||
)
|
||||
|
||||
# Check for data type's mask and warp if found
|
||||
if input.get("mask") is not None:
|
||||
# Create a tempfile for warped mask output
|
||||
apply_transforms_mask_out_path = (
|
||||
element_tempdir / "warped_mask.nii.gz"
|
||||
)
|
||||
# Set antsApplyTransforms command
|
||||
apply_transforms_mask_cmd = [
|
||||
"antsApplyTransforms",
|
||||
"-d 3",
|
||||
"-e 3",
|
||||
"-n 'GenericLabel[NearestNeighbor]'",
|
||||
f"-i {input['mask']['path'].resolve()}",
|
||||
# use resampled reference
|
||||
f"-r {input['reference']['path'].resolve()}",
|
||||
f"-t {warp_file_path.resolve()}",
|
||||
f"-o {apply_transforms_mask_out_path.resolve()}",
|
||||
]
|
||||
# Call antsApplyTransforms
|
||||
run_ext_cmd(
|
||||
name="antsApplyTransforms", cmd=apply_transforms_mask_cmd
|
||||
)
|
||||
|
||||
logger.debug("Updating warped mask data")
|
||||
input.update(
|
||||
{
|
||||
"mask": {
|
||||
# Update path to sync with "data"
|
||||
"path": apply_transforms_mask_out_path,
|
||||
# Load nifti
|
||||
"data": nib.load(apply_transforms_mask_out_path),
|
||||
# Use reference input's space as warped input
|
||||
# mask's space
|
||||
"space": extra_input["T1w"]["space"],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Template space warping
|
||||
else:
|
||||
|
|
@ -149,16 +192,15 @@ class ANTsWarper:
|
|||
target_data=input,
|
||||
extra_input=None,
|
||||
)
|
||||
|
||||
# Create component-scoped tempdir
|
||||
tempdir = WorkDirManager().get_tempdir(prefix="ants_warper")
|
||||
# Save template
|
||||
template_space_img_path = tempdir / f"{reference}_T1w.nii.gz"
|
||||
template_space_img_path = (
|
||||
element_tempdir / f"{reference}_T1w.nii.gz"
|
||||
)
|
||||
nib.save(template_space_img, template_space_img_path)
|
||||
|
||||
# Create a tempfile for warped output
|
||||
warped_output_path = element_tempdir / (
|
||||
f"data_warped_from_{input['space']}_to_" f"{reference}.nii.gz"
|
||||
f"warped_data_from_{input['space']}_to_{reference}.nii.gz"
|
||||
)
|
||||
|
||||
# Set antsApplyTransforms command
|
||||
|
|
@ -175,14 +217,58 @@ class ANTsWarper:
|
|||
# Call antsApplyTransforms
|
||||
run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
|
||||
|
||||
# Delete tempdir
|
||||
WorkDirManager().delete_tempdir(tempdir)
|
||||
|
||||
# Modify target data
|
||||
input["data"] = nib.load(warped_output_path)
|
||||
# Keep pre-warp space for further operations
|
||||
input["prewarp_space"] = input["space"]
|
||||
logger.debug("Updating warped data")
|
||||
input.update(
|
||||
{
|
||||
# Update path to sync with "data"
|
||||
"path": warped_output_path,
|
||||
# Load nifti
|
||||
"data": nib.load(warped_output_path),
|
||||
# Update warped input's space
|
||||
input["space"] = reference
|
||||
"space": reference,
|
||||
# Save reference path
|
||||
"reference": {"path": template_space_img_path},
|
||||
# Keep pre-warp space for further operations
|
||||
"prewarp_space": input["space"],
|
||||
}
|
||||
)
|
||||
|
||||
# Check for data type's mask and warp if found
|
||||
if input.get("mask") is not None:
|
||||
# Create a tempfile for warped mask output
|
||||
apply_transforms_mask_out_path = element_tempdir / (
|
||||
f"warped_mask_from_{input['space']}_to_"
|
||||
f"{reference}.nii.gz"
|
||||
)
|
||||
# Set antsApplyTransforms command
|
||||
apply_transforms_mask_cmd = [
|
||||
"antsApplyTransforms",
|
||||
"-d 3",
|
||||
"-e 3",
|
||||
"-n 'GenericLabel[NearestNeighbor]'",
|
||||
f"-i {input['mask']['path'].resolve()}",
|
||||
# use resampled reference
|
||||
f"-r {input['reference']['path'].resolve()}",
|
||||
f"-t {xfm_file_path.resolve()}",
|
||||
f"-o {apply_transforms_mask_out_path.resolve()}",
|
||||
]
|
||||
# Call antsApplyTransforms
|
||||
run_ext_cmd(
|
||||
name="antsApplyTransforms", cmd=apply_transforms_mask_cmd
|
||||
)
|
||||
|
||||
logger.debug("Updating warped mask data")
|
||||
input.update(
|
||||
{
|
||||
"mask": {
|
||||
# Update path to sync with "data"
|
||||
"path": apply_transforms_mask_out_path,
|
||||
# Load nifti
|
||||
"data": nib.load(apply_transforms_mask_out_path),
|
||||
# Update warped input mask's space
|
||||
"space": reference,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return input
|
||||
|
|
|
|||
|
|
@ -54,9 +54,7 @@ class FSLWarper:
|
|||
Returns
|
||||
-------
|
||||
dict
|
||||
The ``input`` dictionary with modified ``data`` and ``space`` key
|
||||
values and new ``reference`` key whose value points to the
|
||||
reference file used for warping.
|
||||
The ``input`` dictionary with updated values.
|
||||
|
||||
Raises
|
||||
------
|
||||
|
|
@ -100,26 +98,66 @@ class FSLWarper:
|
|||
run_ext_cmd(name="flirt", cmd=flirt_cmd)
|
||||
|
||||
# Create a tempfile for warped output
|
||||
applywarp_out_path = element_tempdir / "output.nii.gz"
|
||||
applywarp_out_path = element_tempdir / "warped_data.nii.gz"
|
||||
# Set applywarp command
|
||||
applywarp_cmd = [
|
||||
"applywarp",
|
||||
"--interp=spline",
|
||||
f"-i {input['path'].resolve()}",
|
||||
f"-r {flirt_out_path.resolve()}", # use resampled reference
|
||||
# use resampled reference
|
||||
f"-r {flirt_out_path.resolve()}",
|
||||
f"-w {warp_file_path.resolve()}",
|
||||
f"-o {applywarp_out_path.resolve()}",
|
||||
]
|
||||
# Call applywarp
|
||||
run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
|
||||
|
||||
logger.debug("Updating warped data")
|
||||
input.update(
|
||||
{
|
||||
# Update path to sync with "data"
|
||||
"path": applywarp_out_path,
|
||||
# Load nifti
|
||||
input["data"] = nib.load(applywarp_out_path)
|
||||
# Save resampled reference path
|
||||
input["reference"] = {"path": flirt_out_path}
|
||||
# Keep pre-warp space for further operations
|
||||
input["prewarp_space"] = input["space"]
|
||||
"data": nib.load(applywarp_out_path),
|
||||
# Use reference input's space as warped input's space
|
||||
input["space"] = extra_input["T1w"]["space"]
|
||||
"space": extra_input["T1w"]["space"],
|
||||
# Save resampled reference path
|
||||
"reference": {"path": flirt_out_path},
|
||||
# Keep pre-warp space for further operations
|
||||
"prewarp_space": input["space"],
|
||||
}
|
||||
)
|
||||
|
||||
# Check for data type's mask and warp if found
|
||||
if input.get("mask") is not None:
|
||||
# Create a tempfile for warped mask output
|
||||
applywarp_mask_out_path = element_tempdir / "warped_mask.nii.gz"
|
||||
# Set applywarp command
|
||||
applywarp_mask_cmd = [
|
||||
"applywarp",
|
||||
"--interp=nn",
|
||||
f"-i {input['mask']['path'].resolve()}",
|
||||
# use resampled reference
|
||||
f"-r {input['reference']['path'].resolve()}",
|
||||
f"-w {warp_file_path.resolve()}",
|
||||
f"-o {applywarp_mask_out_path.resolve()}",
|
||||
]
|
||||
# Call applywarp
|
||||
run_ext_cmd(name="applywarp", cmd=applywarp_mask_cmd)
|
||||
|
||||
logger.debug("Updating warped mask data")
|
||||
input.update(
|
||||
{
|
||||
"mask": {
|
||||
# Update path to sync with "data"
|
||||
"path": applywarp_mask_out_path,
|
||||
# Load nifti
|
||||
"data": nib.load(applywarp_mask_out_path),
|
||||
# Use reference input's space as warped input mask's
|
||||
# space
|
||||
"space": extra_input["T1w"]["space"],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return input
|
||||
|
|
|
|||
Loading…
Reference in a new issue