From b53c2db916ff78eeb1f2ce0a0a80940513a11944 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 15 Apr 2022 22:47:14 +0200 Subject: [PATCH 1/6] fix: address reliability issues of the functional masking workflow --- niworkflows/func/util.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/niworkflows/func/util.py b/niworkflows/func/util.py index 81ae1cdb50a..2ce5c3ad799 100644 --- a/niworkflows/func/util.py +++ b/niworkflows/func/util.py @@ -363,6 +363,8 @@ def init_enhance_and_skullstrip_bold_wf( reportlet for the skull-stripping """ + from niworkflows.interfaces.nibabel import BinaryDilation + workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=["in_file", "pre_mask"]), name="inputnode" @@ -375,15 +377,7 @@ def init_enhance_and_skullstrip_bold_wf( ) # Dilate pre_mask - pre_dilate = pe.Node( - fsl.DilateImage( - operation="max", - kernel_shape="sphere", - kernel_size=3.0, - internal_datatype="char", - ), - name="pre_mask_dilate", - ) + pre_dilate = pe.Node(BinaryDilation(), name="pre_mask_dilate") # Ensure mask's header matches reference's check_hdr = pe.Node(MatchHeader(), name="check_hdr", run_without_submitting=True) From b1c433cb34e547518e6ebeb850fe94f1e137938d Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 15 Apr 2022 22:54:26 +0200 Subject: [PATCH 2/6] fix: remove ``--float`` from epi-to-template registration config --- niworkflows/data/epi_atlasbased_brainmask.json | 1 - 1 file changed, 1 deletion(-) diff --git a/niworkflows/data/epi_atlasbased_brainmask.json b/niworkflows/data/epi_atlasbased_brainmask.json index 31fed8bd2f5..81cafe87b43 100644 --- a/niworkflows/data/epi_atlasbased_brainmask.json +++ b/niworkflows/data/epi_atlasbased_brainmask.json @@ -1,7 +1,6 @@ { "winsorize_upper_quantile": 0.98, "winsorize_lower_quantile": 0.05, - "float": true, "metric": ["Mattes"], "metric_weight": [1], "radius_or_number_of_bins": [64], From d425bec88c4c8550fed50f39dca6625d2f7dbf64 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 15 Apr 2022 22:55:39 +0200 Subject: [PATCH 3/6] sty: fix empty line with indentation --- niworkflows/func/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/niworkflows/func/util.py b/niworkflows/func/util.py index 2ce5c3ad799..581fba8e4a0 100644 --- a/niworkflows/func/util.py +++ b/niworkflows/func/util.py @@ -364,7 +364,7 @@ def init_enhance_and_skullstrip_bold_wf( """ from niworkflows.interfaces.nibabel import BinaryDilation - + workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=["in_file", "pre_mask"]), name="inputnode" From d60d5c61921f7bc3ce4bbc281a45d5ffd1736467 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 15 Apr 2022 23:02:59 +0200 Subject: [PATCH 4/6] enh: remove binarization and dilation --- niworkflows/func/util.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/niworkflows/func/util.py b/niworkflows/func/util.py index 581fba8e4a0..ff8267dbfd8 100644 --- a/niworkflows/func/util.py +++ b/niworkflows/func/util.py @@ -376,12 +376,6 @@ def init_enhance_and_skullstrip_bold_wf( name="outputnode", ) - # Dilate pre_mask - pre_dilate = pe.Node(BinaryDilation(), name="pre_mask_dilate") - - # Ensure mask's header matches reference's - check_hdr = pe.Node(MatchHeader(), name="check_hdr", run_without_submitting=True) - # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1) n4_correct = pe.Node( N4BiasFieldCorrection( @@ -436,7 +430,6 @@ def init_enhance_and_skullstrip_bold_wf( if not pre_mask: from nipype.interfaces.ants.utils import AI - from ..interfaces.nibabel import Binarize bold_template = get_template( "MNI152NLin2009cAsym", resolution=2, desc="fMRIPrep", suffix="boldref" @@ -489,10 +482,12 @@ def init_enhance_and_skullstrip_bold_wf( ), name="map_brainmask", ) - binarize_mask = pe.Node(Binarize(thresh_low=brainmask_thresh), name="binarize_mask") + # Ensure mask's header matches reference's + check_hdr = pe.Node(MatchHeader(), name="check_hdr", run_without_submitting=True) # fmt: off workflow.connect([ + (inputnode, check_hdr, [("in_file", "reference")]), (inputnode, init_aff, [("in_file", "moving_image")]), (inputnode, map_brainmask, [("in_file", "reference_image")]), (inputnode, norm, [("in_file", "moving_image")]), @@ -501,22 +496,19 @@ def init_enhance_and_skullstrip_bold_wf( ("reverse_invert_flags", "invert_transform_flags"), ("reverse_transforms", "transforms"), ]), - (map_brainmask, binarize_mask, [("output_image", "in_file")]), - (binarize_mask, pre_dilate, [("out_mask", "in_file")]), + (map_brainmask, check_hdr, [("output_image", "in_file")]), + (check_hdr, n4_correct, [("out_file", "weight_image")]), ]) # fmt: on else: # fmt: off workflow.connect([ - (inputnode, pre_dilate, [("pre_mask", "in_file")]), + (inputnode, n4_correct, [("pre_mask", "weight_image")]), ]) # fmt: on # fmt: off workflow.connect([ - (inputnode, check_hdr, [("in_file", "reference")]), - (pre_dilate, check_hdr, [("out_file", "in_file")]), - (check_hdr, n4_correct, [("out_file", "weight_image")]), (inputnode, n4_correct, [("in_file", "input_image")]), (inputnode, fixhdr_unifize, [("in_file", "hdr_file")]), (inputnode, fixhdr_skullstrip2, [("in_file", "hdr_file")]), From 82852997bc063256c1aed2ff35adc10bc1d1751e Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 15 Apr 2022 23:23:14 +0200 Subject: [PATCH 5/6] fix: use niworkflows' binary dilations --- niworkflows/func/util.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/niworkflows/func/util.py b/niworkflows/func/util.py index ff8267dbfd8..b14eaf262da 100644 --- a/niworkflows/func/util.py +++ b/niworkflows/func/util.py @@ -363,7 +363,7 @@ def init_enhance_and_skullstrip_bold_wf( reportlet for the skull-stripping """ - from niworkflows.interfaces.nibabel import BinaryDilation + from niworkflows.interfaces.nibabel import ApplyMask, BinaryDilation workflow = Workflow(name=name) inputnode = pe.Node( @@ -391,16 +391,8 @@ def init_enhance_and_skullstrip_bold_wf( skullstrip_first_pass = pe.Node( fsl.BET(frac=0.2, mask=True), name="skullstrip_first_pass" ) - bet_dilate = pe.Node( - fsl.DilateImage( - operation="max", - kernel_shape="sphere", - kernel_size=6.0, - internal_datatype="char", - ), - name="skullstrip_first_dilate", - ) - bet_mask = pe.Node(fsl.ApplyMask(), name="skullstrip_first_mask") + bet_dilate = pe.Node(BinaryDilation(radius=6), name="skullstrip_first_dilate") + bet_mask = pe.Node(ApplyMask(), name="skullstrip_first_mask") # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( @@ -426,7 +418,7 @@ def init_enhance_and_skullstrip_bold_wf( combine_masks = pe.Node(fsl.BinaryMaths(operation="mul"), name="combine_masks") # Compute masked brain - apply_mask = pe.Node(fsl.ApplyMask(), name="apply_mask") + apply_mask = pe.Node(ApplyMask(), name="apply_mask") if not pre_mask: from nipype.interfaces.ants.utils import AI @@ -514,7 +506,7 @@ def init_enhance_and_skullstrip_bold_wf( (inputnode, fixhdr_skullstrip2, [("in_file", "hdr_file")]), (n4_correct, skullstrip_first_pass, [("output_image", "in_file")]), (skullstrip_first_pass, bet_dilate, [("mask_file", "in_file")]), - (bet_dilate, bet_mask, [("out_file", "mask_file")]), + (bet_dilate, bet_mask, [("out_file", "in_mask")]), (skullstrip_first_pass, bet_mask, [("out_file", "in_file")]), (bet_mask, unifize, [("out_file", "in_file")]), (unifize, fixhdr_unifize, [("out_file", "in_file")]), @@ -523,7 +515,7 @@ def init_enhance_and_skullstrip_bold_wf( (skullstrip_second_pass, fixhdr_skullstrip2, [("out_file", "in_file")]), (fixhdr_skullstrip2, combine_masks, [("out_file", "operand_file")]), (fixhdr_unifize, apply_mask, [("out_file", "in_file")]), - (combine_masks, apply_mask, [("out_file", "mask_file")]), + (combine_masks, apply_mask, [("out_file", "in_mask")]), (combine_masks, outputnode, [("out_file", "mask_file")]), (apply_mask, outputnode, [("out_file", "skull_stripped_file")]), (n4_correct, outputnode, [("output_image", "bias_corrected_file")]), @@ -565,6 +557,8 @@ def init_skullstrip_bold_wf(name="skullstrip_bold_wf"): reportlet for the skull-stripping """ + from niworkflows.interfaces.nibabel import ApplyMask + workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=["in_file"]), name="inputnode") outputnode = pe.Node( @@ -580,7 +574,7 @@ def init_skullstrip_bold_wf(name="skullstrip_bold_wf"): afni.Automask(dilate=1, outputtype="NIFTI_GZ"), name="skullstrip_second_pass" ) combine_masks = pe.Node(fsl.BinaryMaths(operation="mul"), name="combine_masks") - apply_mask = pe.Node(fsl.ApplyMask(), name="apply_mask") + apply_mask = pe.Node(ApplyMask(), name="apply_mask") mask_reportlet = pe.Node(SimpleShowMaskRPT(), name="mask_reportlet") # fmt: off @@ -592,7 +586,7 @@ def init_skullstrip_bold_wf(name="skullstrip_bold_wf"): (combine_masks, outputnode, [("out_file", "mask_file")]), # Masked file (inputnode, apply_mask, [("in_file", "in_file")]), - (combine_masks, apply_mask, [("out_file", "mask_file")]), + (combine_masks, apply_mask, [("out_file", "in_mask")]), (apply_mask, outputnode, [("out_file", "skull_stripped_file")]), # Reportlet (inputnode, mask_reportlet, [("in_file", "background_file")]), From 57f27b0ebb4411bfaea0feef9ffb36b8c56041d6 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Tue, 19 Apr 2022 14:38:51 +0200 Subject: [PATCH 6/6] fix: update node names since we are changing inner interfaces Co-authored-by: Mathias Goncalves --- niworkflows/func/util.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/niworkflows/func/util.py b/niworkflows/func/util.py index b14eaf262da..0459395565b 100644 --- a/niworkflows/func/util.py +++ b/niworkflows/func/util.py @@ -391,8 +391,8 @@ def init_enhance_and_skullstrip_bold_wf( skullstrip_first_pass = pe.Node( fsl.BET(frac=0.2, mask=True), name="skullstrip_first_pass" ) - bet_dilate = pe.Node(BinaryDilation(radius=6), name="skullstrip_first_dilate") - bet_mask = pe.Node(ApplyMask(), name="skullstrip_first_mask") + first_dilate = pe.Node(BinaryDilation(radius=6), name="first_dilate") + first_mask = pe.Node(ApplyMask(), name="first_mask") # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( @@ -505,10 +505,10 @@ def init_enhance_and_skullstrip_bold_wf( (inputnode, fixhdr_unifize, [("in_file", "hdr_file")]), (inputnode, fixhdr_skullstrip2, [("in_file", "hdr_file")]), (n4_correct, skullstrip_first_pass, [("output_image", "in_file")]), - (skullstrip_first_pass, bet_dilate, [("mask_file", "in_file")]), - (bet_dilate, bet_mask, [("out_file", "in_mask")]), - (skullstrip_first_pass, bet_mask, [("out_file", "in_file")]), - (bet_mask, unifize, [("out_file", "in_file")]), + (skullstrip_first_pass, first_dilate, [("mask_file", "in_file")]), + (first_dilate, first_mask, [("out_file", "in_mask")]), + (skullstrip_first_pass, first_mask, [("out_file", "in_file")]), + (first_mask, unifize, [("out_file", "in_file")]), (unifize, fixhdr_unifize, [("out_file", "in_file")]), (fixhdr_unifize, skullstrip_second_pass, [("out_file", "in_file")]), (skullstrip_first_pass, combine_masks, [("mask_file", "in_file")]),