Skip to content

Commit 464b7c2

Browse files
committed
ENH: Stop using siemens2rads from old nipype workflows
A new interface is proposed, to be used in phase-difference based workflows. @Aksoo identified a potential issue with siemens2rads (#30 (comment)), although the re-centering did not seem to make a big difference. This implementation of the rescaling uses percentiles to robustly calculate the range of the input image (as recommended in the original paper about FSL PRELUDE), and makes sure the output data type is adequate (float32).
1 parent ebdd7fb commit 464b7c2

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

sdcflows/interfaces/fmap.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,27 @@ def _run_interface(self, runtime):
200200
return runtime
201201

202202

203+
class _PhaseMap2radsInputSpec(BaseInterfaceInputSpec):
204+
in_file = File(exists=True, mandatory=True, desc='input (wrapped) phase map')
205+
206+
207+
class _PhaseMap2radsOutputSpec(TraitedSpec):
208+
out_file = File(desc='the phase map in the range 0 - 6.28')
209+
210+
211+
class PhaseMap2rads(SimpleInterface):
212+
"""Convert a phase map in a.u. to radians."""
213+
214+
input_spec = _PhaseMap2radsInputSpec
215+
output_spec = _PhaseMap2radsOutputSpec
216+
217+
def _run_interface(self, runtime):
218+
self._results['out_file'] = au2rads(
219+
self.inputs.in_file,
220+
newpath=runtime.cwd)
221+
return runtime
222+
223+
203224
def _despike2d(data, thres, neigh=None):
204225
"""Despike axial slices, as done in FSL's ``epiunwarp``."""
205226
if neigh is None:
@@ -531,3 +552,22 @@ def _delta_te(in_values, te1=None, te2=None):
531552
'EchoTime2 metadata field not found. Please consult the BIDS specification.')
532553

533554
return abs(float(te2) - float(te1))
555+
556+
557+
def au2rads(in_file, newpath=None):
558+
"""Convert the input phase difference map in arbitrary units (a.u.) to rads."""
559+
im = nb.load(in_file)
560+
data = im.get_fdata().astype('float32')
561+
hdr = im.header.copy()
562+
563+
data -= np.percentile(data, 2)
564+
data[data < 0] = 0
565+
data = 2.0 * np.pi * data / np.percentile(data, 98)
566+
data[data > 2.0 * np.pi] = 2.0 * np.pi
567+
hdr.set_data_dtype(np.float32)
568+
hdr.set_xyzt_units('mm')
569+
hdr['datatype'] = 16
570+
571+
out_file = fname_presuffix(in_file, suffix='_rads', newpath=newpath)
572+
nb.Nifti1Image(data, im.affine, hdr).to_filename(out_file)
573+
return out_file

sdcflows/workflows/phdiff.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
from nipype.interfaces import ants, fsl, utility as niu
2121
from nipype.pipeline import engine as pe
2222
from niflow.nipype1.workflows.dmri.fsl.utils import (
23-
siemens2rads, demean_image, cleanup_edge_pipeline)
23+
demean_image, cleanup_edge_pipeline)
2424
from niworkflows.engine.workflows import LiterateWorkflow as Workflow
2525
from niworkflows.interfaces.images import IntraModalMerge
2626
from niworkflows.interfaces.masks import BETRPT
2727

28-
from ..interfaces.fmap import Phasediff2Fieldmap
28+
from ..interfaces.fmap import Phasediff2Fieldmap, PhaseMap2rads
2929

3030

3131
def init_phdiff_wf(omp_nthreads, name='phdiff_wf'):
@@ -98,7 +98,7 @@ def init_phdiff_wf(omp_nthreads, name='phdiff_wf'):
9898
# nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate')
9999

100100
# phase diff -> radians
101-
pha2rads = pe.Node(niu.Function(function=siemens2rads), name='pha2rads')
101+
phmap2rads = pe.Node(PhaseMap2rads(), name='phmap2rads')
102102

103103
# FSL PRELUDE will perform phase-unwrapping
104104
prelude = pe.Node(fsl.PRELUDE(), name='prelude')
@@ -124,8 +124,8 @@ def init_phdiff_wf(omp_nthreads, name='phdiff_wf'):
124124
(n4, prelude, [('output_image', 'magnitude_file')]),
125125
(n4, bet, [('output_image', 'in_file')]),
126126
(bet, prelude, [('mask_file', 'mask_file')]),
127-
(inputnode, pha2rads, [('phasediff', 'in_file')]),
128-
(pha2rads, prelude, [('out', 'phase_file')]),
127+
(inputnode, phmap2rads, [('phasediff', 'in_file')]),
128+
(phmap2rads, prelude, [('out_file', 'phase_file')]),
129129
(prelude, denoise, [('unwrapped_phase_file', 'in_file')]),
130130
(denoise, demean, [('out_file', 'in_file')]),
131131
(demean, cleanup_wf, [('out', 'inputnode.in_file')]),

0 commit comments

Comments
 (0)