Skip to content

Commit 5b5fdc2

Browse files
committed
MAINT: Finalize upstreaming of ants interfaces to nipype
After nipy/nipype#3210 the ``niworkflows/interfaces/ants.py`` can go in whole.
1 parent b39e05d commit 5b5fdc2

File tree

3 files changed

+50
-614
lines changed

3 files changed

+50
-614
lines changed

niworkflows/anat/ants.py

Lines changed: 42 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,23 @@
1212
# nipype
1313
from nipype.pipeline import engine as pe
1414
from nipype.interfaces import utility as niu
15-
from nipype.interfaces.fsl.maths import ApplyMask
16-
from nipype.interfaces.ants import N4BiasFieldCorrection, Atropos, MultiplyImages
17-
18-
from ..utils.misc import get_template_specs
19-
# niworkflows
20-
from ..interfaces.ants import (
21-
ImageMath,
22-
ResampleImageBySpacing,
15+
from nipype.interfaces.ants import (
2316
AI,
17+
Atropos,
18+
MultiplyImages,
19+
N4BiasFieldCorrection,
20+
ResampleImageBySpacing,
2421
ThresholdImage,
2522
)
23+
24+
from ..utils.misc import get_template_specs
25+
# niworkflows
26+
from ..interfaces.nibabel import ApplyMask
27+
from ..interfaces.ants import ImageMath
2628
from ..interfaces.fixes import (
2729
FixHeaderRegistration as Registration,
2830
FixHeaderApplyTransforms as ApplyTransforms,
2931
)
30-
from ..interfaces.utils import CopyXForm
3132
from ..interfaces.nibabel import Binarize
3233

3334

@@ -53,19 +54,21 @@
5354
}
5455

5556

56-
def init_brain_extraction_wf(name='brain_extraction_wf',
57-
in_template='OASIS30ANTs',
58-
template_spec=None,
59-
use_float=True,
60-
normalization_quality='precise',
61-
omp_nthreads=None,
62-
mem_gb=3.0,
63-
bids_suffix='T1w',
64-
atropos_refine=True,
65-
atropos_use_random_seed=True,
66-
atropos_model=None,
67-
use_laplacian=True,
68-
bspline_fitting_distance=200):
57+
def init_brain_extraction_wf(
58+
name='brain_extraction_wf',
59+
in_template='OASIS30ANTs',
60+
template_spec=None,
61+
use_float=True,
62+
normalization_quality='precise',
63+
omp_nthreads=None,
64+
mem_gb=3.0,
65+
bids_suffix='T1w',
66+
atropos_refine=True,
67+
atropos_use_random_seed=True,
68+
atropos_model=None,
69+
use_laplacian=True,
70+
bspline_fitting_distance=200
71+
):
6972
"""
7073
Build a workflow for atlas-based brain extraction on anatomical MRI data.
7174
@@ -201,10 +204,6 @@ def init_brain_extraction_wf(name='brain_extraction_wf',
201204
'out_segm', 'out_tpms']),
202205
name='outputnode')
203206

204-
copy_xform = pe.Node(CopyXForm(
205-
fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image']),
206-
name='copy_xform', run_without_submitting=True)
207-
208207
trunc = pe.MapNode(ImageMath(operation='TruncateImageIntensity', op2='0.01 0.999 256'),
209208
name='truncate_images', iterfield=['op1'])
210209
inu_n4 = pe.MapNode(
@@ -296,7 +295,6 @@ def init_brain_extraction_wf(name='brain_extraction_wf',
296295

297296
wf.connect([
298297
(inputnode, trunc, [('in_files', 'op1')]),
299-
(inputnode, copy_xform, [(('in_files', _pop), 'hdr_file')]),
300298
(inputnode, inu_n4_final, [('in_files', 'input_image')]),
301299
(inputnode, init_aff, [('in_mask', 'fixed_image_mask')]),
302300
(inputnode, norm, [('in_mask', fixed_mask_trait)]),
@@ -314,16 +312,11 @@ def init_brain_extraction_wf(name='brain_extraction_wf',
314312
(thr_brainmask, dil_brainmask, [('output_image', 'op1')]),
315313
(dil_brainmask, get_brainmask, [('output_image', 'op1')]),
316314
(inu_n4_final, apply_mask, [('output_image', 'in_file')]),
317-
(get_brainmask, apply_mask, [('output_image', 'mask_file')]),
318-
(get_brainmask, copy_xform, [('output_image', 'out_mask')]),
319-
(apply_mask, copy_xform, [('out_file', 'out_file')]),
320-
(inu_n4_final, copy_xform, [('output_image', 'bias_corrected'),
315+
(get_brainmask, apply_mask, [('output_image', 'in_mask')]),
316+
(get_brainmask, outputnode, [('output_image', 'out_mask')]),
317+
(inu_n4_final, outputnode, [('output_image', 'bias_corrected'),
321318
('bias_image', 'bias_image')]),
322-
(copy_xform, outputnode, [
323-
('out_file', 'out_file'),
324-
('out_mask', 'out_mask'),
325-
('bias_corrected', 'bias_corrected'),
326-
('bias_image', 'bias_image')]),
319+
(apply_mask, outputnode, [('out_file', 'out_file')]),
327320
])
328321

329322
if use_laplacian:
@@ -363,8 +356,8 @@ def init_brain_extraction_wf(name='brain_extraction_wf',
363356
run_without_submitting=True)
364357

365358
wf.disconnect([
366-
(get_brainmask, apply_mask, [('output_image', 'mask_file')]),
367-
(copy_xform, outputnode, [('out_mask', 'out_mask')]),
359+
(get_brainmask, apply_mask, [('output_image', 'in_mask')]),
360+
(get_brainmask, outputnode, [('output_image', 'out_mask')]),
368361
])
369362
wf.connect([
370363
(inu_n4, atropos_wf, [
@@ -376,7 +369,7 @@ def init_brain_extraction_wf(name='brain_extraction_wf',
376369
(atropos_wf, sel_wm, [('outputnode.out_tpms', 'inlist')]),
377370
(sel_wm, inu_n4_final, [('out', 'weight_image')]),
378371
(atropos_wf, apply_mask, [
379-
('outputnode.out_mask', 'mask_file')]),
372+
('outputnode.out_mask', 'in_mask')]),
380373
(atropos_wf, outputnode, [
381374
('outputnode.out_mask', 'out_mask'),
382375
('outputnode.out_segm', 'out_segm'),
@@ -451,7 +444,6 @@ def init_atropos_wf(name='atropos_wf',
451444
out_tpms : str
452445
Output :abbr:`TPMs (tissue probability maps)`
453446
454-
455447
"""
456448
wf = pe.Workflow(name)
457449

@@ -460,10 +452,6 @@ def init_atropos_wf(name='atropos_wf',
460452
outputnode = pe.Node(niu.IdentityInterface(
461453
fields=['out_mask', 'out_segm', 'out_tpms']), name='outputnode')
462454

463-
copy_xform = pe.Node(CopyXForm(
464-
fields=['out_mask', 'out_segm', 'out_tpms']),
465-
name='copy_xform', run_without_submitting=True)
466-
467455
# Run atropos (core node)
468456
atropos = pe.Node(Atropos(
469457
dimension=3,
@@ -561,14 +549,13 @@ def init_atropos_wf(name='atropos_wf',
561549
depad_csf = pe.Node(ImageMath(operation='PadImage', op2='-%d' % padding),
562550
name='27_depad_csf')
563551

564-
msk_conform = pe.Node(niu.Function(function=_conform_mask), name='msk_conform')
552+
msk_dtype = pe.Node(niu.Function(function=_ensure_dtype), name='msk_dtype')
553+
msk_dtype.inputs.dtype = 'uint8'
565554
merge_tpms = pe.Node(niu.Merge(in_segmentation_model[0]), name='merge_tpms')
566555
wf.connect([
567-
(inputnode, copy_xform, [(('in_files', _pop), 'hdr_file')]),
568556
(inputnode, pad_mask, [('in_mask', 'op1')]),
569557
(inputnode, atropos, [('in_files', 'intensity_images'),
570558
('in_mask_dilated', 'mask_image')]),
571-
(inputnode, msk_conform, [(('in_files', _pop), 'in_reference')]),
572559
(atropos, pad_segm, [('classified_image', 'op1')]),
573560
(pad_segm, sel_labels, [('output_image', 'in_segm')]),
574561
(sel_labels, get_wm, [('out_wm', 'op1')]),
@@ -602,14 +589,10 @@ def init_atropos_wf(name='atropos_wf',
602589
(depad_csf, merge_tpms, [('output_image', 'in1')]),
603590
(depad_gm, merge_tpms, [('output_image', 'in2')]),
604591
(depad_wm, merge_tpms, [('output_image', 'in3')]),
605-
(depad_mask, msk_conform, [('output_image', 'in_mask')]),
606-
(msk_conform, copy_xform, [('out', 'out_mask')]),
607-
(depad_segm, copy_xform, [('output_image', 'out_segm')]),
608-
(merge_tpms, copy_xform, [('out', 'out_tpms')]),
609-
(copy_xform, outputnode, [
610-
('out_mask', 'out_mask'),
611-
('out_segm', 'out_segm'),
612-
('out_tpms', 'out_tpms')]),
592+
(depad_mask, msk_dtype, [('output_image', 'in_mask')]),
593+
(msk_dtype, outputnode, [('out', 'out_mask')]),
594+
(depad_segm, outputnode, [('output_image', 'out_segm')]),
595+
(merge_tpms, outputnode, [('out', 'out_tpms')]),
613596
])
614597
return wf
615598

@@ -799,34 +782,25 @@ def _select_labels(in_segm, labels):
799782
return out_files
800783

801784

802-
def _conform_mask(in_mask, in_reference):
803-
"""Ensures the mask headers make sense and match those of the T1w"""
785+
def _ensure_dtype(in_mask, dtype='uint8'):
786+
"""Ensure the mask headers make sense and match those of the T1w."""
804787
from pathlib import Path
805788
import numpy as np
806789
import nibabel as nb
807790
from nipype.utils.filemanip import fname_presuffix
808791

809-
ref = nb.load(in_reference)
810792
nii = nb.load(in_mask)
811793
hdr = nii.header.copy()
812-
hdr.set_data_dtype('int16')
794+
hdr.set_data_dtype(dtype)
813795
hdr.set_slope_inter(1, 0)
814796

815-
qform, qcode = ref.header.get_qform(coded=True)
816-
if qcode is not None:
817-
hdr.set_qform(qform, int(qcode))
818-
819-
sform, scode = ref.header.get_sform(coded=True)
820-
if scode is not None:
821-
hdr.set_sform(sform, int(scode))
822-
823797
if '_maths' in in_mask: # Cut the name at first _maths occurrence
824798
ext = ''.join(Path(in_mask).suffixes)
825799
basename = Path(in_mask).name
826800
in_mask = basename.split('_maths')[0] + ext
827801

828802
out_file = fname_presuffix(in_mask, suffix='_mask',
829803
newpath=str(Path()))
830-
nii.__class__(np.asanyarray(nii.dataobj).astype('int16'), ref.affine,
804+
nii.__class__(np.asanyarray(nii.dataobj).astype(dtype), nii.affine,
831805
hdr).to_filename(out_file)
832806
return out_file

niworkflows/func/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
from nipype.pipeline import engine as pe
88
from nipype.interfaces import utility as niu, fsl, afni
9+
from nipype.interfaces.ants.utils import AI
910

1011
from templateflow.api import get as get_template
1112

1213
from ..engine.workflows import LiterateWorkflow as Workflow
13-
from ..interfaces.ants import AI
1414
from ..interfaces.fixes import (
1515
FixHeaderRegistration as Registration,
1616
FixHeaderApplyTransforms as ApplyTransforms,

0 commit comments

Comments
 (0)