diff --git a/README.md b/README.md index 77962ed..0eec56d 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Below is a list of all planned interfaces, with completed interfaces checked. Th ### Preprocess - [x] ApplyWarp (`applywarp`) -- [ ] ApplyXFM (`flirt`) +- [X] ApplyXFM (`flirt`) - [x] BET (`bet`) - [x] FAST (`fast`) - [x] FIRST (`first`) diff --git a/pydra/tasks/fsl/preprocess/applyxfm.py b/pydra/tasks/fsl/preprocess/applyxfm.py new file mode 100644 index 0000000..2aaf749 --- /dev/null +++ b/pydra/tasks/fsl/preprocess/applyxfm.py @@ -0,0 +1,75 @@ +from pydra.engine import specs +from .flirt import FLIRT + +input_fields = [ + ( + "in_file", + specs.File, + { + "help_string": "input file", + "argstr": "-in {in_file}", + "mandatory": True, + "position": 0, + }, + ), + ( + "reference", + specs.File, + { + "help_string": "reference file", + "argstr": "-ref {reference}", + "mandatory": True, + "position": 1, + }, + ), + ( + "apply_xfm", + bool, + True, + { + "help_string": "apply transformation supplied by in_matrix_file or uses_qform to use the affine matrix stored in the reference header", + "argstr": "-applyxfm", + }, + ), + ( + "in_matrix_file", + str, + { + "help_string": "input 4x4 affine matrix", + "argstr": "-init {in_matrix_file}", + "mandatory": True, + }, + ), + ( + "out_file", + str, + { + "help_string": "registered output file", + "argstr": "-out {out_file}", + "position": 2, + "output_file_template": "{in_file}_flirt", + }, + ), +] + +ApplyXFM_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) + + +class ApplyXFM(FLIRT): + """ + Example + ------- + >>> task = ApplyXFM() + >>> task.inputs.in_file = 'test.nii.gz' + >>> task.inputs.in_matrix_file = 'transform.mat' + >>> task.inputs.reference = 'dest.nii.gz' + >>> task.cmdline # doctest: +ELLIPSIS + 'flirt -in test.nii.gz -ref dest.nii.gz -out .../test_flirt.nii.gz -applyxfm -init transform.mat' + + # using a custom outfile + >>> task.inputs.out_file = 'custom_outfile.nii.gz' + >>> task.cmdline + 'flirt -in test.nii.gz -ref dest.nii.gz -out custom_outfile.nii.gz -applyxfm -init transform.mat' + """ + + input_spec = ApplyXFM_input_spec diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_applyxfm.py b/pydra/tasks/fsl/preprocess/tests/test_run_applyxfm.py new file mode 100644 index 0000000..f4d41b6 --- /dev/null +++ b/pydra/tasks/fsl/preprocess/tests/test_run_applyxfm.py @@ -0,0 +1,38 @@ +import os, pytest +from pathlib import Path +from ..applyxfm import ApplyXFM + + +@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) +@pytest.mark.parametrize("inputs, outputs", [(None, ["out_file"])]) +def test_ApplyXFM(test_data, inputs, outputs): + in_file = Path(test_data) / "test.nii.gz" + reference = Path(test_data) / "test.nii.gz" + in_matrix_file = Path(test_data) / "transform.mat" + if inputs is None: + inputs = {} + for key, val in inputs.items(): + try: + inputs[key] = eval(val) + except: + pass + task = ApplyXFM(in_file=in_file, reference=reference, in_matrix_file=in_matrix_file, **inputs) + assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) + res = task() + print("RESULT: ", res) + for out_nm in outputs: + assert getattr(res.output, out_nm).exists() + + +@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) +def test_ApplyXFM_exception(test_data, inputs, error): + if inputs is None: + inputs = {} + for key, val in inputs.items(): + try: + inputs[key] = eval(val) + except: + pass + task = ApplyXFM(**inputs) + with pytest.raises(eval(error)): + task.generated_output_names diff --git a/pydra/tasks/fsl/tests/data/magnitude.nii b/pydra/tasks/fsl/tests/data/magnitude.nii new file mode 100644 index 0000000..e673671 Binary files /dev/null and b/pydra/tasks/fsl/tests/data/magnitude.nii differ diff --git a/pydra/tasks/fsl/tests/data/test_warpcoef.nii.gz b/pydra/tasks/fsl/tests/data/test_warpcoef.nii.gz new file mode 100644 index 0000000..899cc4a Binary files /dev/null and b/pydra/tasks/fsl/tests/data/test_warpcoef.nii.gz differ diff --git a/pydra/tasks/fsl/tests/data/transform.mat b/pydra/tasks/fsl/tests/data/transform.mat new file mode 100644 index 0000000..7b34788 --- /dev/null +++ b/pydra/tasks/fsl/tests/data/transform.mat @@ -0,0 +1,4 @@ +1 0.0001371992403 0 -0.01404274377 +0 1 0.0003819660051 -0.04808253666 +0 0 1 0 +0 0 0 1