def test_BrainExtractionRPT(monkeypatch, moving, nthreads): """ test antsBrainExtraction with reports""" def _agg(objekt, runtime): outputs = Bunch(BrainExtractionMask=os.path.join( datadir, 'testBrainExtractionRPTBrainExtractionMask.nii.gz') ) return outputs # Patch the _run_interface method monkeypatch.setattr(BrainExtractionRPT, '_run_interface', _run_interface_mock) monkeypatch.setattr(BrainExtractionRPT, 'aggregate_outputs', _agg) bex_rpt = BrainExtractionRPT( generate_report=True, dimension=3, use_floatingpoint_precision=1, anatomical_image=moving, brain_template=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), brain_probability_mask=str( get_template('OASIS30ANTs', resolution=1, label='brain', suffix='probseg')), extraction_registration_mask=str( get_template('OASIS30ANTs', resolution=1, desc='BrainCerebellumRegistration', suffix='mask')), out_prefix='testBrainExtractionRPT', debug=True, # run faster for testing purposes num_threads=nthreads ) _smoke_test_report(bex_rpt, 'testANTSBrainExtraction.svg')
def test_ROIsPlot(): """ the BET report capable test """ import nibabel as nb import numpy as np im = nb.load(str( get_template('OASIS30ANTs', resolution=1, desc='4', suffix='dseg', extensions=['.nii', '.nii.gz']))) lookup = np.zeros(5, dtype=int) lookup[1] = 1 lookup[2] = 4 lookup[3] = 2 lookup[4] = 3 newdata = lookup[np.round(im.get_data()).astype(int)] hdr = im.header.copy() hdr.set_data_dtype('int16') hdr['scl_slope'] = 1 hdr['scl_inter'] = 0 out_file = os.path.abspath('segments.nii.gz') nb.Nifti1Image(newdata, im.affine, hdr).to_filename(out_file) roi_rpt = ROIsPlot( generate_report=True, in_file=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), in_mask=str( get_template('OASIS30ANTs', resolution=1, desc='brain', suffix='mask')), in_rois=[out_file], levels=[1.5, 2.5, 3.5], colors=['gold', 'magenta', 'b'], ) _smoke_test_report(roi_rpt, 'testROIsPlot.svg')
def test_SimpleShowMaskRPT(): """ the BET report capable test """ msk_rpt = SimpleShowMaskRPT( generate_report=True, background_file=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), mask_file=str( get_template('OASIS30ANTs', resolution=1, desc='BrainCerebellumRegistration', suffix='mask')) ) _smoke_test_report(msk_rpt, 'testSimpleMask.svg')
def _validate_results(self): forward_transform = self._results['composite_transform'] input_mask = self.inputs.moving_mask if isdefined(self.inputs.reference_mask): target_mask = self.inputs.reference_mask else: resolution = self.inputs.template_resolution target_mask = get_template(self.inputs.template, resolution=resolution, desc='brain', suffix='mask') res = ApplyTransforms(dimension=3, input_image=input_mask, reference_image=str(target_mask), transforms=forward_transform, interpolation='NearestNeighbor', resource_monitor=False).run() input_mask_data = (nb.load(res.outputs.output_image).get_data() != 0) target_mask_data = (nb.load(str(target_mask)).get_data() != 0) overlap_voxel_count = np.logical_and(input_mask_data, target_mask_data) overlap_perc = float(overlap_voxel_count.sum()) / float(input_mask_data.sum()) * 100 assert overlap_perc > 50, \ "Normalization failed: only %d%% of the normalized moving image " \ "mask overlaps with the reference image mask." % overlap_perc
def test_ROIsPlot2(tmp_path): """ the BET report capable test """ import nibabel as nb import numpy as np im = nb.load( str( get_template( "OASIS30ANTs", resolution=1, desc="4", suffix="dseg", extension=[".nii", ".nii.gz"], ))) lookup = np.zeros(5, dtype=int) lookup[1] = 1 lookup[2] = 4 lookup[3] = 2 lookup[4] = 3 newdata = lookup[np.round(im.get_fdata()).astype(int)] hdr = im.header.copy() hdr.set_data_dtype("int16") hdr["scl_slope"] = 1 hdr["scl_inter"] = 0 out_files = [] for i in range(1, 5): seg = np.zeros_like(newdata, dtype="uint8") seg[(newdata > 0) & (newdata <= i)] = 1 out_file = str(tmp_path / ("segments%02d.nii.gz" % i)) nb.Nifti1Image(seg, im.affine, hdr).to_filename(out_file) out_files.append(out_file) roi_rpt = ROIsPlot( generate_report=True, in_file=str( get_template("OASIS30ANTs", resolution=1, desc=None, suffix="T1w")), in_mask=str( get_template("OASIS30ANTs", resolution=1, desc="brain", suffix="mask")), in_rois=out_files, colors=["gold", "lightblue", "b", "g"], ) _smoke_test_report(roi_rpt, "testROIsPlot2.svg")
def test_ROIsPlot2(tmp_path): """ the BET report capable test """ import nibabel as nb import numpy as np im = nb.load( str( get_template('OASIS30ANTs', resolution=1, desc='4', suffix='dseg', extension=['.nii', '.nii.gz']))) lookup = np.zeros(5, dtype=int) lookup[1] = 1 lookup[2] = 4 lookup[3] = 2 lookup[4] = 3 newdata = lookup[np.round(im.get_data()).astype(int)] hdr = im.header.copy() hdr.set_data_dtype('int16') hdr['scl_slope'] = 1 hdr['scl_inter'] = 0 out_files = [] for i in range(1, 5): seg = np.zeros_like(newdata, dtype='uint8') seg[(newdata > 0) & (newdata <= i)] = 1 out_file = str(tmp_path / ('segments%02d.nii.gz' % i)) nb.Nifti1Image(seg, im.affine, hdr).to_filename(out_file) out_files.append(out_file) roi_rpt = ROIsPlot(generate_report=True, in_file=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), in_mask=str( get_template('OASIS30ANTs', resolution=1, desc='brain', suffix='mask')), in_rois=out_files, colors=['gold', 'lightblue', 'b', 'g']) _smoke_test_report(roi_rpt, 'testROIsPlot2.svg')
def test_ROIsPlot(tmp_path): """ the BET report capable test """ import nibabel as nb import numpy as np im = nb.load( str( get_template( "OASIS30ANTs", resolution=1, desc="4", suffix="dseg", extension=[".nii", ".nii.gz"], ))) lookup = np.zeros(5, dtype=int) lookup[1] = 1 lookup[2] = 4 lookup[3] = 2 lookup[4] = 3 newdata = lookup[np.round(im.get_fdata()).astype(int)] hdr = im.header.copy() hdr.set_data_dtype("int16") hdr["scl_slope"] = 1 hdr["scl_inter"] = 0 out_file = str(tmp_path / "segments.nii.gz") nb.Nifti1Image(newdata, im.affine, hdr).to_filename(out_file) roi_rpt = ROIsPlot( generate_report=True, in_file=str( get_template("OASIS30ANTs", resolution=1, desc=None, suffix="T1w")), in_mask=str( get_template("OASIS30ANTs", resolution=1, desc="brain", suffix="mask")), in_rois=[out_file], levels=[1.5, 2.5, 3.5], colors=["gold", "magenta", "b"], ) _smoke_test_report(roi_rpt, "testROIsPlot.svg")
def get_template_specs(in_template, template_spec=None, default_resolution=1): """ Parse template specifications >>> get_template_specs('MNI152NLin2009cAsym', {'suffix': 'T1w'})[1] {'resolution': 1} >>> get_template_specs('MNI152NLin2009cAsym', {'res': '2', 'suffix': 'T1w'})[1] {'resolution': '2'} >>> specs = get_template_specs('MNIInfant', {'res': '2', 'cohort': '10', 'suffix': 'T1w'})[1] >>> sorted(specs.items()) [('cohort', '10'), ('resolution', '2')] >>> get_template_specs('MNI152NLin2009cAsym', ... {'suffix': 'T1w', 'cohort': 1})[1] # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): RuntimeError: ... >>> get_template_specs('MNI152NLin2009cAsym', ... {'suffix': 'T1w', 'res': '1|2'})[1] # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): RuntimeError: ... """ from templateflow.api import get as get_template # Massage spec (start creating if None) template_spec = template_spec or {} template_spec["desc"] = template_spec.get("desc", None) template_spec["atlas"] = template_spec.get("atlas", None) template_spec["resolution"] = template_spec.pop( "res", template_spec.get("resolution", default_resolution)) common_spec = {"resolution": template_spec["resolution"]} if "cohort" in template_spec: common_spec["cohort"] = template_spec["cohort"] tpl_target_path = get_template(in_template, **template_spec) if not tpl_target_path: raise RuntimeError("""\ Could not find template "{0}" with specs={1}. Please revise your template \ argument.""".format(in_template, template_spec)) if isinstance(tpl_target_path, list): raise RuntimeError("""\ The available template modifiers ({0}) did not select a unique template \ (got "{1}"). Please revise your template argument.""".format( template_spec, ", ".join([str(p) for p in tpl_target_path]))) return str(tpl_target_path), common_spec
def test_BrainExtractionRPT(monkeypatch, moving, nthreads): """ test antsBrainExtraction with reports""" def _agg(objekt, runtime): outputs = objekt.output_spec() outputs.BrainExtractionMask = os.path.join( datadir, "testBrainExtractionRPTBrainExtractionMask.nii.gz") outputs.out_report = os.path.join(runtime.cwd, objekt.inputs.out_report) return outputs # Patch the _run_interface method monkeypatch.setattr(BrainExtractionRPT, "_run_interface", _run_interface_mock) monkeypatch.setattr(BrainExtractionRPT, "aggregate_outputs", _agg) bex_rpt = BrainExtractionRPT( generate_report=True, dimension=3, use_floatingpoint_precision=1, anatomical_image=moving, brain_template=str( get_template("OASIS30ANTs", resolution=1, desc=None, suffix="T1w")), brain_probability_mask=str( get_template("OASIS30ANTs", resolution=1, label="brain", suffix="probseg")), extraction_registration_mask=str( get_template( "OASIS30ANTs", resolution=1, desc="BrainCerebellumRegistration", suffix="mask", )), out_prefix="testBrainExtractionRPT", debug=True, # run faster for testing purposes num_threads=nthreads, ) _smoke_test_report(bex_rpt, "testANTSBrainExtraction.svg")
def test_compression(tmp_path): """ the BET report capable test """ uncompressed = pe.Node( SimpleShowMaskRPT(generate_report=True, background_file=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), mask_file=str( get_template('OASIS30ANTs', resolution=1, desc='BrainCerebellumRegistration', suffix='mask')), compress_report=False), name='uncompressed', base_dir=str(tmp_path)).run().outputs.out_report compressed = pe.Node( SimpleShowMaskRPT(generate_report=True, background_file=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), mask_file=str( get_template('OASIS30ANTs', resolution=1, desc='BrainCerebellumRegistration', suffix='mask')), compress_report=True), name='compressed', base_dir=str(tmp_path)).run().outputs.out_report size = int(os.stat(uncompressed).st_size) size_compress = int(os.stat(compressed).st_size) assert size >= size_compress, ('The uncompressed report is smaller (%d)' 'than the compressed report (%d)' % (size, size_compress))
def test_ROIsPlot(tmp_path): """ the BET report capable test """ import nibabel as nb import numpy as np im = nb.load( str( get_template('OASIS30ANTs', resolution=1, desc='4', suffix='dseg', extension=['.nii', '.nii.gz']))) lookup = np.zeros(5, dtype=int) lookup[1] = 1 lookup[2] = 4 lookup[3] = 2 lookup[4] = 3 newdata = lookup[np.round(im.get_data()).astype(int)] hdr = im.header.copy() hdr.set_data_dtype('int16') hdr['scl_slope'] = 1 hdr['scl_inter'] = 0 out_file = str(tmp_path / 'segments.nii.gz') nb.Nifti1Image(newdata, im.affine, hdr).to_filename(out_file) roi_rpt = ROIsPlot( generate_report=True, in_file=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), in_mask=str( get_template('OASIS30ANTs', resolution=1, desc='brain', suffix='mask')), in_rois=[out_file], levels=[1.5, 2.5, 3.5], colors=['gold', 'magenta', 'b'], ) _smoke_test_report(roi_rpt, 'testROIsPlot.svg')
def mni_downsampled(tmp_path_factory): tmp_path = tmp_path_factory.mktemp(basename="mni_downsampled") os.chdir(str(tmp_path)) tpl = get_template("MNI152NLin2009cAsym", resolution=2, desc="brain", suffix="mask") result = ants.ResampleImageBySpacing( dimension=3, input_image=tpl, out_spacing=(6, 6, 6) ).run() assert result.outputs is not None return result.outputs.output_image
def _run_interface(self, runtime, correct_return_codes=(0, )): self.resample = False input_space = self.inputs.input_space reference_space = self.inputs.reference_space reference_res = (self.inputs.reference_res if isdefined(self.inputs.reference_res) else None) if not isdefined(self.inputs.reference_image): if reference_res is not None: self.inputs.reference_image = get_template( reference_space, resolution=reference_res, desc="brain", suffix="mask", ) input_image = nib.load(self.inputs.input_image) reference_image = nib.load(self.inputs.reference_image) input_matches_reference = input_image.shape[: 3] == reference_image.shape[: 3] input_matches_reference = input_matches_reference and np.allclose( input_image.affine, reference_image.affine, atol=1e-2, rtol=1e-2, # tolerance of 0.01 mm ) self.inputs.dimension = 3 input_image_nvol = nvol(input_image) if input_image_nvol > 0: self.inputs.input_image_type = 3 # time series transforms = ["identity"] if input_space != reference_space: xfm = getresource( f"tpl_{reference_space}_from_{input_space}_mode_image_xfm.h5") assert Path(xfm).is_file() transforms = [str(xfm)] self.inputs.transforms = transforms if (not input_matches_reference or set(transforms) != set(["identity"]) or not self.inputs.lazy): self.resample = True runtime = super(Resample, self)._run_interface(runtime, correct_return_codes) return runtime
def spatial_normalization(settings, mod='T1w', name='SpatialNormalization', resolution=2): """ A simple workflow to perform spatial normalization """ # Have some settings handy tpl_id = settings.get('template_id', 'MNI152NLin2009cAsym') # Define workflow interface workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['moving_image', 'moving_mask']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['inverse_composite_transform', 'out_report']), name='outputnode') # Spatial normalization norm = pe.Node( RobustMNINormalization( flavor='testing' if settings.get('testing', False) else 'fast', num_threads=settings.get('ants_nthreads'), float=settings.get('ants_float', False), template=tpl_id, template_resolution=2, reference=mod, generate_report=True, ), name='SpatialNormalization', # Request all MultiProc processes when ants_nthreads > n_procs num_threads=min( settings.get('ants_nthreads', DEFAULTS['ants_nthreads']), settings.get('n_procs', 1)), mem_gb=3) norm.inputs.reference_mask = str( get_template(tpl_id, resolution=resolution, desc='brain', suffix='mask')) workflow.connect([ (inputnode, norm, [('moving_image', 'moving_image'), ('moving_mask', 'moving_mask')]), (norm, outputnode, [('inverse_composite_transform', 'inverse_composite_transform'), ('out_report', 'out_report')]), ]) return workflow
def spatial_normalization(name="SpatialNormalization"): """Create a simplied workflow to perform fast spatial normalization.""" from niworkflows.interfaces.reportlets.registration import ( SpatialNormalizationRPT as RobustMNINormalization, ) # Have the template id handy tpl_id = config.workflow.template_id # Define workflow interface workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface( fields=["moving_image", "moving_mask", "modality"]), name="inputnode", ) outputnode = pe.Node( niu.IdentityInterface( fields=["inverse_composite_transform", "out_report"]), name="outputnode", ) # Spatial normalization norm = pe.Node( RobustMNINormalization( flavor=["testing", "fast"][config.execution.debug], num_threads=config.nipype.omp_nthreads, float=config.execution.ants_float, template=tpl_id, generate_report=True, ), name="SpatialNormalization", # Request all MultiProc processes when ants_nthreads > n_procs num_threads=config.nipype.omp_nthreads, mem_gb=3, ) norm.inputs.reference_mask = str( get_template(tpl_id, resolution=2, desc="brain", suffix="mask")) # fmt: off workflow.connect([ (inputnode, norm, [("moving_image", "moving_image"), ("moving_mask", "moving_mask"), ("modality", "reference")]), (norm, outputnode, [("inverse_composite_transform", "inverse_composite_transform"), ("out_report", "out_report")]), ]) # fmt: on return workflow
def airmsk_wf(name='AirMaskWorkflow'): """ Implements the Step 1 of [Mortamet2009]_. .. workflow:: from mriqc.workflows.anatomical import airmsk_wf from mriqc.testing import mock_config with mock_config(): wf = airmsk_wf() """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=[ 'in_file', 'in_mask', 'head_mask', 'inverse_composite_transform' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['hat_mask', 'air_mask', 'art_mask', 'rot_mask']), name='outputnode') rotmsk = pe.Node(RotationMask(), name='RotationMask') invt = pe.Node(ants.ApplyTransforms(dimension=3, default_value=0, interpolation='MultiLabel', float=True), name='invert_xfm') invt.inputs.input_image = str( get_template('MNI152NLin2009cAsym', resolution=1, desc='head', suffix='mask')) qi1 = pe.Node(ArtifactMask(), name='ArtifactMask') workflow.connect([(inputnode, rotmsk, [('in_file', 'in_file')]), (inputnode, qi1, [('in_file', 'in_file'), ('head_mask', 'head_mask')]), (rotmsk, qi1, [('out_file', 'rot_mask')]), (inputnode, invt, [('in_mask', 'reference_image'), ('inverse_composite_transform', 'transforms')]), (invt, qi1, [('output_image', 'nasion_post_mask')]), (qi1, outputnode, [('out_hat_msk', 'hat_mask'), ('out_air_msk', 'air_mask'), ('out_art_msk', 'art_mask')]), (rotmsk, outputnode, [('out_file', 'rot_mask')])]) return workflow
def test_ROIsPlot2(): """ the BET report capable test """ import nibabel as nb import numpy as np im = nb.load(str( get_template('OASIS30ANTs', resolution=1, desc='4', suffix='dseg', extensions=['.nii', '.nii.gz']))) lookup = np.zeros(5, dtype=int) lookup[1] = 1 lookup[2] = 4 lookup[3] = 2 lookup[4] = 3 newdata = lookup[np.round(im.get_data()).astype(int)] hdr = im.header.copy() hdr.set_data_dtype('int16') hdr['scl_slope'] = 1 hdr['scl_inter'] = 0 out_files = [] for i in range(1, 5): seg = np.zeros_like(newdata, dtype='uint8') seg[(newdata > 0) & (newdata <= i)] = 1 out_file = os.path.abspath('segments%02d.nii.gz' % i) nb.Nifti1Image(seg, im.affine, hdr).to_filename(out_file) out_files.append(out_file) roi_rpt = ROIsPlot( generate_report=True, in_file=str( get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')), in_mask=str( get_template('OASIS30ANTs', resolution=1, desc='brain', suffix='mask')), in_rois=out_files, colors=['gold', 'lightblue', 'b', 'g'] ) _smoke_test_report(roi_rpt, 'testROIsPlot2.svg')
def spatial_normalization(name='SpatialNormalization', resolution=2): """Create a simplied workflow to perform fast spatial normalization.""" from niworkflows.interfaces.registration import (RobustMNINormalizationRPT as RobustMNINormalization) # Have the template id handy tpl_id = config.workflow.template_id # Define workflow interface workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['moving_image', 'moving_mask', 'modality']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['inverse_composite_transform', 'out_report']), name='outputnode') # Spatial normalization norm = pe.Node( RobustMNINormalization( flavor=['testing', 'fast'][config.execution.debug], num_threads=config.nipype.omp_nthreads, float=config.execution.ants_float, template=tpl_id, template_resolution=resolution, generate_report=True, ), name='SpatialNormalization', # Request all MultiProc processes when ants_nthreads > n_procs num_threads=config.nipype.omp_nthreads, mem_gb=3) norm.inputs.reference_mask = str( get_template(tpl_id, resolution=resolution, desc='brain', suffix='mask')) workflow.connect([ (inputnode, norm, [('moving_image', 'moving_image'), ('moving_mask', 'moving_mask'), ('modality', 'reference')]), (norm, outputnode, [('inverse_composite_transform', 'inverse_composite_transform'), ('out_report', 'out_report')]), ]) return workflow
def _fetch_data(self): """Converts inputspec to files""" if (self.inputs.surface_target == "fsnative" or self.inputs.volume_target != "MNI152NLin2009cAsym"): # subject space is not support yet raise NotImplementedError annotation_files = sorted(glob(os.path.join(self.inputs.subjects_dir, self.inputs.surface_target, 'label', '*h.aparc.annot'))) if not annotation_files: raise IOError("Freesurfer annotations for %s not found in %s" % ( self.inputs.surface_target, self.inputs.subjects_dir)) label_file = str(get_template( 'MNI152NLin2009cAsym', resolution=2, desc='DKT31', suffix='dseg')) return annotation_files, label_file
def _fetch_data(self): """Converts inputspec to files""" if (self.inputs.surface_target == "fsnative" or self.inputs.volume_target != "MNI152NLin2009cAsym"): # subject space is not support yet raise NotImplementedError annotation_files = sorted( glob( os.path.join(self.inputs.subjects_dir, self.inputs.surface_target, 'label', '*h.aparc.annot'))) if not annotation_files: raise IOError( "Freesurfer annotations for %s not found in %s" % (self.inputs.surface_target, self.inputs.subjects_dir)) label_file = str( get_template('MNI152NLin2009cAsym', resolution=2, desc='DKT31', suffix='dseg')) return annotation_files, label_file
def prep_for_fmriprep(bidsdir, rawdir, substr): #make subject dir, anat and func subid = substr.replace('-', '_').replace('_', '') anatdir = bidsdir + '/sub-' + subid + '/anat/' funcdir = bidsdir + '/sub-' + subid + '/func/' os.makedirs(anatdir, exist_ok=True) os.makedirs(funcdir, exist_ok=True) # get t1brain and MNI template t1brain = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/highres.nii.gz' % substr template = str( get_template('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='T1w', extension=['.nii', '.nii.gz'])) ## registered T1w to template for fmriprep standard ### this reg files may not be used tranformfile = tempfile.mkdtemp() reg = Registration() reg.inputs.fixed_image = template reg.inputs.moving_image = t1brain reg.inputs.output_transform_prefix = tranformfile + '/t12mni_' reg.inputs.transforms = ['Affine', 'SyN'] reg.inputs.transform_parameters = [(2.0, ), (0.25, 3.0, 0.0)] reg.inputs.number_of_iterations = [[1500, 200], [100, 50, 30]] reg.inputs.dimension = 3 reg.inputs.num_threads = 3 reg.inputs.write_composite_transform = True reg.inputs.collapse_output_transforms = False reg.inputs.initialize_transforms_per_stage = True reg.inputs.metric = ['Mattes'] * 2 reg.inputs.metric_weight = [ 1 ] * 2 # Default (value ignored currently by ANTs) reg.inputs.radius_or_number_of_bins = [32] * 2 reg.inputs.sampling_strategy = ['Random', None] reg.inputs.sampling_percentage = [0.05, None] reg.inputs.convergence_threshold = [1.e-8, 1.e-9] reg.inputs.convergence_window_size = [20] * 2 reg.inputs.smoothing_sigmas = [[1, 0], [2, 1, 0]] reg.inputs.sigma_units = ['vox'] * 2 reg.inputs.shrink_factors = [[2, 1], [3, 2, 1]] reg.inputs.use_estimate_learning_rate_once = [True, True] reg.inputs.use_histogram_matching = [True, True] # This is the default #reg.inputs.output_warped_image = 'output_warped_image.nii.gz' reg.cmdline reg.run() ## copy transform file to fmriprep directory mni2twtransform = anatdir + '/sub-' + subid + '_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5' t1w2mnitransform = anatdir + '/sub-' + subid + '_from-T1w_to-MNI152NLin2009cAsym_mode-image_xfm.h5' copyfile(tranformfile + '/t12mni_Composite.h5', t1w2mnitransform) copyfile(tranformfile + '/t12mni_InverseComposite.h5', mni2twtransform) ### warp the non-processed/filtered/smooth bold to fmriprep ### now functional boldmask = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/mask.nii.gz' % substr boldref = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI_SBREF.nii.gz' % substr boldprep = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.nii.gz' % substr reffile = tempfile.mkdtemp() + '/reffile.nii.gz' boldstd = reffile = tempfile.mkdtemp() + '/boldstd.nii.gz' maskstd = reffile = tempfile.mkdtemp() + '/maskstd.nii.gz' aw = fsl.ApplyWarp() aw.inputs.in_file = boldref aw.inputs.ref_file = template aw.inputs.field_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/example_func2standard_warp.nii.gz' % substr aw.inputs.out_file = reffile aw.inputs.output_type = 'NIFTI_GZ' res = aw.run() aw1 = fsl.ApplyWarp() aw1.inputs.interp = 'spline' aw1.inputs.ref_file = template aw1.inputs.field_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/example_func2standard_warp.nii.gz' % substr aw1.inputs.in_file = boldprep aw1.inputs.out_file = boldstd aw1.inputs.output_type = 'NIFTI_GZ' res1 = aw1.run() aw2 = fsl.ApplyWarp() aw2.inputs.in_file = boldmask aw2.inputs.ref_file = template aw2.inputs.field_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/example_func2standard_warp.nii.gz' % substr aw2.inputs.out_file = maskstd aw2.inputs.output_type = 'NIFTI_GZ' res2 = aw2.run() tr = nb.load(boldprep).header.get_zooms()[-1] jsontis = { "RepetitionTime": np.float64(tr), "TaskName": 'rest', "SkullStripped": False, } jsmaks = {"mask": True} #newname preprocbold = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz' preprocboldjson = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.json' preprocboldref = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_boldref.nii.gz' preprocmask = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz' preprocmaskjson = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-brain_mask.json' copyfile(maskstd, preprocmask) copyfile(reffile, preprocboldref) copyfile(boldstd, preprocbold) writejson(jsontis, preprocboldjson) writejson(jsmaks, preprocmaskjson) # get wm and csf mask to extract mean signals for regressors ### first warp the anatomical to bold space wmask = rawdir + '/UKB_Pipeline/%s/T1/T1_fast/T1_brain_pve_2.nii.gz' % substr csfmask = rawdir + '/UKB_Pipeline/%s/T1/T1_fast/T1_brain_pve_0.nii.gz' % substr t2funcwmask = tempfile.mkdtemp() + '/wmask.nii.gz' t2funcwcsf = tempfile.mkdtemp() + '/csf.nii.gz' aw = fsl.preprocess.ApplyXFM() aw.inputs.in_file = wmask aw.inputs.reference = boldref aw.inputs.in_matrix_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/highres2example_func.mat' % substr aw.inputs.out_file = t2funcwmask aw.inputs.apply_xfm = True aw.inputs.interp = 'nearestneighbour' aw.inputs.output_type = 'NIFTI_GZ' res = aw.run() aw2 = fsl.preprocess.ApplyXFM() aw2.inputs.in_file = csfmask aw2.inputs.reference = boldref aw2.inputs.in_matrix_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/highres2example_func.mat' % substr aw2.inputs.out_file = t2funcwcsf aw2.inputs.apply_xfm = True aw2.inputs.interp = 'nearestneighbour' aw2.inputs.output_type = 'NIFTI_GZ' res2 = aw2.run() # binarized and extract signals wmbin = nb.load(t2funcwmask).get_fdata() wmbin[wmbin < 0.99999] = 0 csfbin = nb.load(t2funcwcsf).get_fdata() csfbin[csfbin < 0.99999] = 0 maskbin = nb.load(boldmask).get_fdata() bolddata = nb.load(boldprep).get_fdata() wm_mean = bolddata[wmbin > 0, :].mean(axis=0) csf_mean = bolddata[csfbin > 0, :].mean(axis=0) global_mean = bolddata[maskbin > 0, :].mean(axis=0) #### combine all the regressors mcfile = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/mc/prefiltered_func_data_mcf.par' % substr rsmdfile = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/mc/prefiltered_func_data_mcf_abs.rms' % substr motionfile = np.loadtxt(mcfile) rsmd = np.loadtxt(rsmdfile) motionparam = pd.DataFrame( motionfile, columns=['rot_x', 'rot_y', 'rot_z', 'trans_x', 'trans_y', 'trans_z']) otherparam = pd.DataFrame({ 'global_signal': global_mean, 'white_matter': wm_mean, 'csf': csf_mean, 'rmsd': rsmd }) regressors = pd.concat([motionparam, otherparam], axis=1) jsonreg = {'regressor': 'not'} regcsv = funcdir + '/sub-' + subid + '_task-rest_desc-confounds_timeseries.tsv' regjson = funcdir + '/sub-' + subid + '_task-rest_desc-confounds_timeseries.json' regressors.to_csv(regcsv, index=None, sep='\t') writejson(jsonreg, regjson)
def init_rodent_brain_extraction_wf( ants_affine_init=False, factor=20, arc=0.12, step=4, grid=(0, 4, 4), debug=False, interim_checkpoints=True, mem_gb=3.0, mri_scheme="T2w", name="rodent_brain_extraction_wf", omp_nthreads=None, output_dir=None, template_id="Fischer344", template_specs=None, use_float=True, ): """ Build an atlas-based brain extraction pipeline for rodent T1w and T2w MRI data. Parameters ---------- ants_affine_init : :obj:`bool`, optional Set-up a pre-initialization step with ``antsAI`` to account for mis-oriented images. """ inputnode = pe.Node(niu.IdentityInterface(fields=["in_files", "in_mask"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface( fields=["out_corrected", "out_brain", "out_mask"]), name="outputnode", ) template_specs = template_specs or {} if template_id == "WHS" and "resolution" not in template_specs: template_specs["resolution"] = 2 # Find a suitable target template in TemplateFlow tpl_target_path = get_template( template_id, suffix=mri_scheme, **template_specs, ) if not tpl_target_path: raise RuntimeError( f"An instance of template <tpl-{template_id}> with MR scheme '{mri_scheme}'" " could not be found.") tpl_brainmask_path = get_template( template_id, atlas=None, hemi=None, desc="brain", suffix="probseg", **template_specs, ) or get_template( template_id, atlas=None, hemi=None, desc="brain", suffix="mask", **template_specs, ) tpl_regmask_path = get_template( template_id, atlas=None, desc="BrainCerebellumExtraction", suffix="mask", **template_specs, ) denoise = pe.Node(DenoiseImage(dimension=3, copy_header=True), name="denoise", n_procs=omp_nthreads) # Resample template to a controlled, isotropic resolution res_tmpl = pe.Node(RegridToZooms(zooms=HIRES_ZOOMS, smooth=True), name="res_tmpl") # Create Laplacian images lap_tmpl = pe.Node(ImageMath(operation="Laplacian", copy_header=True), name="lap_tmpl") tmpl_sigma = pe.Node(niu.Function(function=_lap_sigma), name="tmpl_sigma", run_without_submitting=True) norm_lap_tmpl = pe.Node(niu.Function(function=_norm_lap), name="norm_lap_tmpl") lap_target = pe.Node(ImageMath(operation="Laplacian", copy_header=True), name="lap_target") target_sigma = pe.Node(niu.Function(function=_lap_sigma), name="target_sigma", run_without_submitting=True) norm_lap_target = pe.Node(niu.Function(function=_norm_lap), name="norm_lap_target") # Set up initial spatial normalization ants_params = "testing" if debug else "precise" norm = pe.Node( Registration(from_file=pkgr_fn( "nirodents", f"data/artsBrainExtraction_{ants_params}_{mri_scheme}.json")), name="norm", n_procs=omp_nthreads, mem_gb=mem_gb, ) norm.inputs.float = use_float # main workflow wf = pe.Workflow(name) # truncate target intensity for N4 correction clip_target = pe.Node(IntensityClip(p_min=15, p_max=99.9), name="clip_target") # truncate template intensity to match target clip_tmpl = pe.Node(IntensityClip(p_min=5, p_max=98), name="clip_tmpl") clip_tmpl.inputs.in_file = _pop(tpl_target_path) # set INU bspline grid based on voxel size bspline_grid = pe.Node(niu.Function(function=_bspline_grid), name="bspline_grid") # INU correction of the target image init_n4 = pe.Node( N4BiasFieldCorrection( dimension=3, save_bias=False, copy_header=True, n_iterations=[50] * (4 - debug), convergence_threshold=1e-7, shrink_factor=4, rescale_intensities=True, ), n_procs=omp_nthreads, name="init_n4", ) clip_inu = pe.Node(IntensityClip(p_min=1, p_max=99.8), name="clip_inu") # Create a buffer interface as a cache for the actual inputs to registration buffernode = pe.Node(niu.IdentityInterface(fields=["hires_target"]), name="buffernode") # Merge image nodes mrg_target = pe.Node(niu.Merge(2), name="mrg_target") mrg_tmpl = pe.Node(niu.Merge(2), name="mrg_tmpl") # fmt: off wf.connect([ # Target image massaging (inputnode, denoise, [(("in_files", _pop), "input_image")]), (inputnode, bspline_grid, [(("in_files", _pop), "in_file")]), (bspline_grid, init_n4, [("out", "args")]), (denoise, clip_target, [("output_image", "in_file")]), (clip_target, init_n4, [("out_file", "input_image")]), (init_n4, clip_inu, [("output_image", "in_file")]), (clip_inu, target_sigma, [("out_file", "in_file")]), (clip_inu, buffernode, [("out_file", "hires_target")]), (buffernode, lap_target, [("hires_target", "op1")]), (target_sigma, lap_target, [("out", "op2")]), (lap_target, norm_lap_target, [("output_image", "in_file")]), (buffernode, mrg_target, [("hires_target", "in1")]), (norm_lap_target, mrg_target, [("out", "in2")]), # Template massaging (clip_tmpl, res_tmpl, [("out_file", "in_file")]), (res_tmpl, tmpl_sigma, [("out_file", "in_file")]), (res_tmpl, lap_tmpl, [("out_file", "op1")]), (tmpl_sigma, lap_tmpl, [("out", "op2")]), (lap_tmpl, norm_lap_tmpl, [("output_image", "in_file")]), (res_tmpl, mrg_tmpl, [("out_file", "in1")]), (norm_lap_tmpl, mrg_tmpl, [("out", "in2")]), # Setup inputs to spatial normalization (mrg_target, norm, [("out", "moving_image")]), (mrg_tmpl, norm, [("out", "fixed_image")]), ]) # fmt: on # Graft a template registration-mask if present if tpl_regmask_path: hires_mask = pe.Node( ApplyTransforms( input_image=_pop(tpl_regmask_path), transforms="identity", interpolation="Gaussian", float=True, ), name="hires_mask", mem_gb=1, ) # fmt: off wf.connect([ (res_tmpl, hires_mask, [("out_file", "reference_image")]), (hires_mask, norm, [("output_image", "fixed_image_masks")]), ]) # fmt: on # Finally project brain mask and refine INU correction map_brainmask = pe.Node( ApplyTransforms(interpolation="Gaussian", float=True), name="map_brainmask", mem_gb=1, ) map_brainmask.inputs.input_image = str(tpl_brainmask_path) thr_brainmask = pe.Node(Binarize(thresh_low=0.50), name="thr_brainmask") final_n4 = pe.Node( N4BiasFieldCorrection( dimension=3, save_bias=True, copy_header=True, n_iterations=[50] * 4, convergence_threshold=1e-7, rescale_intensities=True, shrink_factor=4, ), n_procs=omp_nthreads, name="final_n4", ) final_mask = pe.Node(ApplyMask(), name="final_mask") # fmt: off wf.connect([ (inputnode, map_brainmask, [(("in_files", _pop), "reference_image")]), (bspline_grid, final_n4, [("out", "args")]), (denoise, final_n4, [("output_image", "input_image")]), # Project template's brainmask into subject space (norm, map_brainmask, [("reverse_transforms", "transforms"), ("reverse_invert_flags", "invert_transform_flags")]), (map_brainmask, thr_brainmask, [("output_image", "in_file")]), # take a second pass of N4 (map_brainmask, final_n4, [("output_image", "mask_image")]), (final_n4, final_mask, [("output_image", "in_file")]), (thr_brainmask, final_mask, [("out_mask", "in_mask")]), (final_n4, outputnode, [("output_image", "out_corrected")]), (thr_brainmask, outputnode, [("out_mask", "out_mask")]), (final_mask, outputnode, [("out_file", "out_brain")]), ]) # fmt: on if interim_checkpoints: final_apply = pe.Node( ApplyTransforms(interpolation="BSpline", float=True), name="final_apply", mem_gb=1, ) final_report = pe.Node( SimpleBeforeAfter(after_label="target", before_label=f"tpl-{template_id}"), name="final_report", ) # fmt: off wf.connect([ (inputnode, final_apply, [(("in_files", _pop), "reference_image") ]), (res_tmpl, final_apply, [("out_file", "input_image")]), (norm, final_apply, [("reverse_transforms", "transforms"), ("reverse_invert_flags", "invert_transform_flags")]), (final_apply, final_report, [("output_image", "before")]), (outputnode, final_report, [("out_corrected", "after"), ("out_mask", "wm_seg")]), ]) # fmt: on if ants_affine_init: # Initialize transforms with antsAI lowres_tmpl = pe.Node(RegridToZooms(zooms=LOWRES_ZOOMS, smooth=True), name="lowres_tmpl") lowres_trgt = pe.Node(RegridToZooms(zooms=LOWRES_ZOOMS, smooth=True), name="lowres_trgt") init_aff = pe.Node( AI( convergence=(100, 1e-6, 10), metric=("Mattes", 32, "Random", 0.25), principal_axes=False, search_factor=(factor, arc), search_grid=(step, grid), transform=("Affine", 0.1), verbose=True, ), name="init_aff", n_procs=omp_nthreads, ) # fmt: off wf.connect([ (clip_inu, lowres_trgt, [("out_file", "in_file")]), (lowres_trgt, init_aff, [("out_file", "moving_image")]), (clip_tmpl, lowres_tmpl, [("out_file", "in_file")]), (lowres_tmpl, init_aff, [("out_file", "fixed_image")]), (init_aff, norm, [("output_transform", "initial_moving_transform") ]), ]) # fmt: on if tpl_regmask_path: lowres_mask = pe.Node( ApplyTransforms( input_image=_pop(tpl_regmask_path), transforms="identity", interpolation="MultiLabel", ), name="lowres_mask", mem_gb=1, ) # fmt: off wf.connect([ (lowres_tmpl, lowres_mask, [("out_file", "reference_image")]), (lowres_mask, init_aff, [("output_image", "fixed_image_mask") ]), ]) # fmt: on if interim_checkpoints: init_apply = pe.Node( ApplyTransforms(interpolation="BSpline", invert_transform_flags=[True]), name="init_apply", mem_gb=1, ) init_mask = pe.Node( ApplyTransforms(interpolation="Gaussian", invert_transform_flags=[True]), name="init_mask", mem_gb=1, ) init_mask.inputs.input_image = str(tpl_brainmask_path) init_report = pe.Node( SimpleBeforeAfter( out_report="init_report.svg", before_label="target", after_label="template", ), name="init_report", ) # fmt: off wf.connect([ (lowres_trgt, init_apply, [("out_file", "reference_image")]), (lowres_tmpl, init_apply, [("out_file", "input_image")]), (init_aff, init_apply, [("output_transform", "transforms")]), (lowres_trgt, init_report, [("out_file", "before")]), (init_apply, init_report, [("output_image", "after")]), (lowres_trgt, init_mask, [("out_file", "reference_image")]), (init_aff, init_mask, [("output_transform", "transforms")]), (init_mask, init_report, [("output_image", "wm_seg")]), ]) # fmt: on else: norm.inputs.initial_moving_transform_com = 1 if output_dir: ds_final_inu = pe.Node(DerivativesDataSink( base_directory=str(output_dir), desc="preproc", compress=True, ), name="ds_final_inu", run_without_submitting=True) ds_final_msk = pe.Node(DerivativesDataSink( base_directory=str(output_dir), desc="brain", suffix="mask", compress=True, ), name="ds_final_msk", run_without_submitting=True) # fmt: off wf.connect([ (inputnode, ds_final_inu, [("in_files", "source_file")]), (inputnode, ds_final_msk, [("in_files", "source_file")]), (outputnode, ds_final_inu, [("out_corrected", "in_file")]), (outputnode, ds_final_msk, [("out_mask", "in_file")]), ]) # fmt: on if interim_checkpoints: ds_report = pe.Node(DerivativesDataSink( base_directory=str(output_dir), desc="brain", suffix="mask", datatype="figures"), name="ds_report", run_without_submitting=True) # fmt: off wf.connect([ (inputnode, ds_report, [("in_files", "source_file")]), (final_report, ds_report, [("out_report", "in_file")]), ]) # fmt: on if ants_affine_init and interim_checkpoints: ds_report_init = pe.Node(DerivativesDataSink( base_directory=str(output_dir), desc="init", suffix="mask", datatype="figures"), name="ds_report_init", run_without_submitting=True) # fmt: off wf.connect([ (inputnode, ds_report_init, [("in_files", "source_file")]), (init_report, ds_report_init, [("out_report", "in_file")]), ]) # fmt: on return wf
def epi_mni_align(name='SpatialNormalization'): """ Estimate the transform that maps the EPI space into MNI152NLin2009cAsym. The input epi_mean is the averaged and brain-masked EPI timeseries Returns the EPI mean resampled in MNI space (for checking out registration) and the associated "lobe" parcellation in EPI space. .. workflow:: from mriqc.workflows.functional import epi_mni_align from mriqc.testing import mock_config with mock_config(): wf = epi_mni_align() """ from nipype.interfaces.ants import ApplyTransforms, N4BiasFieldCorrection from templateflow.api import get as get_template from niworkflows.interfaces.registration import (RobustMNINormalizationRPT as RobustMNINormalization) # Get settings testing = config.execution.debug n_procs = config.nipype.nprocs ants_nthreads = config.nipype.omp_nthreads workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['epi_mean', 'epi_mask']), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['epi_mni', 'epi_parc', 'report']), name='outputnode') n4itk = pe.Node(N4BiasFieldCorrection(dimension=3, copy_header=True), name='SharpenEPI') norm = pe.Node(RobustMNINormalization( explicit_masking=False, flavor='testing' if testing else 'precise', float=config.execution.ants_float, generate_report=True, moving='boldref', num_threads=ants_nthreads, reference='boldref', reference_image=str( get_template('MNI152NLin2009cAsym', resolution=2, suffix='boldref')), reference_mask=str( get_template('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='mask')), template='MNI152NLin2009cAsym', template_resolution=2, ), name='EPI2MNI', num_threads=n_procs, mem_gb=3) # Warp segmentation into EPI space invt = pe.Node(ApplyTransforms(float=True, input_image=str( get_template('MNI152NLin2009cAsym', resolution=1, desc='carpet', suffix='dseg')), dimension=3, default_value=0, interpolation='MultiLabel'), name='ResampleSegmentation') workflow.connect([ (inputnode, invt, [('epi_mean', 'reference_image')]), (inputnode, n4itk, [('epi_mean', 'input_image')]), (inputnode, norm, [('epi_mask', 'moving_mask')]), (n4itk, norm, [('output_image', 'moving_image')]), (norm, invt, [('inverse_composite_transform', 'transforms')]), (invt, outputnode, [('output_image', 'epi_parc')]), (norm, outputnode, [('warped_image', 'epi_mni'), ('out_report', 'report')]), ]) return workflow
def init_cbfqc_compt_wf(mem_gb, asl_file, metadata, omp_nthreads, name='cbfqc_compt_wf'): """ Create a workflow for :abbr:`cbfqc( compute cbf)`. Workflow Graph .. workflow:: :graph2use: orig :simple_form: yes from aslprep.workflows.asl.cbf import init_cbfqc_compt_wf wf = init_cbfqc_compt_wf(mem_gb=0.1) Parameters ---------- metadata : :obj:`dict` BIDS metadata for asl file name : :obj:`str` Name of workflow (default: ``cbfqc_compt_wf'``) Inputs ------ *cbf all cbf asl_mask asl mask NIFTI file t1w_tpms t1w probability maps t1_asl_xform t1w to asl transfromation file Outputs ------- qc_file qc measures in tsv """ workflow = Workflow(name=name) workflow.__desc__ = """\ The following quality control (qc) measures was estimated: framewise displacement and relative root mean square dice index. Other qc meaure include dice and jaccard indices, cross-correlation and coverage that estimate the coregistration quality of ASL and T1W images and normalization quality of ASL to template. Quality evaluation index (QEI) was also computed for CBF [@cbfqc]. The QEI is automated for objective quality evaluation of CBF maps and measured the CBF quality based on structural similarity,spatial variability and the percentatge of voxels with negtaive CBF within Grey matter """ inputnode = pe.Node(niu.IdentityInterface(fields=[ 'meancbf', 'avgscore', 'scrub', 'basil', 'asl_mask', 't1w_tpms', 'confmat', 'asl_mask_std', 't1_asl_xform', 'pv', 't1w_mask' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['qc_file']), name='outputnode') def _pick_csf(files): return files[-1] def _pick_gm(files): return files[0] def _pick_wm(files): return files[1] csf_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor', float=True), name='csf_tfm', mem_gb=0.1) wm_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor', float=True), name='wm_tfm', mem_gb=0.1) gm_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor', float=True), name='gm_tfm', mem_gb=0.1) mask_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor', float=True), name='masktonative', mem_gb=0.1) from templateflow.api import get as get_template brain_mask = str( get_template('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='mask')) from nipype.interfaces.afni import Resample resample = pe.Node(Resample(in_file=brain_mask, outputtype='NIFTI_GZ'), name='resample', mem_gb=0.1) qccompute = pe.Node(qccbf(in_file=asl_file), name='qccompute', run_without_submitting=True, mem_gb=0.2) workflow.connect([ (inputnode, csf_tfm, [('asl_mask', 'reference_image'), ('t1_asl_xform', 'transforms')]), (inputnode, csf_tfm, [(('t1w_tpms', _pick_csf), 'input_image')]), (inputnode, wm_tfm, [('asl_mask', 'reference_image'), ('t1_asl_xform', 'transforms')]), (inputnode, wm_tfm, [(('t1w_tpms', _pick_wm), 'input_image')]), (inputnode, gm_tfm, [('asl_mask', 'reference_image'), ('t1_asl_xform', 'transforms')]), (inputnode, gm_tfm, [(('t1w_tpms', _pick_gm), 'input_image')]), (inputnode, mask_tfm, [('asl_mask', 'reference_image'), ('t1_asl_xform', 'transforms'), ('t1w_mask', 'input_image')]), (mask_tfm, qccompute, [('output_image', 'in_t1mask')]), (inputnode, qccompute, [('asl_mask', 'in_aslmask'), ('confmat', 'in_confmat')]), (inputnode, qccompute, [(('asl_mask_std', _pick_csf), 'in_aslmaskstd') ]), (inputnode, resample, [(('asl_mask_std', _pick_csf), 'master')]), (resample, qccompute, [('out_file', 'in_templatemask')]), (gm_tfm, qccompute, [('output_image', 'in_greyM')]), (wm_tfm, qccompute, [('output_image', 'in_whiteM')]), (csf_tfm, qccompute, [('output_image', 'in_csf')]), (inputnode, qccompute, [('scrub', 'in_scrub'), ('meancbf', 'in_meancbf'), ('avgscore', 'in_avgscore'), ('basil', 'in_basil'), ('pv', 'in_pvc')]), (qccompute, outputnode, [('qc_file', 'qc_file')]), ]) return workflow
def anat_qc_workflow(name="anatMRIQC"): """ One-subject-one-session-one-run pipeline to extract the NR-IQMs from anatomical images .. workflow:: import os.path as op from mriqc.workflows.anatomical import anat_qc_workflow from mriqc.testing import mock_config with mock_config(): wf = anat_qc_workflow() """ dataset = config.workflow.inputs.get( "T1w", []) + config.workflow.inputs.get("T2w", []) message = BUILDING_WORKFLOW.format( detail=(f"for {len(dataset)} NIfTI files." if len(dataset) > 2 else f"({' and '.join(('<%s>' % v for v in dataset))})."), ) config.loggers.workflow.info(message) # Initialize workflow workflow = pe.Workflow(name=name) # Define workflow, inputs and outputs # 0. Get data inputnode = pe.Node(niu.IdentityInterface(fields=["in_file"]), name="inputnode") inputnode.iterables = [("in_file", dataset)] outputnode = pe.Node(niu.IdentityInterface(fields=["out_json"]), name="outputnode") # 1. Reorient anatomical image to_ras = pe.Node(ConformImage(check_dtype=False), name="conform") # 2. species specific skull-stripping if config.workflow.species.lower() == "human": skull_stripping = synthstrip_wf( omp_nthreads=config.nipype.omp_nthreads) ss_bias_field = "outputnode.bias_image" else: from nirodents.workflows.brainextraction import init_rodent_brain_extraction_wf skull_stripping = init_rodent_brain_extraction_wf( template_id=config.workflow.template_id) ss_bias_field = "final_n4.bias_image" # 3. Head mask hmsk = headmsk_wf() # 4. Spatial Normalization, using ANTs norm = spatial_normalization() # 5. Air mask (with and without artifacts) amw = airmsk_wf() # 6. Brain tissue segmentation if config.workflow.species.lower() == "human": segment = pe.Node( fsl.FAST(segments=True, out_basename="segment"), name="segmentation", mem_gb=5, ) seg_in_file = "in_files" dseg_out = "tissue_class_map" pve_out = "partial_volume_files" else: from niworkflows.interfaces.fixes import ApplyTransforms tpms = [ str(tpm) for tpm in get_template(config.workflow.template_id, label=["CSF", "GM", "WM"], suffix="probseg") ] xfm_tpms = pe.MapNode( ApplyTransforms( dimension=3, default_value=0, float=True, interpolation="Gaussian", output_image="prior.nii.gz", ), iterfield=["input_image"], name="xfm_tpms", ) xfm_tpms.inputs.input_image = tpms format_tpm_names = pe.Node( niu.Function( input_names=["in_files"], output_names=["file_format"], function=_format_tpm_names, execution={ "keep_inputs": True, "remove_unnecessary_outputs": False }, ), name="format_tpm_names", ) segment = pe.Node( ants.Atropos( initialization="PriorProbabilityImages", number_of_tissue_classes=3, prior_weighting=0.1, mrf_radius=[1, 1, 1], mrf_smoothing_factor=0.01, save_posteriors=True, out_classified_image_name="segment.nii.gz", output_posteriors_name_template="segment_%02d.nii.gz", ), name="segmentation", mem_gb=5, ) seg_in_file = "intensity_images" dseg_out = "classified_image" pve_out = "posteriors" # 7. Compute IQMs iqmswf = compute_iqms() # Reports repwf = individual_reports() # Connect all nodes # fmt: off workflow.connect([ (inputnode, to_ras, [("in_file", "in_file")]), (inputnode, iqmswf, [("in_file", "inputnode.in_file")]), (inputnode, norm, [(("in_file", _get_mod), "inputnode.modality")]), (to_ras, skull_stripping, [("out_file", "inputnode.in_files")]), (skull_stripping, segment, [("outputnode.out_brain", seg_in_file)]), (skull_stripping, hmsk, [("outputnode.out_corrected", "inputnode.in_file")]), (segment, hmsk, [(dseg_out, "inputnode.in_segm")]), (skull_stripping, norm, [("outputnode.out_corrected", "inputnode.moving_image"), ("outputnode.out_mask", "inputnode.moving_mask")]), (norm, amw, [("outputnode.inverse_composite_transform", "inputnode.inverse_composite_transform")]), (norm, iqmswf, [("outputnode.inverse_composite_transform", "inputnode.inverse_composite_transform")]), (norm, repwf, ([("outputnode.out_report", "inputnode.mni_report")])), (to_ras, amw, [("out_file", "inputnode.in_file")]), (skull_stripping, amw, [("outputnode.out_mask", "inputnode.in_mask")]), (hmsk, amw, [("outputnode.out_file", "inputnode.head_mask")]), (to_ras, iqmswf, [("out_file", "inputnode.in_ras")]), (skull_stripping, iqmswf, [("outputnode.out_corrected", "inputnode.inu_corrected"), (ss_bias_field, "inputnode.in_inu"), ("outputnode.out_mask", "inputnode.brainmask")]), (amw, iqmswf, [("outputnode.air_mask", "inputnode.airmask"), ("outputnode.hat_mask", "inputnode.hatmask"), ("outputnode.art_mask", "inputnode.artmask"), ("outputnode.rot_mask", "inputnode.rotmask")]), (segment, iqmswf, [(dseg_out, "inputnode.segmentation"), (pve_out, "inputnode.pvms")]), (hmsk, iqmswf, [("outputnode.out_file", "inputnode.headmask")]), (to_ras, repwf, [("out_file", "inputnode.in_ras")]), (skull_stripping, repwf, [("outputnode.out_corrected", "inputnode.inu_corrected"), ("outputnode.out_mask", "inputnode.brainmask")]), (hmsk, repwf, [("outputnode.out_file", "inputnode.headmask")]), (amw, repwf, [("outputnode.air_mask", "inputnode.airmask"), ("outputnode.art_mask", "inputnode.artmask"), ("outputnode.rot_mask", "inputnode.rotmask")]), (segment, repwf, [(dseg_out, "inputnode.segmentation")]), (iqmswf, repwf, [("outputnode.noisefit", "inputnode.noisefit")]), (iqmswf, repwf, [("outputnode.out_file", "inputnode.in_iqms")]), (iqmswf, outputnode, [("outputnode.out_file", "out_json")]), ]) if config.workflow.species.lower() == 'human': workflow.connect([ (inputnode, segment, [(("in_file", _get_imgtype), "img_type")]), ]) else: workflow.connect([ (skull_stripping, xfm_tpms, [("outputnode.out_brain", "reference_image")]), (norm, xfm_tpms, [("outputnode.inverse_composite_transform", "transforms")]), (xfm_tpms, format_tpm_names, [('output_image', 'in_files')]), (format_tpm_names, segment, [(('file_format', _pop), 'prior_image') ]), (skull_stripping, segment, [("outputnode.out_mask", "mask_image") ]), ]) # fmt: on # Upload metrics if not config.execution.no_sub: from ..interfaces.webapi import UploadIQMs upldwf = pe.Node(UploadIQMs(), name="UploadMetrics") upldwf.inputs.url = config.execution.webapi_url upldwf.inputs.strict = config.execution.upload_strict if config.execution.webapi_port: upldwf.inputs.port = config.execution.webapi_port # fmt: off workflow.connect([ (iqmswf, upldwf, [("outputnode.out_file", "in_iqms")]), (upldwf, repwf, [("api_id", "inputnode.api_id")]), ]) # fmt: on return workflow
def reference_mask(): return str( get_template('MNI152Lin', resolution=2, desc='brain', suffix='mask'))
def init_enhance_and_skullstrip_bold_wf(name='enhance_and_skullstrip_bold_wf', pre_mask=False, omp_nthreads=1): """ This workflow takes in a :abbr:`BOLD (blood-oxygen level-dependant)` :abbr:`fMRI (functional MRI)` average/summary (e.g., a reference image averaging non-steady-state timepoints), and sharpens the histogram with the application of the N4 algorithm for removing the :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal mask. Steps of this workflow are: 1. Calculate a tentative mask by registering (9-parameters) to *fMRIPrep*'s :abbr:`EPI (echo-planar imaging)` -*boldref* template, which is in MNI space. The tentative mask is obtained by resampling the MNI template's brainmask into *boldref*-space. 2. Binary dilation of the tentative mask with a sphere of 3mm diameter. 3. Run ANTs' ``N4BiasFieldCorrection`` on the input :abbr:`BOLD (blood-oxygen level-dependant)` average, using the mask generated in 1) instead of the internal Otsu thresholding. 4. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 5. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image with the latest mask calculated in 3), then use AFNI's ``3dUnifize`` to *standardize* the T2* contrast distribution. 6. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 7. Calculate a final mask as the intersection of 4) and 6). 8. Apply final mask on the enhanced reference. Step 1 can be skipped if the ``pre_mask`` argument is set to ``True`` and a tentative mask is passed in to the workflow throught the ``pre_mask`` Nipype input. .. workflow :: :graph2use: orig :simple_form: yes from niworkflows.func.util import init_enhance_and_skullstrip_bold_wf wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1) **Parameters** name : str Name of workflow (default: ``enhance_and_skullstrip_bold_wf``) pre_mask : bool Indicates whether the ``pre_mask`` input will be set (and thus, step 1 should be skipped). omp_nthreads : int number of threads available to parallel nodes **Inputs** in_file BOLD image (single volume) pre_mask : bool A tentative brain mask to initialize the workflow (requires ``pre_mask`` parameter set ``True``). **Outputs** bias_corrected_file the ``in_file`` after `N4BiasFieldCorrection`_ skull_stripped_file the ``bias_corrected_file`` after skull-stripping mask_file mask of the skull-stripped input file out_report reportlet for the skull-stripping .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053 """ workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'pre_mask']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['mask_file', 'skull_stripped_file', 'bias_corrected_file']), name='outputnode') # 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') # 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(ants.N4BiasFieldCorrection( dimension=3, copy_header=True, bspline_fitting_distance=200), name='n4_correct', n_procs=1) # Create a generous BET mask out of the bias-corrected EPI 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') # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( afni.Unifize( t2=True, outputtype='NIFTI_GZ', # Default -clfrac is 0.1, 0.4 was too conservative # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation) args='-clfrac 0.2 -rbt 18.3 65.0 90.0', out_file="uni.nii.gz"), name='unifize') fixhdr_unifize = pe.Node(CopyXForm(), name='fixhdr_unifize', mem_gb=0.1) # Run ANFI's 3dAutomask to extract a refined brain mask skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') fixhdr_skullstrip2 = pe.Node(CopyXForm(), name='fixhdr_skullstrip2', mem_gb=0.1) # Take intersection of both masks combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') # Compute masked brain apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask') if not pre_mask: bold_template = get_template('MNI152NLin2009cAsym', resolution=2, desc='fMRIPrep', suffix='boldref') brain_mask = get_template('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='mask') # Initialize transforms with antsAI init_aff = pe.Node(AI(fixed_image=str(bold_template), fixed_image_mask=str(brain_mask), metric=('Mattes', 32, 'Regular', 0.2), transform=('Affine', 0.1), search_factor=(20, 0.12), principal_axes=False, convergence=(10, 1e-6, 10), verbose=True), name='init_aff', n_procs=omp_nthreads) # Registration().version may be None if parseversion(Registration().version or '0.0.0') > Version('2.2.0'): init_aff.inputs.search_grid = (40, (0, 40, 40)) # Set up spatial normalization norm = pe.Node(Registration(from_file=pkgr_fn( 'fmriprep.data', 'epi_atlasbased_brainmask.json')), name='norm', n_procs=omp_nthreads) norm.inputs.fixed_image = str(bold_template) map_brainmask = pe.Node(ApplyTransforms(interpolation='MultiLabel', float=True, input_image=str(brain_mask)), name='map_brainmask') workflow.connect([ (inputnode, init_aff, [('in_file', 'moving_image')]), (inputnode, map_brainmask, [('in_file', 'reference_image')]), (inputnode, norm, [('in_file', 'moving_image')]), (init_aff, norm, [('output_transform', 'initial_moving_transform') ]), (norm, map_brainmask, [('reverse_invert_flags', 'invert_transform_flags'), ('reverse_transforms', 'transforms')]), (map_brainmask, pre_dilate, [('output_image', 'in_file')]), ]) else: workflow.connect([ (inputnode, pre_dilate, [('pre_mask', 'in_file')]), ]) workflow.connect([ (inputnode, check_hdr, [('in_file', 'reference')]), (pre_dilate, check_hdr, [('out_file', 'in_file')]), (check_hdr, n4_correct, [('out_file', 'mask_image')]), (inputnode, n4_correct, [('in_file', 'input_image')]), (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', 'mask_file')]), (skullstrip_first_pass, bet_mask, [('out_file', 'in_file')]), (bet_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')]), (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, outputnode, [('out_file', 'mask_file')]), (apply_mask, outputnode, [('out_file', 'skull_stripped_file')]), (n4_correct, outputnode, [('output_image', 'bias_corrected_file')]), ]) return workflow
def reference_mask(): return str(get_template('MNI152Lin', resolution=2, desc='brain', suffix='mask'))
def _get_ants_args(self): args = { "moving_image": self.inputs.moving_image, "num_threads": self.inputs.num_threads, "float": self.inputs.float, "terminal_output": "file", "write_composite_transform": True, "initial_moving_transform": self.inputs.initial_moving_transform, } """ Moving image handling - The following truth table maps out the intended action sequence. Future refactoring may more directly encode this. moving_mask and lesion_mask are files True = file False = None | moving_mask | explicit_masking | lesion_mask | action |-------------|------------------|-------------|------------------------------------------- | True | True | True | Update `moving_image` after applying | | | | mask. | | | | Set `moving_image_masks` applying | | | | `create_cfm` with `global_mask=True`. |-------------|------------------|-------------|------------------------------------------- | True | True | False | Update `moving_image` after applying | | | | mask. |-------------|------------------|-------------|------------------------------------------- | True | False | True | Set `moving_image_masks` applying | | | | `create_cfm` with `global_mask=False` |-------------|------------------|-------------|------------------------------------------- | True | False | False | args['moving_image_masks'] = moving_mask |-------------|------------------|-------------|------------------------------------------- | False | * | True | Set `moving_image_masks` applying | | | | `create_cfm` with `global_mask=True` |-------------|------------------|-------------|------------------------------------------- | False | * | False | No action """ # If a moving mask is provided... if isdefined(self.inputs.moving_mask): # If explicit masking is enabled... if self.inputs.explicit_masking: # Mask the moving image. # Do not use a moving mask during registration. args["moving_image"] = mask( self.inputs.moving_image, self.inputs.moving_mask, "moving_masked.nii.gz", ) # If explicit masking is disabled... else: # Use the moving mask during registration. # Do not mask the moving image. args["moving_image_masks"] = self.inputs.moving_mask # If a lesion mask is also provided... if isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: # [global mask - lesion mask] (if explicit masking is enabled) # [moving mask - lesion mask] (if explicit masking is disabled) # Use this as the moving mask. args["moving_image_masks"] = create_cfm( self.inputs.moving_mask, lesion_mask=self.inputs.lesion_mask, global_mask=self.inputs.explicit_masking, ) # If no moving mask is provided... # But a lesion mask *IS* provided... elif isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask - lesion mask] # Use this as the moving mask. args["moving_image_masks"] = create_cfm( self.inputs.moving_image, lesion_mask=self.inputs.lesion_mask, global_mask=True, ) """ Reference image handling - The following truth table maps out the intended action sequence. Future refactoring may more directly encode this. reference_mask and lesion_mask are files True = file False = None | reference_mask | explicit_masking | lesion_mask | action |----------------|------------------|-------------|---------------------------------------- | True | True | True | Update `fixed_image` after applying | | | | mask. | | | | Set `fixed_image_masks` applying | | | | `create_cfm` with `global_mask=True`. |----------------|------------------|-------------|---------------------------------------- | True | True | False | Update `fixed_image` after applying | | | | mask. |----------------|------------------|-------------|---------------------------------------- | True | False | True | Set `fixed_image_masks` applying | | | | `create_cfm` with `global_mask=False` |----------------|------------------|-------------|---------------------------------------- | True | False | False | args['fixed_image_masks'] = fixed_mask |----------------|------------------|-------------|---------------------------------------- | False | * | True | Set `fixed_image_masks` applying | | | | `create_cfm` with `global_mask=True` |----------------|------------------|-------------|---------------------------------------- | False | * | False | No action """ # If a reference image is provided... if isdefined(self.inputs.reference_image): # Use the reference image as the fixed image. args["fixed_image"] = self.inputs.reference_image self._reference_image = self.inputs.reference_image # If a reference mask is provided... if isdefined(self.inputs.reference_mask): # If explicit masking is enabled... if self.inputs.explicit_masking: # Mask the reference image. # Do not use a fixed mask during registration. args["fixed_image"] = mask( self.inputs.reference_image, self.inputs.reference_mask, "fixed_masked.nii.gz", ) # If a lesion mask is also provided... if isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask] # Use this as the fixed mask. args["fixed_image_masks"] = create_cfm( self.inputs.reference_mask, lesion_mask=None, global_mask=True, ) # If a reference mask is provided... # But explicit masking is disabled... else: # Use the reference mask as the fixed mask during registration. # Do not mask the fixed image. args["fixed_image_masks"] = self.inputs.reference_mask # If no reference mask is provided... # But a lesion mask *IS* provided ... elif isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask] # Use this as the fixed mask args["fixed_image_masks"] = create_cfm( self.inputs.reference_image, lesion_mask=None, global_mask=True) # If no reference image is provided, fall back to the default template. else: from ..utils.misc import get_template_specs # Raise an error if the user specifies an unsupported image orientation. if self.inputs.orientation == "LAS": raise NotImplementedError template_spec = (self.inputs.template_spec if isdefined(self.inputs.template_spec) else {}) default_resolution = { "precise": 1, "fast": 2, "testing": 2 }[self.inputs.flavor] # Set the template resolution. if isdefined(self.inputs.template_resolution): NIWORKFLOWS_LOG.warning( "The use of ``template_resolution`` is deprecated") template_spec["res"] = self.inputs.template_resolution template_spec["suffix"] = self.inputs.reference template_spec["desc"] = None ref_template, template_spec = get_template_specs( self.inputs.template, template_spec=template_spec, default_resolution=default_resolution, ) # Set reference image self._reference_image = ref_template if not op.isfile(self._reference_image): raise ValueError("""\ The registration reference must be an existing file, but path "%s" \ cannot be found.""" % ref_template) # Get the template specified by the user. ref_mask = get_template(self.inputs.template, desc="brain", suffix="mask", **template_spec) # Default is explicit masking disabled args["fixed_image"] = ref_template # Use the template mask as the fixed mask. args["fixed_image_masks"] = str(ref_mask) # Overwrite defaults if explicit masking if self.inputs.explicit_masking: # Mask the template image with the template mask. args["fixed_image"] = mask(ref_template, str(ref_mask), "fixed_masked.nii.gz") # Do not use a fixed mask during registration. args.pop("fixed_image_masks", None) # If a lesion mask is provided... if isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask] # Use this as the fixed mask. args["fixed_image_masks"] = create_cfm(str(ref_mask), lesion_mask=None, global_mask=True) return args
def init_enhance_and_skullstrip_bold_wf( brainmask_thresh=0.5, name="enhance_and_skullstrip_bold_wf", omp_nthreads=1, pre_mask=False, ): """ Enhance and run brain extraction on a BOLD EPI image. This workflow takes in a :abbr:`BOLD (blood-oxygen level-dependant)` :abbr:`fMRI (functional MRI)` average/summary (e.g., a reference image averaging non-steady-state timepoints), and sharpens the histogram with the application of the N4 algorithm for removing the :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal mask. Steps of this workflow are: 1. Calculate a tentative mask by registering (9-parameters) to *fMRIPrep*'s :abbr:`EPI (echo-planar imaging)` -*boldref* template, which is in MNI space. The tentative mask is obtained by resampling the MNI template's brainmask into *boldref*-space. 2. Binary dilation of the tentative mask with a sphere of 3mm diameter. 3. Run ANTs' ``N4BiasFieldCorrection`` on the input :abbr:`BOLD (blood-oxygen level-dependant)` average, using the mask generated in 1) instead of the internal Otsu thresholding. 4. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 5. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image with the latest mask calculated in 3), then use AFNI's ``3dUnifize`` to *standardize* the T2* contrast distribution. 6. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 7. Calculate a final mask as the intersection of 4) and 6). 8. Apply final mask on the enhanced reference. Step 1 can be skipped if the ``pre_mask`` argument is set to ``True`` and a tentative mask is passed in to the workflow throught the ``pre_mask`` Nipype input. Workflow graph .. workflow :: :graph2use: orig :simple_form: yes from niworkflows.func.util import init_enhance_and_skullstrip_bold_wf wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1) .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053 Parameters ---------- brainmask_thresh: :obj:`float` Lower threshold for the probabilistic brainmask to obtain the final binary mask (default: 0.5). name : str Name of workflow (default: ``enhance_and_skullstrip_bold_wf``) omp_nthreads : int number of threads available to parallel nodes pre_mask : bool Indicates whether the ``pre_mask`` input will be set (and thus, step 1 should be skipped). Inputs ------ in_file : str BOLD image (single volume) pre_mask : bool A tentative brain mask to initialize the workflow (requires ``pre_mask`` parameter set ``True``). Outputs ------- bias_corrected_file : str the ``in_file`` after `N4BiasFieldCorrection`_ skull_stripped_file : str the ``bias_corrected_file`` after skull-stripping mask_file : str mask of the skull-stripped input file out_report : str reportlet for the skull-stripping """ workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=["in_file", "pre_mask"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface( fields=["mask_file", "skull_stripped_file", "bias_corrected_file" ]), name="outputnode", ) # 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", ) # 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(dimension=3, copy_header=True, bspline_fitting_distance=200), shrink_factor=2, name="n4_correct", n_procs=1, ) n4_correct.inputs.rescale_intensities = True # Create a generous BET mask out of the bias-corrected EPI 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") # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( afni.Unifize( t2=True, outputtype="NIFTI_GZ", # Default -clfrac is 0.1, 0.4 was too conservative # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation) args="-clfrac 0.2 -rbt 18.3 65.0 90.0", out_file="uni.nii.gz", ), name="unifize", ) fixhdr_unifize = pe.Node(CopyXForm(), name="fixhdr_unifize", mem_gb=0.1) # Run ANFI's 3dAutomask to extract a refined brain mask skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype="NIFTI_GZ"), name="skullstrip_second_pass") fixhdr_skullstrip2 = pe.Node(CopyXForm(), name="fixhdr_skullstrip2", mem_gb=0.1) # Take intersection of both masks combine_masks = pe.Node(fsl.BinaryMaths(operation="mul"), name="combine_masks") # Compute masked brain apply_mask = pe.Node(fsl.ApplyMask(), name="apply_mask") if not pre_mask: from ..interfaces.nibabel import Binarize bold_template = get_template("MNI152NLin2009cAsym", resolution=2, desc="fMRIPrep", suffix="boldref") brain_mask = get_template("MNI152NLin2009cAsym", resolution=2, desc="brain", suffix="mask") # Initialize transforms with antsAI init_aff = pe.Node( AI( fixed_image=str(bold_template), fixed_image_mask=str(brain_mask), metric=("Mattes", 32, "Regular", 0.2), transform=("Affine", 0.1), search_factor=(20, 0.12), principal_axes=False, convergence=(10, 1e-6, 10), verbose=True, ), name="init_aff", n_procs=omp_nthreads, ) # Registration().version may be None if parseversion(Registration().version or "0.0.0") > Version("2.2.0"): init_aff.inputs.search_grid = (40, (0, 40, 40)) # Set up spatial normalization norm = pe.Node( Registration(from_file=pkgr_fn("niworkflows.data", "epi_atlasbased_brainmask.json")), name="norm", n_procs=omp_nthreads, ) norm.inputs.fixed_image = str(bold_template) map_brainmask = pe.Node( ApplyTransforms( interpolation="BSpline", float=True, # Use the higher resolution and probseg for numerical stability in rounding input_image=str( get_template( "MNI152NLin2009cAsym", resolution=1, label="brain", suffix="probseg", )), ), name="map_brainmask", ) binarize_mask = pe.Node(Binarize(thresh_low=brainmask_thresh), name="binarize_mask") # fmt: off workflow.connect([ (inputnode, init_aff, [("in_file", "moving_image")]), (inputnode, map_brainmask, [("in_file", "reference_image")]), (inputnode, norm, [("in_file", "moving_image")]), (init_aff, norm, [("output_transform", "initial_moving_transform") ]), (norm, map_brainmask, [ ("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")]), ]) # fmt: on else: # fmt: off workflow.connect([ (inputnode, pre_dilate, [("pre_mask", "in_file")]), ]) # 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", "mask_image")]), (inputnode, n4_correct, [("in_file", "input_image")]), (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", "mask_file")]), (skullstrip_first_pass, bet_mask, [("out_file", "in_file")]), (bet_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")]), (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, outputnode, [("out_file", "mask_file")]), (apply_mask, outputnode, [("out_file", "skull_stripped_file")]), (n4_correct, outputnode, [("output_image", "bias_corrected_file")]), ]) # fmt: on return workflow
def compute_iqms(name="ComputeIQMs"): """ Setup the workflow that actually computes the IQMs. .. workflow:: from mriqc.workflows.anatomical import compute_iqms from mriqc.testing import mock_config with mock_config(): wf = compute_iqms() """ from niworkflows.interfaces.bids import ReadSidecarJSON from ..interfaces.anatomical import Harmonize from .utils import _tofloat workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=[ "in_file", "in_ras", "brainmask", "airmask", "artmask", "headmask", "rotmask", "hatmask", "segmentation", "inu_corrected", "in_inu", "pvms", "metadata", "inverse_composite_transform", ]), name="inputnode", ) outputnode = pe.Node( niu.IdentityInterface(fields=["out_file", "noisefit"]), name="outputnode", ) # Extract metadata meta = pe.Node(ReadSidecarJSON(), name="metadata") # Add provenance addprov = pe.Node(AddProvenance(), name="provenance", run_without_submitting=True) # AFNI check smoothing fwhm_interface = get_fwhmx() fwhm = pe.Node(fwhm_interface, name="smoothness") # Harmonize homog = pe.Node(Harmonize(), name="harmonize") if config.workflow.species.lower() != "human": homog.inputs.erodemsk = False homog.inputs.thresh = 0.8 # Mortamet's QI2 getqi2 = pe.Node(ComputeQI2(), name="ComputeQI2") # Compute python-coded measures measures = pe.Node( StructuralQC(human=config.workflow.species.lower() == "human"), "measures") # Project MNI segmentation to T1 space invt = pe.MapNode( ants.ApplyTransforms(dimension=3, default_value=0, interpolation="Linear", float=True), iterfield=["input_image"], name="MNItpms2t1", ) if config.workflow.species.lower() == "human": invt.inputs.input_image = [ str(p) for p in get_template( config.workflow.template_id, suffix="probseg", resolution=1, label=["CSF", "GM", "WM"], ) ] else: invt.inputs.input_image = [ str(p) for p in get_template( config.workflow.template_id, suffix="probseg", label=["CSF", "GM", "WM"], ) ] datasink = pe.Node( IQMFileSink( out_dir=config.execution.output_dir, dataset=config.execution.dsname, ), name="datasink", run_without_submitting=True, ) def _getwm(inlist): return inlist[-1] # fmt: off workflow.connect([ (inputnode, meta, [("in_file", "in_file")]), (inputnode, datasink, [("in_file", "in_file"), (("in_file", _get_mod), "modality")]), (inputnode, addprov, [(("in_file", _get_mod), "modality")]), (meta, datasink, [("subject", "subject_id"), ("session", "session_id"), ("task", "task_id"), ("acquisition", "acq_id"), ("reconstruction", "rec_id"), ("run", "run_id"), ("out_dict", "metadata")]), (inputnode, addprov, [("in_file", "in_file"), ("airmask", "air_msk"), ("rotmask", "rot_msk")]), (inputnode, getqi2, [("in_ras", "in_file"), ("hatmask", "air_msk")]), (inputnode, homog, [("inu_corrected", "in_file"), (("pvms", _getwm), "wm_mask")]), (inputnode, measures, [("in_inu", "in_bias"), ("in_ras", "in_file"), ("airmask", "air_msk"), ("headmask", "head_msk"), ("artmask", "artifact_msk"), ("rotmask", "rot_msk"), ("segmentation", "in_segm"), ("pvms", "in_pvms")]), (inputnode, fwhm, [("in_ras", "in_file"), ("brainmask", "mask")]), (inputnode, invt, [("in_ras", "reference_image"), ("inverse_composite_transform", "transforms")]), (homog, measures, [("out_file", "in_noinu")]), (invt, measures, [("output_image", "mni_tpms")]), (fwhm, measures, [(("fwhm", _tofloat), "in_fwhm")]), (measures, datasink, [("out_qc", "root")]), (addprov, datasink, [("out_prov", "provenance")]), (getqi2, datasink, [("qi2", "qi_2")]), (getqi2, outputnode, [("out_file", "noisefit")]), (datasink, outputnode, [("out_file", "out_file")]), ]) # fmt: on return workflow
def init_brain_extraction_wf(name='brain_extraction_wf', in_template='OASIS30ANTs', use_float=True, normalization_quality='precise', omp_nthreads=None, mem_gb=3.0, bids_suffix='T1w', atropos_refine=True, atropos_use_random_seed=True, atropos_model=None, use_laplacian=True, bspline_fitting_distance=200): """ A Nipype implementation of the official ANTs' ``antsBrainExtraction.sh`` workflow (only for 3D images). The official workflow is built as follows (and this implementation follows the same organization): 1. Step 1 performs several clerical tasks (adding padding, calculating the Laplacian of inputs, affine initialization) and the core spatial normalization. 2. Maps the brain mask into target space using the normalization calculated in 1. 3. Superstep 1b: smart binarization of the brain mask 4. Superstep 6: apply ATROPOS and massage its outputs 5. Superstep 7: use results from 4 to refine the brain mask .. workflow:: :graph2use: orig :simple_form: yes from niworkflows.anat import init_brain_extraction_wf wf = init_brain_extraction_wf() **Parameters** in_template : str Name of the skull-stripping template ('OASIS30ANTs', 'NKI', or path). The brain template from which regions will be projected Anatomical template created using e.g. LPBA40 data set with ``buildtemplateparallel.sh`` in ANTs. The workflow will automatically search for a brain probability mask created using e.g. LPBA40 data set which have brain masks defined, and warped to anatomical template and averaged resulting in a probability image. use_float : bool Whether single precision should be used normalization_quality : str Use more precise or faster registration parameters (default: ``precise``, other possible values: ``testing``) omp_nthreads : int Maximum number of threads an individual process may use mem_gb : float Estimated peak memory consumption of the most hungry nodes in the workflow bids_suffix : str Sequence type of the first input image. For a list of acceptable values see https://bids-specification.readthedocs.io/en/latest/\ 04-modality-specific-files/01-magnetic-resonance-imaging-data.html#anatomy-imaging-data atropos_refine : bool Enables or disables the whole ATROPOS sub-workflow atropos_use_random_seed : bool Whether ATROPOS should generate a random seed based on the system's clock atropos_model : tuple or None Allows to specify a particular segmentation model, overwriting the defaults based on ``bids_suffix`` use_laplacian : bool Enables or disables alignment of the Laplacian as an additional criterion for image registration quality (default: True) bspline_fitting_distance : float The size of the b-spline mesh grid elements, in mm (default: 200) name : str, optional Workflow name (default: antsBrainExtraction) **Inputs** in_files List of input anatomical images to be brain-extracted, typically T1-weighted. If a list of anatomical images is provided, subsequently specified images are used during the segmentation process. However, only the first image is used in the registration of priors. Our suggestion would be to specify the T1w as the first image. in_mask (optional) Mask used for registration to limit the metric computation to a specific region. **Outputs** out_file Skull-stripped and :abbr:`INU (intensity non-uniformity)`-corrected ``in_files`` out_mask Calculated brain mask bias_corrected The ``in_files`` input images, after :abbr:`INU (intensity non-uniformity)` correction, before skull-stripping. bias_image The :abbr:`INU (intensity non-uniformity)` field estimated for each input in ``in_files`` out_segm Output segmentation by ATROPOS out_tpms Output :abbr:`TPMs (tissue probability maps)` by ATROPOS """ from templateflow.api import get as get_template wf = pe.Workflow(name) tpl_target_path = str( get_template(in_template, desc=None, resolution=1, suffix=bids_suffix)) # Get probabilistic brain mask if available tpl_mask_path = get_template( in_template, resolution=1, label='brain', suffix='probseg') or \ get_template(in_template, resolution=1, desc='brain', suffix='mask') if omp_nthreads is None or omp_nthreads < 1: omp_nthreads = cpu_count() inputnode = pe.Node(niu.IdentityInterface(fields=['in_files', 'in_mask']), name='inputnode') # Try to find a registration mask, set if available tpl_regmask_path = get_template( in_template, resolution=1, desc='BrainCerebellumExtraction', suffix='mask') if tpl_regmask_path: inputnode.inputs.in_mask = str(tpl_regmask_path) outputnode = pe.Node(niu.IdentityInterface( fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image', 'out_segm']), name='outputnode') trunc = pe.MapNode(ImageMath(operation='TruncateImageIntensity', op2='0.01 0.999 256'), name='truncate_images', iterfield=['op1']) inu_n4 = pe.MapNode( N4BiasFieldCorrection( dimension=3, save_bias=False, copy_header=True, n_iterations=[50] * 4, convergence_threshold=1e-7, shrink_factor=4, bspline_fitting_distance=bspline_fitting_distance), n_procs=omp_nthreads, name='inu_n4', iterfield=['input_image']) res_tmpl = pe.Node(ResampleImageBySpacing( out_spacing=(4, 4, 4), apply_smoothing=True), name='res_tmpl') res_tmpl.inputs.input_image = tpl_target_path res_target = pe.Node(ResampleImageBySpacing( out_spacing=(4, 4, 4), apply_smoothing=True), name='res_target') lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_tmpl') lap_tmpl.inputs.op1 = tpl_target_path lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_target') mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl') mrg_tmpl.inputs.in1 = tpl_target_path mrg_target = pe.Node(niu.Merge(2), name='mrg_target') # Initialize transforms with antsAI init_aff = pe.Node(AI( metric=('Mattes', 32, 'Regular', 0.25), transform=('Affine', 0.1), search_factor=(15, 0.1), principal_axes=False, convergence=(10, 1e-6, 10), verbose=True), name='init_aff', n_procs=omp_nthreads) if parseversion(Registration().version) > Version('2.2.0'): init_aff.inputs.search_grid = (40, (0, 40, 40)) # Set up spatial normalization settings_file = 'antsBrainExtraction_%s.json' if use_laplacian \ else 'antsBrainExtractionNoLaplacian_%s.json' norm = pe.Node(Registration(from_file=pkgr_fn( 'niworkflows.data', settings_file % normalization_quality)), name='norm', n_procs=omp_nthreads, mem_gb=mem_gb) norm.inputs.float = use_float fixed_mask_trait = 'fixed_image_mask' if parseversion(Registration().version) >= Version('2.2.0'): fixed_mask_trait += 's' map_brainmask = pe.Node( ApplyTransforms(interpolation='Gaussian', float=True), name='map_brainmask', mem_gb=1 ) map_brainmask.inputs.input_image = str(tpl_mask_path) thr_brainmask = pe.Node(ThresholdImage( dimension=3, th_low=0.5, th_high=1.0, inside_value=1, outside_value=0), name='thr_brainmask') # Morphological dilation, radius=2 dil_brainmask = pe.Node(ImageMath(operation='MD', op2='2'), name='dil_brainmask') # Get largest connected component get_brainmask = pe.Node(ImageMath(operation='GetLargestComponent'), name='get_brainmask') # Refine INU correction inu_n4_final = pe.MapNode( N4BiasFieldCorrection( dimension=3, save_bias=True, copy_header=True, n_iterations=[50] * 5, convergence_threshold=1e-7, shrink_factor=4, bspline_fitting_distance=bspline_fitting_distance), n_procs=omp_nthreads, name='inu_n4_final', iterfield=['input_image']) # Apply mask apply_mask = pe.MapNode(ApplyMask(), iterfield=['in_file'], name='apply_mask') wf.connect([ (inputnode, trunc, [('in_files', 'op1')]), (inputnode, inu_n4_final, [('in_files', 'input_image')]), (inputnode, init_aff, [('in_mask', 'fixed_image_mask')]), (inputnode, norm, [('in_mask', fixed_mask_trait)]), (inputnode, map_brainmask, [(('in_files', _pop), 'reference_image')]), (trunc, inu_n4, [('output_image', 'input_image')]), (inu_n4, res_target, [ (('output_image', _pop), 'input_image')]), (res_tmpl, init_aff, [('output_image', 'fixed_image')]), (res_target, init_aff, [('output_image', 'moving_image')]), (init_aff, norm, [('output_transform', 'initial_moving_transform')]), (norm, map_brainmask, [ ('reverse_transforms', 'transforms'), ('reverse_invert_flags', 'invert_transform_flags')]), (map_brainmask, thr_brainmask, [('output_image', 'input_image')]), (thr_brainmask, dil_brainmask, [('output_image', 'op1')]), (dil_brainmask, get_brainmask, [('output_image', 'op1')]), (inu_n4_final, apply_mask, [('output_image', 'in_file')]), (get_brainmask, apply_mask, [('output_image', 'mask_file')]), (get_brainmask, outputnode, [('output_image', 'out_mask')]), (apply_mask, outputnode, [('out_file', 'out_file')]), (inu_n4_final, outputnode, [('output_image', 'bias_corrected'), ('bias_image', 'bias_image')]), ]) if use_laplacian: lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_tmpl') lap_tmpl.inputs.op1 = tpl_target_path lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_target') mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl') mrg_tmpl.inputs.in1 = tpl_target_path mrg_target = pe.Node(niu.Merge(2), name='mrg_target') wf.connect([ (inu_n4, lap_target, [ (('output_image', _pop), 'op1')]), (lap_tmpl, mrg_tmpl, [('output_image', 'in2')]), (inu_n4, mrg_target, [('output_image', 'in1')]), (lap_target, mrg_target, [('output_image', 'in2')]), (mrg_tmpl, norm, [('out', 'fixed_image')]), (mrg_target, norm, [('out', 'moving_image')]), ]) else: norm.inputs.fixed_image = tpl_target_path wf.connect([ (inu_n4, norm, [ (('output_image', _pop), 'moving_image')]), ]) if atropos_refine: atropos_model = atropos_model or list(ATROPOS_MODELS[bids_suffix].values()) atropos_wf = init_atropos_wf( use_random_seed=atropos_use_random_seed, omp_nthreads=omp_nthreads, mem_gb=mem_gb, in_segmentation_model=atropos_model, ) sel_wm = pe.Node(niu.Select(index=atropos_model[-1] - 1), name='sel_wm', run_without_submitting=True) wf.disconnect([ (get_brainmask, outputnode, [('output_image', 'out_mask')]), (get_brainmask, apply_mask, [('output_image', 'mask_file')]), ]) wf.connect([ (inu_n4, atropos_wf, [ ('output_image', 'inputnode.in_files')]), (thr_brainmask, atropos_wf, [ ('output_image', 'inputnode.in_mask')]), (get_brainmask, atropos_wf, [ ('output_image', 'inputnode.in_mask_dilated')]), (atropos_wf, sel_wm, [('outputnode.out_tpms', 'inlist')]), (sel_wm, inu_n4_final, [('out', 'weight_image')]), (atropos_wf, outputnode, [ ('outputnode.out_mask', 'out_mask')]), (atropos_wf, apply_mask, [ ('outputnode.out_mask', 'mask_file')]), (atropos_wf, outputnode, [ ('outputnode.out_segm', 'out_segm'), ('outputnode.out_tpms', 'out_tpms')]) ]) return wf
def airmsk_wf(name="AirMaskWorkflow"): """ Implements the Step 1 of [Mortamet2009]_. .. workflow:: from mriqc.testing import mock_config from mriqc.workflows.anatomical import airmsk_wf with mock_config(): wf = airmsk_wf() """ workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=[ "in_file", "in_mask", "head_mask", "inverse_composite_transform", ]), name="inputnode", ) outputnode = pe.Node( niu.IdentityInterface( fields=["hat_mask", "air_mask", "art_mask", "rot_mask"]), name="outputnode", ) rotmsk = pe.Node(RotationMask(), name="RotationMask") invt = pe.Node( ants.ApplyTransforms( dimension=3, default_value=0, interpolation="MultiLabel", float=True, ), name="invert_xfm", ) if config.workflow.species.lower() == "human": invt.inputs.input_image = str( get_template(config.workflow.template_id, resolution=1, desc="head", suffix="mask")) else: # TODO: provide options for other populations invt.inputs.input_image = str( get_template(config.workflow.template_id, desc="brain", suffix="mask")[0]) qi1 = pe.Node(ArtifactMask(), name="ArtifactMask") # fmt: off workflow.connect([(inputnode, rotmsk, [("in_file", "in_file")]), (inputnode, qi1, [("in_file", "in_file"), ("head_mask", "head_mask")]), (rotmsk, qi1, [("out_file", "rot_mask")]), (inputnode, invt, [("in_mask", "reference_image"), ("inverse_composite_transform", "transforms")]), (invt, qi1, [("output_image", "nasion_post_mask")]), (qi1, outputnode, [("out_hat_msk", "hat_mask"), ("out_air_msk", "air_mask"), ("out_art_msk", "art_mask")]), (rotmsk, outputnode, [("out_file", "rot_mask")])]) # fmt: on return workflow
def init_carpetplot_wf(mem_gb, metadata, cifti_output, name="bold_carpet_wf"): """ Build a workflow to generate *carpet* plots. Resamples the MNI parcellation (ad-hoc parcellation derived from the Harvard-Oxford template and others). Parameters ---------- mem_gb : :obj:`float` Size of BOLD file in GB - please note that this size should be calculated after resamplings that may extend the FoV metadata : :obj:`dict` BIDS metadata for BOLD file name : :obj:`str` Name of workflow (default: ``bold_carpet_wf``) Inputs ------ bold BOLD image, after the prescribed corrections (STC, HMC and SDC) when available. bold_mask BOLD series mask confounds_file TSV of all aggregated confounds t1_bold_xform Affine matrix that maps the T1w space into alignment with the native BOLD space std2anat_xfm ANTs-compatible affine-and-warp transform file cifti_bold BOLD image in CIFTI format, to be used in place of volumetric BOLD Outputs ------- out_carpetplot Path of the generated SVG file """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.interfaces.fixes import FixHeaderApplyTransforms as ApplyTransforms inputnode = pe.Node(niu.IdentityInterface(fields=[ 'bold', 'bold_mask', 'confounds_file', 't1_bold_xform', 'std2anat_xfm', 'cifti_bold' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['out_carpetplot']), name='outputnode') # List transforms mrg_xfms = pe.Node(niu.Merge(2), name='mrg_xfms') # Warp segmentation into EPI space resample_parc = pe.Node(ApplyTransforms( dimension=3, input_image=str( get_template('MNI152NLin2009cAsym', resolution=1, desc='carpet', suffix='dseg', extension=['.nii', '.nii.gz'])), interpolation='MultiLabel'), name='resample_parc') # Carpetplot and confounds plot conf_plot = pe.Node(FMRISummary(tr=metadata['RepetitionTime'], confounds_list=[ ('global_signal', None, 'GS'), ('csf', None, 'GSCSF'), ('white_matter', None, 'GSWM'), ('std_dvars', None, 'DVARS'), ('framewise_displacement', 'mm', 'FD') ]), name='conf_plot', mem_gb=mem_gb) ds_report_bold_conf = pe.Node(DerivativesDataSink( desc='carpetplot', datatype="figures", extension="svg", dismiss_entities=("echo", )), name='ds_report_bold_conf', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) workflow = Workflow(name=name) # no need for segmentations if using CIFTI if cifti_output: workflow.connect(inputnode, 'cifti_bold', conf_plot, 'in_func') else: workflow.connect([ (inputnode, mrg_xfms, [('t1_bold_xform', 'in1'), ('std2anat_xfm', 'in2')]), (inputnode, resample_parc, [('bold_mask', 'reference_image')]), (mrg_xfms, resample_parc, [('out', 'transforms')]), # Carpetplot (inputnode, conf_plot, [('bold', 'in_func'), ('bold_mask', 'in_mask')]), (resample_parc, conf_plot, [('output_image', 'in_segm')]) ]) workflow.connect([ (inputnode, conf_plot, [('confounds_file', 'confounds_file')]), (conf_plot, ds_report_bold_conf, [('out_file', 'in_file')]), (conf_plot, outputnode, [('out_file', 'out_carpetplot')]), ]) return workflow
def init_cbfplot_wf(mem_gb, metadata, omp_nthreads, name='cbf_plot'): workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=[ 'cbf', 'cbf_ts', 'score_ts', 'score', 'scrub', 'asl_ref', 'basil', 'pvc', 'asl_mask', 't1_asl_xform', 'std2anat_xfm', 'confounds_file', 'scoreindex' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 'cbf_carpetplot', 'score_carpetplot', 'cbf_summary_plot', 'cbf_summary_plot', 'score_summary_plot', 'scrub_summary_plot', 'basil_summary_plot', 'pvc_summary_plot' ]), name='outputnode') mrg_xfms = pe.Node(niu.Merge(2), name='mrg_xfms') from templateflow.api import get as get_template seg = get_template('MNI152NLin2009cAsym', resolution=1, desc='carpet', suffix='dseg') print(seg) resample_parc = pe.Node(ApplyTransforms(float=True, input_image=str(seg), dimension=3, default_value=0, interpolation='MultiLabel'), name='resample_parc') cbftssummary = pe.Node(CBFtsSummary(tr=metadata['RepetitionTime']), name='cbf_ts_summary', mem_gb=0.2) cbfsummary = pe.Node(CBFSummary(label='cbf'), name='cbf_summary', mem_gb=0.2) scoresummary = pe.Node(CBFSummary(label='score'), name='score_summary', mem_gb=0.2) scrubsummary = pe.Node(CBFSummary(label='scrub'), name='scrub_summary', mem_gb=0.2) basilsummary = pe.Node(CBFSummary(label='basil'), name='basil_summary', mem_gb=0.2) pvcsummary = pe.Node(CBFSummary(label='pvc'), name='pvc_summary', mem_gb=0.2) ds_report_cbftsplot = pe.Node(DerivativesDataSink(desc='cbftsplot', datatype="figures", keep_dtype=True), name='ds_report_cbftsplot', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) ds_report_cbfplot = pe.Node(DerivativesDataSink(desc='cbfplot', datatype="figures", keep_dtype=True), name='ds_report_cbfplot', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) ds_report_scoreplot = pe.Node(DerivativesDataSink(desc='scoreplot', datatype="figures", keep_dtype=True), name='ds_report_scoreplot', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) ds_report_scrubplot = pe.Node(DerivativesDataSink(desc='scrubplot', datatype="figures", keep_dtype=True), name='ds_report_scrubplot', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) ds_report_basilplot = pe.Node(DerivativesDataSink(desc='basilplot', datatype="figures", keep_dtype=True), name='ds_report_basilplot', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) ds_report_pvcplot = pe.Node(DerivativesDataSink(desc='pvcplot', datatype="figures", keep_dtype=True), name='ds_report_pvcplot', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) workflow.connect([ (inputnode, mrg_xfms, [('t1_asl_xform', 'in1'), ('std2anat_xfm', 'in2')]), (inputnode, resample_parc, [('asl_mask', 'reference_image')]), (mrg_xfms, resample_parc, [('out', 'transforms')]), (resample_parc, cbftssummary, [('output_image', 'seg_file')]), (inputnode, cbftssummary, [('cbf_ts', 'cbf_ts'), ('confounds_file', 'conf_file'), ('scoreindex', 'score_file')]), (cbftssummary, ds_report_cbftsplot, [('out_file', 'in_file')]), (cbftssummary, outputnode, [('out_file', 'cbf_carpetplot')]), (inputnode, cbfsummary, [('cbf', 'cbf'), ('asl_ref', 'ref_vol')]), (cbfsummary, ds_report_cbfplot, [('out_file', 'in_file')]), (cbfsummary, outputnode, [('out_file', 'cbf_summary_plot')]), (inputnode, scoresummary, [('score', 'cbf'), ('asl_ref', 'ref_vol')]), (scoresummary, ds_report_scoreplot, [('out_file', 'in_file')]), (scoresummary, outputnode, [('out_file', 'score_summary_plot')]), (inputnode, scrubsummary, [('scrub', 'cbf'), ('asl_ref', 'ref_vol')]), (scrubsummary, ds_report_scrubplot, [('out_file', 'in_file')]), (scrubsummary, outputnode, [('out_file', 'scrub_summary_plot')]), (inputnode, basilsummary, [('basil', 'cbf'), ('asl_ref', 'ref_vol')]), (basilsummary, ds_report_basilplot, [('out_file', 'in_file')]), (basilsummary, outputnode, [('out_file', 'basil_summary_plot')]), (inputnode, pvcsummary, [('pvc', 'cbf'), ('asl_ref', 'ref_vol')]), (pvcsummary, ds_report_pvcplot, [('out_file', 'in_file')]), (pvcsummary, outputnode, [('out_file', 'pvc_summary_plot')]), ]) return workflow
def reference(): return str(get_template('MNI152Lin', resolution=2, desc=None, suffix='T1w'))
def init_brain_extraction_wf(name='brain_extraction_wf', in_template='OASIS30ANTs', template_spec=None, use_float=True, normalization_quality='precise', omp_nthreads=None, mem_gb=3.0, bids_suffix='T1w', atropos_refine=True, atropos_use_random_seed=True, atropos_model=None, use_laplacian=True, bspline_fitting_distance=200): """ Build a workflow for atlas-based brain extraction on anatomical MRI data. A Nipype implementation of the official ANTs' ``antsBrainExtraction.sh`` workflow (only for 3D images). The official workflow is built as follows (and this implementation follows the same organization): 1. Step 1 performs several clerical tasks (adding padding, calculating the Laplacian of inputs, affine initialization) and the core spatial normalization. 2. Maps the brain mask into target space using the normalization calculated in 1. 3. Superstep 1b: smart binarization of the brain mask 4. Superstep 6: apply ATROPOS and massage its outputs 5. Superstep 7: use results from 4 to refine the brain mask Workflow Graph .. workflow:: :graph2use: orig :simple_form: yes from niworkflows.anat.ants import init_brain_extraction_wf wf = init_brain_extraction_wf() Parameters ---------- in_template : str Name of the skull-stripping template ('OASIS30ANTs', 'NKI', or path). The brain template from which regions will be projected Anatomical template created using e.g. LPBA40 data set with ``buildtemplateparallel.sh`` in ANTs. The workflow will automatically search for a brain probability mask created using e.g. LPBA40 data set which have brain masks defined, and warped to anatomical template and averaged resulting in a probability image. use_float : bool Whether single precision should be used normalization_quality : str Use more precise or faster registration parameters (default: ``precise``, other possible values: ``testing``) omp_nthreads : int Maximum number of threads an individual process may use mem_gb : float Estimated peak memory consumption of the most hungry nodes in the workflow bids_suffix : str Sequence type of the first input image. For a list of acceptable values see https://bids-specification.readthedocs.io/en/latest/\ 04-modality-specific-files/01-magnetic-resonance-imaging-data.html#anatomy-imaging-data atropos_refine : bool Enables or disables the whole ATROPOS sub-workflow atropos_use_random_seed : bool Whether ATROPOS should generate a random seed based on the system's clock atropos_model : tuple or None Allows to specify a particular segmentation model, overwriting the defaults based on ``bids_suffix`` use_laplacian : bool Enables or disables alignment of the Laplacian as an additional criterion for image registration quality (default: True) bspline_fitting_distance : float The size of the b-spline mesh grid elements, in mm (default: 200) name : str, optional Workflow name (default: antsBrainExtraction) Inputs ------ in_files : list List of input anatomical images to be brain-extracted, typically T1-weighted. If a list of anatomical images is provided, subsequently specified images are used during the segmentation process. However, only the first image is used in the registration of priors. Our suggestion would be to specify the T1w as the first image. in_mask : list, optional Mask used for registration to limit the metric computation to a specific region. Outputs ------- out_file : str Skull-stripped and :abbr:`INU (intensity non-uniformity)`-corrected ``in_files`` out_mask : str Calculated brain mask bias_corrected : str The ``in_files`` input images, after :abbr:`INU (intensity non-uniformity)` correction, before skull-stripping. bias_image : str The :abbr:`INU (intensity non-uniformity)` field estimated for each input in ``in_files`` out_segm : str Output segmentation by ATROPOS out_tpms : str Output :abbr:`TPMs (tissue probability maps)` by ATROPOS """ from templateflow.api import get as get_template wf = pe.Workflow(name) template_spec = template_spec or {} # suffix passed via spec takes precedence template_spec['suffix'] = template_spec.get('suffix', bids_suffix) tpl_target_path, common_spec = get_template_specs( in_template, template_spec=template_spec) # Get probabilistic brain mask if available tpl_mask_path = get_template( in_template, label='brain', suffix='probseg', **common_spec) or \ get_template(in_template, desc='brain', suffix='mask', **common_spec) if omp_nthreads is None or omp_nthreads < 1: omp_nthreads = cpu_count() inputnode = pe.Node(niu.IdentityInterface(fields=['in_files', 'in_mask']), name='inputnode') # Try to find a registration mask, set if available tpl_regmask_path = get_template( in_template, desc='BrainCerebellumExtraction', suffix='mask', **common_spec) if tpl_regmask_path: inputnode.inputs.in_mask = str(tpl_regmask_path) outputnode = pe.Node(niu.IdentityInterface( fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image', 'out_segm', 'out_tpms']), name='outputnode') copy_xform = pe.Node(CopyXForm( fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image']), name='copy_xform', run_without_submitting=True) trunc = pe.MapNode(ImageMath(operation='TruncateImageIntensity', op2='0.01 0.999 256'), name='truncate_images', iterfield=['op1']) inu_n4 = pe.MapNode( N4BiasFieldCorrection( dimension=3, save_bias=False, copy_header=True, n_iterations=[50] * 4, convergence_threshold=1e-7, shrink_factor=4, bspline_fitting_distance=bspline_fitting_distance), n_procs=omp_nthreads, name='inu_n4', iterfield=['input_image']) res_tmpl = pe.Node(ResampleImageBySpacing( out_spacing=(4, 4, 4), apply_smoothing=True), name='res_tmpl') res_tmpl.inputs.input_image = tpl_target_path res_target = pe.Node(ResampleImageBySpacing( out_spacing=(4, 4, 4), apply_smoothing=True), name='res_target') lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_tmpl') lap_tmpl.inputs.op1 = tpl_target_path lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_target') mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl') mrg_tmpl.inputs.in1 = tpl_target_path mrg_target = pe.Node(niu.Merge(2), name='mrg_target') # Initialize transforms with antsAI init_aff = pe.Node(AI( metric=('Mattes', 32, 'Regular', 0.25), transform=('Affine', 0.1), search_factor=(15, 0.1), principal_axes=False, convergence=(10, 1e-6, 10), verbose=True), name='init_aff', n_procs=omp_nthreads) # Tolerate missing ANTs at construction time _ants_version = Registration().version if _ants_version and parseversion(_ants_version) >= Version('2.3.0'): init_aff.inputs.search_grid = (40, (0, 40, 40)) # Set up spatial normalization settings_file = 'antsBrainExtraction_%s.json' if use_laplacian \ else 'antsBrainExtractionNoLaplacian_%s.json' norm = pe.Node(Registration(from_file=pkgr_fn( 'niworkflows.data', settings_file % normalization_quality)), name='norm', n_procs=omp_nthreads, mem_gb=mem_gb) norm.inputs.float = use_float fixed_mask_trait = 'fixed_image_mask' if _ants_version and parseversion(_ants_version) >= Version('2.2.0'): fixed_mask_trait += 's' map_brainmask = pe.Node( ApplyTransforms(interpolation='Gaussian', float=True), name='map_brainmask', mem_gb=1 ) map_brainmask.inputs.input_image = str(tpl_mask_path) thr_brainmask = pe.Node(ThresholdImage( dimension=3, th_low=0.5, th_high=1.0, inside_value=1, outside_value=0), name='thr_brainmask') # Morphological dilation, radius=2 dil_brainmask = pe.Node(ImageMath(operation='MD', op2='2'), name='dil_brainmask') # Get largest connected component get_brainmask = pe.Node(ImageMath(operation='GetLargestComponent'), name='get_brainmask') # Refine INU correction inu_n4_final = pe.MapNode( N4BiasFieldCorrection( dimension=3, save_bias=True, copy_header=True, n_iterations=[50] * 5, convergence_threshold=1e-7, shrink_factor=4, bspline_fitting_distance=bspline_fitting_distance), n_procs=omp_nthreads, name='inu_n4_final', iterfield=['input_image']) if _ants_version and parseversion(_ants_version) >= Version('2.1.0'): inu_n4_final.inputs.rescale_intensities = True else: warn("""\ Found ANTs version %s, which is too old. Please consider upgrading to 2.1.0 or \ greater so that the --rescale-intensities option is available with \ N4BiasFieldCorrection.""" % _ants_version, DeprecationWarning) # Apply mask apply_mask = pe.MapNode(ApplyMask(), iterfield=['in_file'], name='apply_mask') wf.connect([ (inputnode, trunc, [('in_files', 'op1')]), (inputnode, copy_xform, [(('in_files', _pop), 'hdr_file')]), (inputnode, inu_n4_final, [('in_files', 'input_image')]), (inputnode, init_aff, [('in_mask', 'fixed_image_mask')]), (inputnode, norm, [('in_mask', fixed_mask_trait)]), (inputnode, map_brainmask, [(('in_files', _pop), 'reference_image')]), (trunc, inu_n4, [('output_image', 'input_image')]), (inu_n4, res_target, [ (('output_image', _pop), 'input_image')]), (res_tmpl, init_aff, [('output_image', 'fixed_image')]), (res_target, init_aff, [('output_image', 'moving_image')]), (init_aff, norm, [('output_transform', 'initial_moving_transform')]), (norm, map_brainmask, [ ('reverse_transforms', 'transforms'), ('reverse_invert_flags', 'invert_transform_flags')]), (map_brainmask, thr_brainmask, [('output_image', 'input_image')]), (thr_brainmask, dil_brainmask, [('output_image', 'op1')]), (dil_brainmask, get_brainmask, [('output_image', 'op1')]), (inu_n4_final, apply_mask, [('output_image', 'in_file')]), (get_brainmask, apply_mask, [('output_image', 'mask_file')]), (get_brainmask, copy_xform, [('output_image', 'out_mask')]), (apply_mask, copy_xform, [('out_file', 'out_file')]), (inu_n4_final, copy_xform, [('output_image', 'bias_corrected'), ('bias_image', 'bias_image')]), (copy_xform, outputnode, [ ('out_file', 'out_file'), ('out_mask', 'out_mask'), ('bias_corrected', 'bias_corrected'), ('bias_image', 'bias_image')]), ]) if use_laplacian: lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_tmpl') lap_tmpl.inputs.op1 = tpl_target_path lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), name='lap_target') mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl') mrg_tmpl.inputs.in1 = tpl_target_path mrg_target = pe.Node(niu.Merge(2), name='mrg_target') wf.connect([ (inu_n4, lap_target, [ (('output_image', _pop), 'op1')]), (lap_tmpl, mrg_tmpl, [('output_image', 'in2')]), (inu_n4, mrg_target, [('output_image', 'in1')]), (lap_target, mrg_target, [('output_image', 'in2')]), (mrg_tmpl, norm, [('out', 'fixed_image')]), (mrg_target, norm, [('out', 'moving_image')]), ]) else: norm.inputs.fixed_image = tpl_target_path wf.connect([ (inu_n4, norm, [ (('output_image', _pop), 'moving_image')]), ]) if atropos_refine: atropos_model = atropos_model or list(ATROPOS_MODELS[bids_suffix].values()) atropos_wf = init_atropos_wf( use_random_seed=atropos_use_random_seed, omp_nthreads=omp_nthreads, mem_gb=mem_gb, in_segmentation_model=atropos_model, ) sel_wm = pe.Node(niu.Select(index=atropos_model[-1] - 1), name='sel_wm', run_without_submitting=True) wf.disconnect([ (get_brainmask, apply_mask, [('output_image', 'mask_file')]), (copy_xform, outputnode, [('out_mask', 'out_mask')]), ]) wf.connect([ (inu_n4, atropos_wf, [ ('output_image', 'inputnode.in_files')]), (thr_brainmask, atropos_wf, [ ('output_image', 'inputnode.in_mask')]), (get_brainmask, atropos_wf, [ ('output_image', 'inputnode.in_mask_dilated')]), (atropos_wf, sel_wm, [('outputnode.out_tpms', 'inlist')]), (sel_wm, inu_n4_final, [('out', 'weight_image')]), (atropos_wf, apply_mask, [ ('outputnode.out_mask', 'mask_file')]), (atropos_wf, outputnode, [ ('outputnode.out_mask', 'out_mask'), ('outputnode.out_segm', 'out_segm'), ('outputnode.out_tpms', 'out_tpms')]), ]) return wf
def compute_iqms(settings, modality='T1w', name='ComputeIQMs'): """ Workflow that actually computes the IQMs .. workflow:: from mriqc.workflows.anatomical import compute_iqms wf = compute_iqms(settings={'output_dir': 'out'}) """ from .utils import _tofloat from ..interfaces.anatomical import Harmonize workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=[ 'in_file', 'in_ras', 'brainmask', 'airmask', 'artmask', 'headmask', 'rotmask', 'hatmask', 'segmentation', 'inu_corrected', 'in_inu', 'pvms', 'metadata', 'inverse_composite_transform' ]), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['out_file', 'noisefit']), name='outputnode') # Extract metadata meta = pe.Node(ReadSidecarJSON(), name='metadata') # Add provenance addprov = pe.Node(niu.Function(function=_add_provenance), name='provenance') addprov.inputs.settings = { 'testing': settings.get('testing', False), 'webapi_url': settings.get('webapi_url'), 'webapi_port': settings.get('webapi_port') } # AFNI check smoothing fwhm_interface = get_fwhmx() fwhm = pe.Node(fwhm_interface, name='smoothness') # Harmonize homog = pe.Node(Harmonize(), name='harmonize') # Mortamet's QI2 getqi2 = pe.Node(ComputeQI2(), name='ComputeQI2') # Compute python-coded measures measures = pe.Node(StructuralQC(), 'measures') # Project MNI segmentation to T1 space invt = pe.MapNode(ants.ApplyTransforms(dimension=3, default_value=0, interpolation='Linear', float=True), iterfield=['input_image'], name='MNItpms2t1') invt.inputs.input_image = [ str(p) for p in get_template('MNI152NLin2009cAsym', suffix='probseg', resolution=1, label=['CSF', 'GM', 'WM']) ] datasink = pe.Node(IQMFileSink(modality=modality, out_dir=str(settings['output_dir']), dataset=settings.get( 'dataset_name', 'unknown')), name='datasink', run_without_submitting=True) datasink.inputs.modality = modality def _getwm(inlist): return inlist[-1] workflow.connect([ (inputnode, meta, [('in_file', 'in_file')]), (inputnode, datasink, [('in_file', 'in_file')]), (meta, datasink, [('subject', 'subject_id'), ('session', 'session_id'), ('task', 'task_id'), ('acquisition', 'acq_id'), ('reconstruction', 'rec_id'), ('run', 'run_id'), ('out_dict', 'metadata')]), (inputnode, addprov, [('in_file', 'in_file'), ('airmask', 'air_msk'), ('rotmask', 'rot_msk')]), (inputnode, getqi2, [('in_ras', 'in_file'), ('hatmask', 'air_msk')]), (inputnode, homog, [('inu_corrected', 'in_file'), (('pvms', _getwm), 'wm_mask')]), (inputnode, measures, [('in_inu', 'in_bias'), ('in_ras', 'in_file'), ('airmask', 'air_msk'), ('headmask', 'head_msk'), ('artmask', 'artifact_msk'), ('rotmask', 'rot_msk'), ('segmentation', 'in_segm'), ('pvms', 'in_pvms')]), (inputnode, fwhm, [('in_ras', 'in_file'), ('brainmask', 'mask')]), (inputnode, invt, [('in_ras', 'reference_image'), ('inverse_composite_transform', 'transforms')]), (homog, measures, [('out_file', 'in_noinu')]), (invt, measures, [('output_image', 'mni_tpms')]), (fwhm, measures, [(('fwhm', _tofloat), 'in_fwhm')]), (measures, datasink, [('out_qc', 'root')]), (addprov, datasink, [('out', 'provenance')]), (getqi2, datasink, [('qi2', 'qi_2')]), (getqi2, outputnode, [('out_file', 'noisefit')]), (datasink, outputnode, [('out_file', 'out_file')]), ]) return workflow
def init_ica_aroma_components_wf(workdir=None, name="ica_aroma_components_wf", memcalc=MemoryCalculator()): """ """ workflow = pe.Workflow(name=name) strfields = ["bold_file", "bold_mask", "itk_bold_to_t1", "out_warp"] inputnode = pe.Node(Exec(fieldtpls=[ ("tags", None), ("anat2std_xfm", None), *[(field, "firststr") for field in strfields], ("bold_split", None), ("repetition_time", None), ("skip_vols", None), ("movpar_file", None), ("xforms", None), ("std_dseg", "ravel"), ]), name="inputnode", run_without_submitting=True) outputnode = pe.Node( niu.IdentityInterface(fields=[ "aroma_noise_ics", "melodic_mix", "aroma_metadata", "aromavals" ]), name="outputnode", ) # make_resultdicts = pe.Node(MakeResultdicts(reportkeys=["ica_aroma"]), name="make_resultdicts", run_without_submitting=True) workflow.connect(inputnode, "tags", make_resultdicts, "tags") # resultdict_datasink = pe.Node(ResultdictDatasink(base_directory=workdir), name="resultdict_datasink", run_without_submitting=True) workflow.connect(make_resultdicts, "resultdicts", resultdict_datasink, "indicts") # mergexfm = pe.Node(niu.Merge(numinputs=2), name="mergexfm", run_without_submitting=True) workflow.connect(inputnode, "anat2std_xfm", mergexfm, "in1") mergexfm.inputs.in2 = getresource( f"tpl_MNI152NLin6Asym_from_{constants.reference_space}_mode_image_xfm.h5" ) compxfm = pe.Node( ApplyTransforms( dimension=3, print_out_composite_warp_file=True, output_image="ants_t1_to_mniComposite.nii.gz", ), name="compxfm", ) compxfm.inputs.reference_image = firststr( get_template("MNI152NLin6Asym", resolution=1, suffix="T1w")) workflow.connect(mergexfm, "out", compxfm, "transforms") compxfmlist = pe.Node(niu.Merge(1), name="compxfmlist", run_without_submitting=True) workflow.connect(compxfm, "output_image", compxfmlist, "in1") # bold_std_trans_wf = init_bold_std_trans_wf( freesurfer=False, mem_gb=memcalc.series_std_gb, omp_nthreads=config.nipype.omp_nthreads, spaces=spaces, name="bold_std_trans_wf", use_compression=not config.execution.low_mem, ) bold_std_trans_wf_inputnode = bold_std_trans_wf.get_node("inputnode") bold_std_trans_wf_inputnode.inputs.templates = ["MNI152NLin6Asym"] workflow.connect(compxfmlist, "out", bold_std_trans_wf, "inputnode.anat2std_xfm") workflow.connect(inputnode, "bold_file", bold_std_trans_wf, "inputnode.name_source") workflow.connect(inputnode, "bold_split", bold_std_trans_wf, "inputnode.bold_split") workflow.connect(inputnode, "xforms", bold_std_trans_wf, "inputnode.hmc_xforms") workflow.connect(inputnode, "itk_bold_to_t1", bold_std_trans_wf, "inputnode.itk_bold_to_t1") workflow.connect(inputnode, "bold_mask", bold_std_trans_wf, "inputnode.bold_mask") workflow.connect(inputnode, "out_warp", bold_std_trans_wf, "inputnode.fieldwarp") # ica_aroma_wf = init_ica_aroma_wf( mem_gb=memcalc.series_std_gb, metadata={"RepetitionTime": np.nan}, omp_nthreads=config.nipype.omp_nthreads, err_on_aroma_warn=config.workflow.aroma_err_on_warn, aroma_melodic_dim=config.workflow.aroma_melodic_dim, name="ica_aroma_wf", ) ica_aroma_wf.get_node("ica_aroma").inputs.denoise_type = "no" add_nonsteady = ica_aroma_wf.get_node("add_nonsteady") ds_report_ica_aroma = ica_aroma_wf.get_node("ds_report_ica_aroma") ica_aroma_wf.remove_nodes([add_nonsteady, ds_report_ica_aroma]) workflow.connect(inputnode, "repetition_time", ica_aroma_wf, "melodic.tr_sec") workflow.connect(inputnode, "repetition_time", ica_aroma_wf, "ica_aroma.TR") workflow.connect(inputnode, "movpar_file", ica_aroma_wf, "inputnode.movpar_file") workflow.connect(inputnode, "skip_vols", ica_aroma_wf, "inputnode.skip_vols") workflow.connect(bold_std_trans_wf, "outputnode.bold_std", ica_aroma_wf, "inputnode.bold_std") workflow.connect(bold_std_trans_wf, "outputnode.bold_mask_std", ica_aroma_wf, "inputnode.bold_mask_std") workflow.connect( bold_std_trans_wf, "outputnode.spatial_reference", ica_aroma_wf, "inputnode.spatial_reference", ) workflow.connect(ica_aroma_wf, "outputnode.aroma_noise_ics", outputnode, "aroma_noise_ics") workflow.connect(ica_aroma_wf, "outputnode.melodic_mix", outputnode, "melodic_mix") workflow.connect(ica_aroma_wf, "outputnode.aroma_metadata", outputnode, "aroma_metadata") workflow.connect(ica_aroma_wf, "ica_aroma.out_report", make_resultdicts, "ica_aroma") return workflow
def _get_ants_args(self): args = {'moving_image': self.inputs.moving_image, 'num_threads': self.inputs.num_threads, 'float': self.inputs.float, 'terminal_output': 'file', 'write_composite_transform': True, 'initial_moving_transform': self.inputs.initial_moving_transform} """ Moving image handling - The following truth table maps out the intended action sequence. Future refactoring may more directly encode this. moving_mask and lesion_mask are files True = file False = None | moving_mask | explicit_masking | lesion_mask | action |-------------|------------------|-------------|------------------------------------------- | True | True | True | Update `moving_image` after applying | | | | mask. | | | | Set `moving_image_masks` applying | | | | `create_cfm` with `global_mask=True`. |-------------|------------------|-------------|------------------------------------------- | True | True | False | Update `moving_image` after applying | | | | mask. |-------------|------------------|-------------|------------------------------------------- | True | False | True | Set `moving_image_masks` applying | | | | `create_cfm` with `global_mask=False` |-------------|------------------|-------------|------------------------------------------- | True | False | False | args['moving_image_masks'] = moving_mask |-------------|------------------|-------------|------------------------------------------- | False | * | True | Set `moving_image_masks` applying | | | | `create_cfm` with `global_mask=True` |-------------|------------------|-------------|------------------------------------------- | False | * | False | No action """ # If a moving mask is provided... if isdefined(self.inputs.moving_mask): # If explicit masking is enabled... if self.inputs.explicit_masking: # Mask the moving image. # Do not use a moving mask during registration. args['moving_image'] = mask( self.inputs.moving_image, self.inputs.moving_mask, "moving_masked.nii.gz") # If explicit masking is disabled... else: # Use the moving mask during registration. # Do not mask the moving image. args['moving_image_masks'] = self.inputs.moving_mask # If a lesion mask is also provided... if isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: # [global mask - lesion mask] (if explicit masking is enabled) # [moving mask - lesion mask] (if explicit masking is disabled) # Use this as the moving mask. args['moving_image_masks'] = create_cfm( self.inputs.moving_mask, lesion_mask=self.inputs.lesion_mask, global_mask=self.inputs.explicit_masking) # If no moving mask is provided... # But a lesion mask *IS* provided... elif isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask - lesion mask] # Use this as the moving mask. args['moving_image_masks'] = create_cfm( self.inputs.moving_image, lesion_mask=self.inputs.lesion_mask, global_mask=True) """ Reference image handling - The following truth table maps out the intended action sequence. Future refactoring may more directly encode this. reference_mask and lesion_mask are files True = file False = None | reference_mask | explicit_masking | lesion_mask | action |----------------|------------------|-------------|---------------------------------------- | True | True | True | Update `fixed_image` after applying | | | | mask. | | | | Set `fixed_image_masks` applying | | | | `create_cfm` with `global_mask=True`. |----------------|------------------|-------------|---------------------------------------- | True | True | False | Update `fixed_image` after applying | | | | mask. |----------------|------------------|-------------|---------------------------------------- | True | False | True | Set `fixed_image_masks` applying | | | | `create_cfm` with `global_mask=False` |----------------|------------------|-------------|---------------------------------------- | True | False | False | args['fixed_image_masks'] = fixed_mask |----------------|------------------|-------------|---------------------------------------- | False | * | True | Set `fixed_image_masks` applying | | | | `create_cfm` with `global_mask=True` |----------------|------------------|-------------|---------------------------------------- | False | * | False | No action """ # If a reference image is provided... if isdefined(self.inputs.reference_image): # Use the reference image as the fixed image. args['fixed_image'] = self.inputs.reference_image # If a reference mask is provided... if isdefined(self.inputs.reference_mask): # If explicit masking is enabled... if self.inputs.explicit_masking: # Mask the reference image. # Do not use a fixed mask during registration. args['fixed_image'] = mask( self.inputs.reference_image, self.inputs.reference_mask, "fixed_masked.nii.gz") # If a lesion mask is also provided... if isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask] # Use this as the fixed mask. args['fixed_image_masks'] = create_cfm( self.inputs.reference_mask, lesion_mask=None, global_mask=True) # If a reference mask is provided... # But explicit masking is disabled... else: # Use the reference mask as the fixed mask during registration. # Do not mask the fixed image. args['fixed_image_masks'] = self.inputs.reference_mask # If no reference mask is provided... # But a lesion mask *IS* provided ... elif isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask] # Use this as the fixed mask args['fixed_image_masks'] = create_cfm( self.inputs.reference_image, lesion_mask=None, global_mask=True) # If no reference image is provided, fall back to the default template. else: # Raise an error if the user specifies an unsupported image orientation. if self.inputs.orientation == 'LAS': raise NotImplementedError # Set the template resolution. resolution = self.inputs.template_resolution # Get the template specified by the user. ref_template = get_template(self.inputs.template, resolution=resolution, desc=None, suffix=self.inputs.reference) ref_mask = get_template(self.inputs.template, resolution=resolution, desc='brain', suffix='mask') # Default is explicit masking disabled args['fixed_image'] = str(ref_template) # Use the template mask as the fixed mask. args['fixed_image_masks'] = str(ref_mask) # Overwrite defaults if explicit masking if self.inputs.explicit_masking: # Mask the template image with the template mask. args['fixed_image'] = mask(str(ref_template), str(ref_mask), "fixed_masked.nii.gz") # Do not use a fixed mask during registration. args.pop('fixed_image_masks', None) # If a lesion mask is provided... if isdefined(self.inputs.lesion_mask): # Create a cost function mask with the form: [global mask] # Use this as the fixed mask. args['fixed_image_masks'] = create_cfm( str(ref_mask), lesion_mask=None, global_mask=True) return args