def _unwrap(fmap_data, mag_file, mask=None): from math import pi from nipype.interfaces.fsl import PRELUDE magnii = nb.load(mag_file) if mask is None: mask = np.ones_like(fmap_data, dtype=np.uint8) fmapmax = max(abs(fmap_data[mask > 0].min()), fmap_data[mask > 0].max()) fmap_data *= pi / fmapmax nb.Nifti1Image(fmap_data, magnii.affine).to_filename('fmap_rad.nii.gz') nb.Nifti1Image(mask, magnii.affine).to_filename('fmap_mask.nii.gz') nb.Nifti1Image(magnii.get_data(), magnii.affine).to_filename('fmap_mag.nii.gz') # Run prelude res = PRELUDE(phase_file='fmap_rad.nii.gz', magnitude_file='fmap_mag.nii.gz', mask_file='fmap_mask.nii.gz').run() unwrapped = nb.load(res.outputs.unwrapped_phase_file).get_data() * (fmapmax / pi) return unwrapped
def init_phdiff_wf(omp_nthreads, debug=False, name="phdiff_wf"): r""" Generate a :math:`B_0` field from consecutive-phases and phase-difference maps. This workflow preprocess phase-difference maps (or generates the phase-difference map should two ``phase1``/``phase2`` be provided at the input), and generates an image equivalent to BIDS's ``fieldmap`` that can be processed with the general fieldmap workflow. Besides phase2 - phase1 subtraction, the core of this particular workflow relies in the phase-unwrapping with FSL PRELUDE [Jenkinson2003]_. FSL PRELUDE takes wrapped maps in the range 0 to 6.28, `as per the user guide <https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE/Guide#Step_2_-_Getting_.28wrapped.29_phase_in_radians>`__. For the phase-difference maps, recentering back to :math:`[-\pi \dotsb \pi )` is necessary. After some massaging and with the scaling of the echo separation factor :math:`\Delta \text{TE}`, the phase-difference maps are converted into an actual :math:`B_0` map in Hz units. Workflow Graph .. workflow :: :graph2use: orig :simple_form: yes from sdcflows.workflows.fit.fieldmap import init_phdiff_wf wf = init_phdiff_wf(omp_nthreads=1) Parameters ---------- omp_nthreads : :obj:`int` Maximum number of threads an individual process may use debug : :obj:`bool` Run on debug mode name : :obj:`str` Name of workflow (default: ``phdiff_wf``) Inputs ------ magnitude : :obj:`os.PathLike` A reference magnitude image preprocessed elsewhere. phase : :obj:`list` of :obj:`tuple` of (:obj:`os.PathLike`, :obj:`dict`) List containing one GRE phase-difference map with its corresponding metadata (requires ``EchoTime1`` and ``EchoTime2``), or the phase maps for the two subsequent echoes, with their metadata (requires ``EchoTime``). mask : :obj:`os.PathLike` A brain mask calculated from the magnitude image. Outputs ------- fieldmap : :obj:`os.PathLike` The estimated fieldmap in Hz. """ from nipype.interfaces.fsl import PRELUDE from ...interfaces.fmap import Phasediff2Fieldmap, PhaseMap2rads, SubtractPhases workflow = Workflow(name=name) workflow.__postdesc__ = f"""\ The corresponding phase-map(s) were phase-unwrapped with `prelude` (FSL {PRELUDE.version}). """ inputnode = pe.Node( niu.IdentityInterface(fields=["magnitude", "phase", "mask"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface(fields=["fieldmap"]), name="outputnode", ) def _split(phase): return phase split = pe.MapNode( # We cannot use an inline connection function with MapNode niu.Function(function=_split, output_names=["map_file", "meta"]), iterfield=["phase"], run_without_submitting=True, name="split", ) # phase diff -> radians phmap2rads = pe.MapNode( PhaseMap2rads(), name="phmap2rads", iterfield=["in_file"], run_without_submitting=True, ) # FSL PRELUDE will perform phase-unwrapping prelude = pe.Node(PRELUDE(), name="prelude") calc_phdiff = pe.Node(SubtractPhases(), name="calc_phdiff", run_without_submitting=True) calc_phdiff.interface._always_run = debug compfmap = pe.Node(Phasediff2Fieldmap(), name="compfmap") # fmt: off workflow.connect([ (inputnode, split, [("phase", "phase")]), (inputnode, prelude, [("magnitude", "magnitude_file"), ("mask", "mask_file")]), (split, phmap2rads, [("map_file", "in_file")]), (phmap2rads, calc_phdiff, [("out_file", "in_phases")]), (split, calc_phdiff, [("meta", "in_meta")]), (calc_phdiff, prelude, [("phase_diff", "phase_file")]), (prelude, compfmap, [("unwrapped_phase_file", "in_file")]), (calc_phdiff, compfmap, [("metadata", "metadata")]), (compfmap, outputnode, [("out_file", "fieldmap")]), ]) # fmt: on return workflow