-
Notifications
You must be signed in to change notification settings - Fork 307
[ENH] Add phase1/phase2 SDC support #1359
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 29 commits
b2a937a
f2b45d4
9dec5d8
840d167
bb510de
4d78483
6e0edda
9a0fcde
e5a6dee
d89c776
f6d4aa7
649dafe
8558aa5
1d12256
70b3413
191e155
880d04d
dc5b547
9f9284e
ce36514
0712c5e
4fd6add
09316a9
f9ca876
150b54f
ada0d9d
2c52d49
27c51ae
f57c063
2f6a294
a8fc3bd
0f7cdec
f2e861d
ff2d7d9
d94346f
5ce44ce
db42f74
6c7ec33
ef86939
1be1be1
c27d839
4d371a1
9c5b46b
85fcb4e
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 |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
|
||
Fieldmap preprocessing workflow for fieldmap data structure | ||
8.9.1 in BIDS 1.0.0: one phase diff and at least one magnitude image | ||
8.9.2 in BIDS 1.0.0: two phase images and two magnitude images | ||
|
||
""" | ||
|
||
|
@@ -27,11 +28,11 @@ | |
from ...engine import Workflow | ||
from ...interfaces import ( | ||
ReadSidecarJSON, IntraModalMerge, DerivativesDataSink, | ||
Phasediff2Fieldmap | ||
Phasediff2Fieldmap, Phases2Fieldmap | ||
) | ||
|
||
|
||
def init_phdiff_wf(omp_nthreads, name='phdiff_wf'): | ||
def init_phdiff_wf(omp_nthreads, phasetype="phasediff", name='phdiff_wf'): | ||
""" | ||
Estimates the fieldmap using a phase-difference image and one or more | ||
magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)` | ||
|
@@ -70,12 +71,6 @@ def init_phdiff_wf(omp_nthreads, name='phdiff_wf'): | |
outputnode = pe.Node(niu.IdentityInterface( | ||
fields=['fmap', 'fmap_ref', 'fmap_mask']), name='outputnode') | ||
|
||
def _pick1st(inlist): | ||
return inlist[0] | ||
|
||
# Read phasediff echo times | ||
meta = pe.Node(ReadSidecarJSON(), name='meta', mem_gb=0.01, run_without_submitting=True) | ||
|
||
# Merge input magnitude images | ||
magmrg = pe.Node(IntraModalMerge(), name='magmrg') | ||
|
||
|
@@ -90,9 +85,6 @@ def _pick1st(inlist): | |
# dilate = pe.Node(fsl.maths.MathsCommand( | ||
# nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate') | ||
|
||
# phase diff -> radians | ||
pha2rads = pe.Node(niu.Function(function=siemens2rads), name='pha2rads') | ||
|
||
# FSL PRELUDE will perform phase-unwrapping | ||
prelude = pe.Node(fsl.PRELUDE(), name='prelude') | ||
|
||
|
@@ -110,16 +102,44 @@ def _pick1st(inlist): | |
# pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='ComputeFieldmapFUGUE') | ||
# rsec2hz (divide by 2pi) | ||
|
||
if phasetype == "phasediff": | ||
# phase diff -> radians | ||
pha2rads = pe.Node(niu.Function(function=siemens2rads), | ||
name='pha2rads') | ||
# Read phasediff echo times | ||
meta = pe.Node(ReadSidecarJSON(), name='meta', mem_gb=0.01, | ||
run_without_submitting=True) | ||
workflow.connect([ | ||
(meta, compfmap, [('out_dict', 'metadata')]), | ||
(inputnode, pha2rads, [('phasediff', 'in_file')]), | ||
(pha2rads, prelude, [('out', 'phase_file')]), | ||
(inputnode, ds_fmap_mask, [('phasediff', 'source_file')]), | ||
]) | ||
|
||
elif phasetype == "phase": | ||
workflow.__desc__ += """\ | ||
The phase difference used for unwarping was calculated using a method developed | ||
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. If I'm understanding this PR correctly, this implements a method described by Jezzard & Balaban in 1995 (https://www.ncbi.nlm.nih.gov/pubmed/7674900). Modern scanners generally provide the phase difference map, and for that reason, this was missing in fMRIPrep. Code contributions are credited via the |
||
by Mark Elliott [@pncprocessing]. | ||
""" | ||
# Special case for phase1, phase2 images | ||
meta = pe.MapNode(ReadSidecarJSON(), name='meta', mem_gb=0.01, | ||
run_without_submitting=True, iterfield=['in_file']) | ||
phases2fmap = pe.Node(Phases2Fieldmap(), name='phases2fmap') | ||
workflow.connect([ | ||
(meta, phases2fmap, [('out_dict', 'metadatas')]), | ||
(inputnode, phases2fmap, [('phasediff', 'phase_files')]), | ||
(phases2fmap, prelude, [('out_file', 'phase_file')]), | ||
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. the difference map needs to be phase unwrapped? aren't the phase maps unwrapped individually? 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. Consider: p1 = pi - eps p1 - p2 = 2pi - 2eps = -2eps Phase differences should be between -pi and pi, as well. 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. That means you are clipping it again, correct? 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. Oh sorry, I think I misunderstood the context here. You're saying that 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. Yes, I understood before that each phase map needs to be unwrapped (which makes sense to me). If they are phase-unwrapped, there's no point on running PRELUDE (Phase Region Expanding Labeller for Unwrapping Discrete Estimates). Also, I am very curious as to how the individual phase maps are unwrapped, if not done with PRELUDE. I know there are better methods out there (e.g., using graph cuts) but they are rarely used in general. 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. Okay, I have confirmed this point: as per the FUGUE guide, each phase map should be unwrapped with PRELUDE separately (step 3) of the guide. Then they can be subtracted as they are not wrapped within [-pi, pi) anymore. After that point, the pipeline should be exactly the same as for the |
||
(phases2fmap, compfmap, [('phasediff_metadata', 'metadata')]), | ||
(phases2fmap, ds_fmap_mask, [('out_file', 'source_file')]) | ||
]) | ||
|
||
workflow.connect([ | ||
(inputnode, meta, [('phasediff', 'in_file')]), | ||
(inputnode, magmrg, [('magnitude', 'in_files')]), | ||
(magmrg, n4, [('out_avg', 'input_image')]), | ||
(n4, prelude, [('output_image', 'magnitude_file')]), | ||
(n4, bet, [('output_image', 'in_file')]), | ||
(bet, prelude, [('mask_file', 'mask_file')]), | ||
(inputnode, pha2rads, [('phasediff', 'in_file')]), | ||
(pha2rads, prelude, [('out', 'phase_file')]), | ||
(meta, compfmap, [('out_dict', 'metadata')]), | ||
(prelude, denoise, [('unwrapped_phase_file', 'in_file')]), | ||
(denoise, demean, [('out_file', 'in_file')]), | ||
(demean, cleanup_wf, [('out', 'inputnode.in_file')]), | ||
|
@@ -128,7 +148,6 @@ def _pick1st(inlist): | |
(compfmap, outputnode, [('out_file', 'fmap')]), | ||
(bet, outputnode, [('mask_file', 'fmap_mask'), | ||
('out_file', 'fmap_ref')]), | ||
(inputnode, ds_fmap_mask, [('phasediff', 'source_file')]), | ||
(bet, ds_fmap_mask, [('out_report', 'in_file')]), | ||
]) | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.