|
14 | 14 |
|
15 | 15 | import os
|
16 | 16 | import os.path as op
|
| 17 | +from distutils import spawn |
17 | 18 |
|
18 | 19 | from ...utils.filemanip import (load_json, save_json, split_filename)
|
19 | 20 | from ..base import (
|
@@ -46,6 +47,167 @@ class CentralityInputSpec(AFNICommandInputSpec):
|
46 | 47 | desc='Mask the dataset to target brain-only voxels',
|
47 | 48 | argstr='-automask')
|
48 | 49 |
|
| 50 | +class AlignEpiAnatPyInputSpec(CommandLineInputSpec): |
| 51 | + outputtype = traits.Enum('AFNI', list(Info.ftypes.keys()), |
| 52 | + desc='AFNI output filetype') |
| 53 | + py27_path = File( |
| 54 | + desc='Path to Python 2.7 executable for running afni python scripts', |
| 55 | + argstr='%s '+spawn.find_executable('align_epi_anat.py'), |
| 56 | + exists=True, |
| 57 | + #default='/opt/miniconda/envs/py27/bin/python', |
| 58 | + mandatory=True, |
| 59 | + position=0 |
| 60 | + ) |
| 61 | + in_file = File( |
| 62 | + desc='EPI dataset to align', |
| 63 | + argstr='-epi %s', |
| 64 | + mandatory=True, |
| 65 | + exists=True, |
| 66 | + copyfile=False) |
| 67 | + anat = File( |
| 68 | + desc='name of structural dataset', |
| 69 | + argstr='-anat %s', |
| 70 | + mandatory=True, |
| 71 | + exists=True, |
| 72 | + copyfile=False) |
| 73 | + epi_base = traits.Str( |
| 74 | + desc='the epi base used in alignment' |
| 75 | + 'should be one of (0/mean/median/max/subbrick#)', |
| 76 | + mandatory=True, |
| 77 | + argstr='-epi_base %s') |
| 78 | + anat2epi = traits.Bool( |
| 79 | + default = True, |
| 80 | + desc='align anatomical to EPI dataset (default)', |
| 81 | + argstr='-anat2epi') |
| 82 | + epi2anat = traits.Bool( |
| 83 | + desc='align EPI to anatomical dataset', |
| 84 | + argstr='-epi2anat') |
| 85 | + save_skullstrip = traits.Bool( |
| 86 | + desc='save skull-stripped (not aligned)', |
| 87 | + argstr='-save_skullstrip') |
| 88 | + suffix = traits.Str( |
| 89 | + desc='append suffix to the original anat/epi dataset to use' |
| 90 | + 'in the resulting dataset names (default is "_al")', |
| 91 | + argstr='-suffix %s') |
| 92 | + epi_strip = traits.Enum(('3dSkullStrip','3dAutomask','None'), |
| 93 | + desc='method to mask brain in EPI data' |
| 94 | + 'should be one of[3dSkullStrip]/3dAutomask/None)', |
| 95 | + argstr='-epi_strip %s') |
| 96 | + volreg = traits.Enum(('on','off'), |
| 97 | + desc='do volume registration on EPI dataset before alignment' |
| 98 | + 'should be \'on\' or \'off\', defaults to \'on\'', |
| 99 | + default='on', |
| 100 | + argstr='-volreg %s') |
| 101 | + tshift = traits.Enum(('on','off'), |
| 102 | + desc='do time shifting of EPI dataset before alignment' |
| 103 | + 'should be \'on\' or \'off\', defaults to \'on\'', |
| 104 | + default='on', |
| 105 | + argstr='-tshift %s') |
| 106 | + |
| 107 | +class AlignEpiAnatPyOutputSpec(TraitedSpec): |
| 108 | + anat_al_orig = File( |
| 109 | + desc="A version of the anatomy that is aligned to the EPI") |
| 110 | + epi_al_orig = File( |
| 111 | + desc="A version of the EPI dataset aligned to the anatomy") |
| 112 | + epi_tlrc_al = File( |
| 113 | + desc="A version of the EPI dataset aligned to a standard template") |
| 114 | + anat_al_mat = File( |
| 115 | + desc="matrix to align anatomy to the EPI") |
| 116 | + epi_al_mat = File( |
| 117 | + desc="matrix to align EPI to anatomy") |
| 118 | + epi_vr_al_mat = File( |
| 119 | + desc="matrix to volume register EPI") |
| 120 | + epi_reg_al_mat = File( |
| 121 | + desc="matrix to volume register and align epi to anatomy") |
| 122 | + epi_al_tlrc_mat = File( |
| 123 | + desc="matrix to volume register and align epi" |
| 124 | + "to anatomy and put into standard space") |
| 125 | + epi_vr_motion = File( |
| 126 | + desc="motion parameters from EPI time-series" |
| 127 | + "registration (tsh included in name if slice" |
| 128 | + "timing correction is also included).") |
| 129 | + skullstrip = File( |
| 130 | + desc="skull-stripped (not aligned) volume") |
| 131 | + |
| 132 | +class AlignEpiAnatPy(AFNICommand): |
| 133 | + """align EPI to anatomical datasets or vice versa |
| 134 | + This Python script computes the alignment between two datasets, typically |
| 135 | + an EPI and an anatomical structural dataset, and applies the resulting |
| 136 | + transformation to one or the other to bring them into alignment. |
| 137 | +
|
| 138 | + This script computes the transforms needed to align EPI and |
| 139 | + anatomical datasets using a cost function designed for this purpose. The |
| 140 | + script combines multiple transformations, thereby minimizing the amount of |
| 141 | + interpolation applied to the data. |
| 142 | + |
| 143 | + Basic Usage: |
| 144 | + align_epi_anat.py -anat anat+orig -epi epi+orig -epi_base 5 |
| 145 | + |
| 146 | + The user must provide EPI and anatomical datasets and specify the EPI |
| 147 | + sub-brick to use as a base in the alignment. |
| 148 | +
|
| 149 | + Internally, the script always aligns the anatomical to the EPI dataset, |
| 150 | + and the resulting transformation is saved to a 1D file. |
| 151 | + As a user option, the inverse of this transformation may be applied to the |
| 152 | + EPI dataset in order to align it to the anatomical data instead. |
| 153 | +
|
| 154 | + This program generates several kinds of output in the form of datasets |
| 155 | + and transformation matrices which can be applied to other datasets if |
| 156 | + needed. Time-series volume registration, oblique data transformations and |
| 157 | + Talairach (standard template) transformations will be combined as needed |
| 158 | + and requested (with options to turn on and off each of the steps) in |
| 159 | + order to create the aligned datasets. |
| 160 | +
|
| 161 | + For complete details, see the `align_epi_anat.py' Documentation. |
| 162 | + <https://afni.nimh.nih.gov/pub/dist/doc/program_help/align_epi_anat.py.html>`_ |
| 163 | +
|
| 164 | + Examples |
| 165 | + ======== |
| 166 | + >>> from nipype.interfaces import afni |
| 167 | + >>> al_ea = afni.AlignEpiAnatPy() |
| 168 | + >>> al_ea.inputs.py27_path = "/opt/miniconda/envs/py27/bin/python" |
| 169 | + >>> al_ea.inputs.anat = "structural.nii" |
| 170 | + >>> al_ea.inputs.in_file = "functional.nii" |
| 171 | + >>> al_ea.inputs.epi_base = '0' |
| 172 | + >>> al_ea.inputs.epi_strip = '3dAutomask' |
| 173 | + >>> al_ea.inputs.volreg = 'off' |
| 174 | + >>> al_ea.inputs.tshift = 'off' |
| 175 | + >>> al_ea.inputs.save_skullstrip = True |
| 176 | + >>> al_ea.cmdline # doctest: +ALLOW_UNICODE |
| 177 | + 'echo "" && /opt/miniconda/envs/py27/bin/python /root/abin/align_epi_anat.py -anat structural.nii -epi_base 0 -epi_strip 3dAutomask -epi functional.nii -save_skullstrip -tshift off -volreg off' |
| 178 | + >>> res = allineate.run() # doctest: +SKIP |
| 179 | + """ |
| 180 | + _cmd = 'echo "" && ' |
| 181 | + input_spec = AlignEpiAnatPyInputSpec |
| 182 | + output_spec = AlignEpiAnatPyOutputSpec |
| 183 | + |
| 184 | + def _list_outputs(self): |
| 185 | + outputs = self.output_spec().get() |
| 186 | + anat_prefix = ''.join(self._gen_fname(self.inputs.anat).split('+')[:-1]) |
| 187 | + epi_prefix = ''.join(self._gen_fname(self.inputs.in_file).split('+')[:-1]) |
| 188 | + ext = '.HEAD' |
| 189 | + matext='.1D' |
| 190 | + if not isdefined(self.inputs.suffix): |
| 191 | + suffix = '_al' |
| 192 | + else: |
| 193 | + suffix = '_'+self.inputs.suffix |
| 194 | + if self.inputs.anat2epi: |
| 195 | + outputs['anat_al_orig'] = os.path.abspath(self._gen_fname(anat_prefix, suffix=suffix+'+orig')+ext) |
| 196 | + outputs['anat_al_mat'] = os.path.abspath(self._gen_fname(anat_prefix, suffix=suffix+'_mat.aff12')+matext) |
| 197 | + if self.inputs.epi2anat: |
| 198 | + outputs['epi_al_orig'] = os.path.abspath(self._gen_fname(epi_prefix, suffix=suffix+'+orig')+ext) |
| 199 | + outputs['epi_al_mat'] = os.path.abspath(self._gen_fname(epi_prefix, suffix=suffix+'_mat.aff12')+matext) |
| 200 | + if self.inputs.volreg == 'on': |
| 201 | + outputs['epi_vr_al_mat'] = os.path.abspath(self._gen_fname(epi_prefix, suffix='_vr'+suffix+'_mat.aff12')+matext) |
| 202 | + if self.inputs.tshift == 'on': |
| 203 | + outputs['epi_vr_motion'] = os.path.abspath(self._gen_fname(epi_prefix, suffix='tsh_vr_motion')+matext) |
| 204 | + elif self.inputs.tshift == 'off': |
| 205 | + outputs['epi_vr_motion'] = os.path.abspath(self._gen_fname(epi_prefix, suffix='vr_motion')+matext) |
| 206 | + if self.inputs.volreg == 'on' and self.inputs.epi2anat: |
| 207 | + outputs['epi_reg_al_mat']= os.path.abspath(self._gen_fname(epi_prefix, suffix='_reg'+suffix+'_mat.aff12')+matext) |
| 208 | + if self.inputs.save_skullstrip: |
| 209 | + outputs.skullstrip = os.path.abspath(self._gen_fname(anat_prefix, suffix='_ns'+'+orig')+ext) |
| 210 | + return outputs |
49 | 211 |
|
50 | 212 | class AllineateInputSpec(AFNICommandInputSpec):
|
51 | 213 | in_file = File(
|
|
0 commit comments