|
22 | 22 | # Local imports
|
23 | 23 | from ...utils.filemanip import (fname_presuffix, filename_to_list,
|
24 | 24 | list_to_filename, split_filename)
|
25 |
| -from ..base import (OutputMultiPath, TraitedSpec, isdefined, traits, |
26 |
| - InputMultiPath, File) |
27 |
| -from .base import (SPMCommand, scans_for_fname, func_is_3d, scans_for_fnames, |
28 |
| - SPMCommandInputSpec, ImageFileSPM) |
| 25 | +from ..base import (OutputMultiPath, TraitedSpec, isdefined, |
| 26 | + traits, InputMultiPath, File, Str) |
| 27 | +from .base import (SPMCommand, scans_for_fname, func_is_3d, |
| 28 | + scans_for_fnames, SPMCommandInputSpec, ImageFileSPM) |
29 | 29 |
|
30 | 30 | __docformat__ = 'restructuredtext'
|
31 | 31 |
|
32 | 32 |
|
| 33 | +class FieldMapInputSpec(SPMCommandInputSpec): |
| 34 | + jobtype = traits.Enum('calculatevdm', 'applyvdm', usedefault=True, |
| 35 | + desc='one of: calculatevdm, applyvdm') |
| 36 | + phase_file = File(mandatory=True, exists=True, copyfile=False, |
| 37 | + field='subj.data.presubphasemag.phase', |
| 38 | + desc='presubstracted phase file') |
| 39 | + magnitude_file = File(mandatory=True, exists=True, copyfile=False, |
| 40 | + field='subj.data.presubphasemag.magnitude', |
| 41 | + desc='presubstracted magnitude file') |
| 42 | + echo_times = traits.Tuple(traits.Float, traits.Float, mandatory=True, |
| 43 | + field='subj.defaults.defaultsval.et', |
| 44 | + desc='short and long echo times') |
| 45 | + maskbrain = traits.Bool(True, usedefault=True, |
| 46 | + field='subj.defaults.defaultsval.maskbrain', |
| 47 | + desc='masking or no masking of the brain') |
| 48 | + blip_direction = traits.Enum(1, -1, mandatory=True, |
| 49 | + field='subj.defaults.defaultsval.blipdir', |
| 50 | + desc='polarity of the phase-encode blips') |
| 51 | + total_readout_time = traits.Float(mandatory=True, |
| 52 | + field='subj.defaults.defaultsval.tert', |
| 53 | + desc='total EPI readout time') |
| 54 | + epifm = traits.Bool(False, usedefault=True, |
| 55 | + field='subj.defaults.defaultsval.epifm', |
| 56 | + desc='epi-based field map'); |
| 57 | + jacobian_modulation = traits.Bool(False, usedefault=True, |
| 58 | + field='subj.defaults.defaultsval.ajm', |
| 59 | + desc='jacobian modulation'); |
| 60 | + # Unwarping defaults parameters |
| 61 | + method = traits.Enum('Mark3D', 'Mark2D', 'Huttonish', usedefault=True, |
| 62 | + desc='One of: Mark3D, Mark2D, Huttonish', |
| 63 | + field='subj.defaults.defaultsval.uflags.method'); |
| 64 | + unwarp_fwhm = traits.Range(low=0, value=10, usedefault=True, |
| 65 | + field='subj.defaults.defaultsval.uflags.fwhm', |
| 66 | + desc='gaussian smoothing kernel width'); |
| 67 | + pad = traits.Range(low=0, value=0, usedefault=True, |
| 68 | + field='subj.defaults.defaultsval.uflags.pad', |
| 69 | + desc='padding kernel width'); |
| 70 | + ws = traits.Bool(True, usedefault=True, |
| 71 | + field='subj.defaults.defaultsval.uflags.ws', |
| 72 | + desc='weighted smoothing'); |
| 73 | + # Brain mask defaults parameters |
| 74 | + template = File(copyfile=False, exists=True, |
| 75 | + field='subj.defaults.defaultsval.mflags.template', |
| 76 | + desc='template image for brain masking'); |
| 77 | + mask_fwhm = traits.Range(low=0, value=5, usedefault=True, |
| 78 | + field='subj.defaults.defaultsval.mflags.fwhm', |
| 79 | + desc='gaussian smoothing kernel width'); |
| 80 | + nerode = traits.Range(low=0, value=2, usedefault=True, |
| 81 | + field='subj.defaults.defaultsval.mflags.nerode', |
| 82 | + desc='number of erosions'); |
| 83 | + ndilate = traits.Range(low=0, value=4, usedefault=True, |
| 84 | + field='subj.defaults.defaultsval.mflags.ndilate', |
| 85 | + desc='number of erosions'); |
| 86 | + thresh = traits.Float(0.5, usedefault=True, |
| 87 | + field='subj.defaults.defaultsval.mflags.thresh', |
| 88 | + desc='threshold used to create brain mask from segmented data'); |
| 89 | + reg = traits.Float(0.02, usedefault=True, |
| 90 | + field='subj.defaults.defaultsval.mflags.reg', |
| 91 | + desc='regularization value used in the segmentation'); |
| 92 | + # EPI unwarping for quality check |
| 93 | + epi_file = File(copyfile=False, exists=True, mandatory=True, |
| 94 | + field='subj.session.epi', |
| 95 | + desc='EPI to unwarp'); |
| 96 | + matchvdm = traits.Bool(True, usedefault=True, |
| 97 | + field='subj.matchvdm', |
| 98 | + desc='match VDM to EPI'); |
| 99 | + sessname = Str('_run-', usedefault=True, |
| 100 | + field='subj.sessname', |
| 101 | + desc='VDM filename extension'); |
| 102 | + writeunwarped = traits.Bool(False, usedefault=True, |
| 103 | + field='subj.writeunwarped', |
| 104 | + desc='write unwarped EPI'); |
| 105 | + anat_file = File(copyfile=False, exists=True, |
| 106 | + field='subj.anat', |
| 107 | + desc='anatomical image for comparison'); |
| 108 | + matchanat = traits.Bool(True, usedefault=True, |
| 109 | + field='subj.matchanat', |
| 110 | + desc='match anatomical image to EPI'); |
| 111 | + |
| 112 | + |
| 113 | +class FieldMapOutputSpec(TraitedSpec): |
| 114 | + vdm = File(exists=True, desc='voxel difference map') |
| 115 | + |
| 116 | + |
| 117 | +class FieldMap(SPMCommand): |
| 118 | + """Use the fieldmap toolbox from spm to calculate the voxel displacement map (VDM). |
| 119 | +
|
| 120 | + http://www.fil.ion.ucl.ac.uk/spm/doc/manual.pdf#page=173 |
| 121 | +
|
| 122 | + To do |
| 123 | + ----- |
| 124 | + Deal with real/imag magnitude images and with the two phase files case. |
| 125 | +
|
| 126 | + Examples |
| 127 | + -------- |
| 128 | + >>> from nipype.interfaces.spm import FieldMap |
| 129 | + >>> fm = FieldMap() |
| 130 | + >>> fm.inputs.phase_file = 'phase.nii' |
| 131 | + >>> fm.inputs.magnitude_file = 'magnitude.nii' |
| 132 | + >>> fm.inputs.echo_times = (5.19, 7.65) |
| 133 | + >>> fm.inputs.blip_direction = 1 |
| 134 | + >>> fm.inputs.total_readout_time = 15.6 |
| 135 | + >>> fm.inputs.epi_file = 'epi.nii' |
| 136 | + >>> fm.run() # doctest: +SKIP |
| 137 | +
|
| 138 | + """ |
| 139 | + |
| 140 | + input_spec = FieldMapInputSpec |
| 141 | + output_spec = FieldMapOutputSpec |
| 142 | + _jobtype = 'tools' |
| 143 | + _jobname = 'fieldmap' |
| 144 | + |
| 145 | + def _format_arg(self, opt, spec, val): |
| 146 | + """Convert input to appropriate format for spm |
| 147 | + """ |
| 148 | + if opt in ['phase_file', 'magnitude_file', 'anat_file', 'epi_file']: |
| 149 | + return scans_for_fname(filename_to_list(val)) |
| 150 | + |
| 151 | + return super(FieldMap, self)._format_arg(opt, spec, val) |
| 152 | + |
| 153 | + def _parse_inputs(self): |
| 154 | + """validate spm fieldmap options if set to None ignore |
| 155 | + """ |
| 156 | + einputs = super(FieldMap, self)._parse_inputs() |
| 157 | + return [{self.inputs.jobtype: einputs[0]}] |
| 158 | + |
| 159 | + def _list_outputs(self): |
| 160 | + outputs = self._outputs().get() |
| 161 | + jobtype = self.inputs.jobtype |
| 162 | + if jobtype == "calculatevdm": |
| 163 | + outputs['vdm'] = fname_presuffix(self.inputs.phase_file, prefix='vdm5_sc') |
| 164 | + |
| 165 | + return outputs |
| 166 | + |
| 167 | + |
33 | 168 | class SliceTimingInputSpec(SPMCommandInputSpec):
|
34 | 169 | in_files = InputMultiPath(
|
35 | 170 | traits.Either(
|
|
0 commit comments