-
Notifications
You must be signed in to change notification settings - Fork 28
ENH: Stop using siemens2rads from old nipype workflows #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
04637a5
e21ed8b
aea890b
616c16f
97ed3db
588d3fd
7ec8e91
82a108a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -187,7 +187,16 @@ class _Phasediff2FieldmapOutputSpec(TraitedSpec): | |
|
||
|
||
class Phasediff2Fieldmap(SimpleInterface): | ||
"""Convert a phase difference map into a fieldmap in Hz.""" | ||
""" | ||
Convert a phase difference map into a fieldmap in Hz. | ||
|
||
This interface is equivalent to running the following steps: | ||
#. Convert from rad to rad/s | ||
(``niflow.nipype1.workflows.dmri.fsl.utils.rads2radsec``) | ||
#. FUGUE execution: fsl.FUGUE(save_fmap=True) | ||
#. Conversion from rad/s to Hz (divide by 2pi, ``rsec2hz``). | ||
|
||
""" | ||
|
||
input_spec = _Phasediff2FieldmapInputSpec | ||
output_spec = _Phasediff2FieldmapOutputSpec | ||
|
@@ -200,6 +209,27 @@ def _run_interface(self, runtime): | |
return runtime | ||
|
||
|
||
class _PhaseMap2radsInputSpec(BaseInterfaceInputSpec): | ||
in_file = File(exists=True, mandatory=True, desc='input (wrapped) phase map') | ||
|
||
|
||
class _PhaseMap2radsOutputSpec(TraitedSpec): | ||
out_file = File(desc='the phase map in the range 0 - 6.28') | ||
|
||
|
||
class PhaseMap2rads(SimpleInterface): | ||
"""Convert a phase map in a.u. to radians.""" | ||
|
||
input_spec = _PhaseMap2radsInputSpec | ||
output_spec = _PhaseMap2radsOutputSpec | ||
|
||
def _run_interface(self, runtime): | ||
self._results['out_file'] = au2rads( | ||
self.inputs.in_file, | ||
newpath=runtime.cwd) | ||
return runtime | ||
|
||
|
||
def _despike2d(data, thres, neigh=None): | ||
"""Despike axial slices, as done in FSL's ``epiunwarp``.""" | ||
if neigh is None: | ||
|
@@ -531,3 +561,32 @@ def _delta_te(in_values, te1=None, te2=None): | |
'EchoTime2 metadata field not found. Please consult the BIDS specification.') | ||
|
||
return abs(float(te2) - float(te1)) | ||
|
||
|
||
def au2rads(in_file, newpath=None): | ||
"""Convert the input phase difference map in arbitrary units (a.u.) to rads.""" | ||
from scipy.stats import mode | ||
im = nb.load(in_file) | ||
data = im.get_fdata(dtype='float32') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now I'm thinking about this again, I wonder if it makes more sense to make it float64 for the calculation, given that it's only one volume. This would ensure that the rounding error of casting to float32 on write (the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feels like splitting hairs... especially for images that originally were int16, DYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, probably. But it's cheap and reduces accumulated error. That accumulated error is almost certainly in the noise, but the extra guard bits also give you lots of room to have suboptimal order of operations without changing the output relative to an optimal (smallest induced error) algorithm, which feels useful for reproducibility/comparability with other tools. |
||
hdr = im.header.copy() | ||
|
||
# First center data around 0.0. | ||
data -= mode(data, axis=None)[0][0] | ||
|
||
# Scale lower tail | ||
data[data < 0] = - np.pi * data[data < 0] / data[data < 0].min() | ||
|
||
# Scale upper tail | ||
data[data > 0] = np.pi * data[data > 0] / data[data > 0].max() | ||
|
||
# Offset to 0 - 2pi | ||
data += np.pi | ||
|
||
# Clip | ||
data = np.clip(data, 0.0, 2 * np.pi) | ||
|
||
hdr.set_data_dtype(np.float32) | ||
hdr.set_xyzt_units('mm') | ||
out_file = fname_presuffix(in_file, suffix='_rads', newpath=newpath) | ||
nb.Nifti1Image(data, im.affine, hdr).to_filename(out_file) | ||
return out_file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.