Exemplo n.º 1
0
def gen_sig2noise_img(in4d, outdir):
    startdir = os.getcwd()
    os.chdir(outdir)
    tsnr = misc.TSNR()
    tsnr.inputs.in_file = in4d
    tsnrout = tsnr.run()
    ## there is no valid return code for tsnr
    #if tsnrout.runtime.returncode == 0:
    #    return tsnrout.outputs.tsnr_file
    #else:
    #    print tsnrout.runtime.stderr
    #    return None
    os.chdir(startdir)
    return tsnrout.outputs.tsnr_file
Exemplo n.º 2
0
def fmri_qc(name='fmri_qc'):

    inputnode = pe.Node(
        utility.IdentityInterface(
            fields=['motion','realigned','mask','grey']),
        name='inputspec')
    
    n_tsnr = pe.Node(algmisc.TSNR(), name='tsnr')

    def tsnr_stats(tsnr,mask,grey=None):
        import nibabel as nb, numpy as np
        tsnr=nb.load(tsnr).get_data()
        mask=np.logical_and(
            nb.load(mask).get_data()>0,
            np.logical_not(np.logical_or(np.isinf(tsnr),np.isnan(tsnr))))
        grey_tsnr_mean = np.nan
        grey_tsnr_std = np.nan
        if grey is not None:
            grey=np.logical_and(nb.load(grey).get_data()>0, mask)
            grey_tsnr_mean = tsnr[grey].mean()
            grey_tsnr_std = tsnr[grey].std()
        brain_tsnr_mean = tsnr[mask].mean()
        brain_tsnr_std = tsnr[mask].std()
        return brain_tsnr_mean,brain_tsnr_std,grey_tsnr_mean,grey_tsnr_std
    
    n_tsnr_stats = pe.Node(
        utility.Function(
            input_names=['tsnr','mask','grey'],
            output_names=['brain_tsnr_mean','brain_tsnr_std',
                          'grey_tsnr_mean','grey_tsnr_std'],
            function=tsnr_stats),
        name='tsnr_stats')

    w=pe.Workflow(name=name)
    w.connect([
            (inputnode,n_tsnr,[('realigned','in_file')]),
            (n_tsnr,n_tsnr_stats,[('tsnr_file','tsnr')]),
            (inputnode,n_tsnr_stats,[('mask','mask'),
                                     ('grey','grey')]),

            ])
    return w
Exemplo n.º 3
0
despike = Node(afni.Despike(), name='despike')
despike.inputs.outputtype = 'NIFTI'
#Outputs: out_file

#Slice timing corrected (gets timing from header)
st_corr = Node(spm.SliceTiming(), name='slicetiming_correction')
st_corr.inputs.ref_slice = 1
#Outputs: timecorrected_files

#Realignment using SPM <--- Maybe just estimate and apply all transforms at the end?
realign = Node(spm.Realign(), name='realign')
realign.inputs.register_to_mean = False
realign.inputs.quality = 1.0
#Outputs: realignment_parameters, reliced epi images (motion corrected)

tsnr = Node(misc.TSNR(), name='tsnr')
tsnr.inputs.regress_poly = 2
#Outputs: detrended_file, mean_file, stddev_file, tsnr_file

smooth = Node(spm.Smooth(), name='smooth')
smooth.inputs.fwhm = fwhm

####Anatomical preprocessing####

#dcmstack - Convert dicoms to nii (with embeded metadata)
anat_stack = Node(dcmstack.DcmStack(), name='anatstack')
anat_stack.inputs.embed_meta = True
anat_stack.inputs.out_format = 'anat'
anat_stack.inputs.out_ext = '.nii'
#Outputs: out_file
Exemplo n.º 4
0
def fmri_qc_workflow(name='fMRIQC', settings=None):
    """ The fMRI qc workflow """

    if settings is None:
        settings = {}

    workflow = pe.Workflow(name=name)
    deriv_dir = op.abspath('./derivatives')
    if 'work_dir' in settings.keys():
        deriv_dir = op.abspath(op.join(settings['work_dir'], 'derivatives'))

    if not op.exists(deriv_dir):
        os.makedirs(deriv_dir)

    # Read FD radius, or default it
    fd_radius = settings.get('fd_radius', 80.)

    # Define workflow, inputs and outputs
    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'bids_root', 'subject_id', 'session_id', 'run_id', 'site_name',
        'start_idx', 'stop_idx'
    ]),
                        name='inputnode')
    get_idx = pe.Node(niu.Function(
        input_names=['in_file', 'start_idx', 'stop_idx'],
        function=fmri_getidx,
        output_names=['start_idx', 'stop_idx']),
                      name='get_idx')

    outputnode = pe.Node(niu.IdentityInterface(
        fields=['qc', 'mosaic', 'out_group', 'out_movpar', 'out_dvars']),
                         name='outputnode')

    # 0. Get data
    datasource = pe.Node(niu.Function(input_names=[
        'bids_root', 'data_type', 'subject_id', 'session_id', 'run_id'
    ],
                                      output_names=['out_file'],
                                      function=bids_getfile),
                         name='datasource')
    datasource.inputs.data_type = 'func'

    # Workflow --------------------------------------------------------
    # 1. HMC: head motion correct
    hmcwf = hmc_mcflirt()
    if settings.get('hmc_afni', False):
        hmcwf = hmc_afni(
            st_correct=settings.get('correct_slice_timing', False))
    hmcwf.inputs.inputnode.fd_radius = fd_radius

    mean = pe.Node(
        afp.TStat(  # 2. Compute mean fmri
            options='-mean', outputtype='NIFTI_GZ'),
        name='mean')
    bmw = fmri_bmsk_workflow(  # 3. Compute brain mask
        use_bet=settings.get('use_bet', False))

    # Compute TSNR using nipype implementation
    tsnr = pe.Node(nam.TSNR(), name='compute_tsnr')

    # Compute DVARS
    dvnode = pe.Node(ComputeDVARS(), name='ComputeDVARS')

    # AFNI quality measures
    fwhm = pe.Node(afp.FWHMx(combine=True, detrend=True), name='smoothness')
    # fwhm.inputs.acf = True  # add when AFNI >= 16
    outliers = pe.Node(afp.OutlierCount(fraction=True, out_file='ouliers.out'),
                       name='outliers')
    quality = pe.Node(afp.QualityIndex(automask=True),
                      out_file='quality.out',
                      name='quality')

    measures = pe.Node(FunctionalQC(), name='measures')

    # Plots
    plot_mean = pe.Node(PlotMosaic(title='Mean fMRI'), name='plot_mean')
    plot_tsnr = pe.Node(PlotMosaic(title='tSNR volume'), name='plot_tSNR')
    plot_fd = pe.Node(PlotFD(), name='plot_fd')
    plot_fd.inputs.fd_radius = fd_radius

    merg = pe.Node(niu.Merge(3), name='plot_metadata')

    workflow.connect([
        (inputnode, datasource, [('bids_root', 'bids_root'),
                                 ('subject_id', 'subject_id'),
                                 ('session_id', 'session_id'),
                                 ('run_id', 'run_id')]),
        (inputnode, get_idx, [('start_idx', 'start_idx'),
                              ('stop_idx', 'stop_idx')]),
        (datasource, get_idx, [('out_file', 'in_file')]),
        (inputnode, merg, [('session_id', 'in1'), ('run_id', 'in2'),
                           ('site_name', 'in3')]),
        (datasource, hmcwf, [('out_file', 'inputnode.in_file')]),
        (get_idx, hmcwf, [('start_idx', 'inputnode.start_idx'),
                          ('stop_idx', 'inputnode.stop_idx')]),
        (hmcwf, bmw, [('outputnode.out_file', 'inputnode.in_file')]),
        (hmcwf, mean, [('outputnode.out_file', 'in_file')]),
        (hmcwf, tsnr, [('outputnode.out_file', 'in_file')]),
        (mean, plot_mean, [('out_file', 'in_file')]),
        (tsnr, plot_tsnr, [('tsnr_file', 'in_file')]),
        (hmcwf, plot_fd, [('outputnode.out_movpar', 'in_file')]),
        (inputnode, plot_mean, [('subject_id', 'subject')]),
        (inputnode, plot_tsnr, [('subject_id', 'subject')]),
        (inputnode, plot_fd, [('subject_id', 'subject')]),
        (merg, plot_mean, [('out', 'metadata')]),
        (merg, plot_tsnr, [('out', 'metadata')]),
        (merg, plot_fd, [('out', 'metadata')]),
        (mean, fwhm, [('out_file', 'in_file')]),
        (bmw, fwhm, [('outputnode.out_file', 'mask')]),
        (hmcwf, outliers, [('outputnode.out_file', 'in_file')]),
        (bmw, outliers, [('outputnode.out_file', 'mask')]),
        (hmcwf, quality, [('outputnode.out_file', 'in_file')]),
        (hmcwf, dvnode, [('outputnode.out_file', 'in_file')]),
        (bmw, dvnode, [('outputnode.out_file', 'in_mask')]),
        (mean, measures, [('out_file', 'in_epi')]),
        (hmcwf, measures, [('outputnode.out_file', 'in_hmc'),
                           ('outputnode.out_movpar', 'fd_movpar')]),
        (bmw, measures, [('outputnode.out_file', 'in_mask')]),
        (tsnr, measures, [('tsnr_file', 'in_tsnr')]),
        (dvnode, measures, [('out_file', 'in_dvars')]),
        (dvnode, outputnode, [('out_file', 'out_dvars')]),
        (hmcwf, outputnode, [('outputnode.out_movpar', 'out_movpar')]),
    ])

    if settings.get('mosaic_mask', False):
        workflow.connect(bmw, 'outputnode.out_file', plot_mean, 'in_mask')
        workflow.connect(bmw, 'outputnode.out_file', plot_tsnr, 'in_mask')

    # Save mean mosaic to well-formed path
    mvmean = pe.Node(niu.Rename(
        format_string='meanepi_%(subject_id)s_%(session_id)s_%(run_id)s',
        keep_ext=True),
                     name='rename_mean_mosaic')
    dsmean = pe.Node(nio.DataSink(base_directory=settings['work_dir'],
                                  parameterization=False),
                     name='ds_mean')
    workflow.connect([(inputnode, mvmean, [('subject_id', 'subject_id'),
                                           ('session_id', 'session_id'),
                                           ('run_id', 'run_id')]),
                      (plot_mean, mvmean, [('out_file', 'in_file')]),
                      (mvmean, dsmean, [('out_file', '@mosaic')])])
    # Save tSNR mosaic to well-formed path
    mvtsnr = pe.Node(niu.Rename(
        format_string='tsnr_%(subject_id)s_%(session_id)s_%(run_id)s',
        keep_ext=True),
                     name='rename_tsnr_mosaic')
    dstsnr = pe.Node(nio.DataSink(base_directory=settings['work_dir'],
                                  parameterization=False),
                     name='ds_tsnr')
    workflow.connect([(inputnode, mvtsnr, [('subject_id', 'subject_id'),
                                           ('session_id', 'session_id'),
                                           ('run_id', 'run_id')]),
                      (plot_tsnr, mvtsnr, [('out_file', 'in_file')]),
                      (mvtsnr, dstsnr, [('out_file', '@mosaic')])])
    # Save FD plot to well-formed path
    mvfd = pe.Node(niu.Rename(
        format_string='fd_%(subject_id)s_%(session_id)s_%(run_id)s',
        keep_ext=True),
                   name='rename_fd_mosaic')
    dsfd = pe.Node(nio.DataSink(base_directory=settings['work_dir'],
                                parameterization=False),
                   name='ds_fd')
    workflow.connect([(inputnode, mvfd, [('subject_id', 'subject_id'),
                                         ('session_id', 'session_id'),
                                         ('run_id', 'run_id')]),
                      (plot_fd, mvfd, [('out_file', 'in_file')]),
                      (mvfd, dsfd, [('out_file', '@mosaic')])])

    # Format name
    out_name = pe.Node(niu.Function(
        input_names=['subid', 'sesid', 'runid', 'prefix', 'out_path'],
        output_names=['out_file'],
        function=bids_path),
                       name='FormatName')
    out_name.inputs.out_path = deriv_dir
    out_name.inputs.prefix = 'func'

    # Save to JSON file
    datasink = pe.Node(nio.JSONFileSink(), name='datasink')
    datasink.inputs.qc_type = 'func'

    workflow.connect([
        (inputnode, out_name, [('subject_id', 'subid'),
                               ('session_id', 'sesid'), ('run_id', 'runid')]),
        (inputnode, datasink, [('subject_id', 'subject_id'),
                               ('session_id', 'session_id'),
                               ('run_id', 'run_id')]),
        (plot_mean, datasink, [('out_file', 'mean_plot')]),
        (plot_tsnr, datasink, [('out_file', 'tsnr_plot')]),
        (plot_fd, datasink, [('out_file', 'fd_plot')]),
        (fwhm, datasink, [(('fwhm', fwhm_dict), 'fwhm')]),
        (outliers, datasink, [(('out_file', _parse_tout), 'outlier')]),
        (quality, datasink, [(('out_file', _parse_tqual), 'quality')]),
        (measures, datasink, [('summary', 'summary'), ('spacing', 'spacing'),
                              ('size', 'size'), ('fber', 'fber'),
                              ('efc', 'efc'), ('snr', 'snr'), ('gsr', 'gsr'),
                              ('m_tsnr', 'm_tsnr'), ('fd_stats', 'fd_stats'),
                              ('dvars', 'dvars'), ('gcor', 'gcor')]),
        (out_name, datasink, [('out_file', 'out_file')]),
        (datasink, outputnode, [('out_file', 'out_file')])
    ])

    return workflow
Exemplo n.º 5
0
def create_qc_pipeline(working_dir, ds_dir, name='qc'):
    # initiate workflow
    qc_wf = Workflow(name=name)
    qc_wf.base_dir = os.path.join(working_dir, 'LeiCA_resting',
                                  'rsfMRI_preprocessing')

    # set fsl output
    fsl.FSLCommand.set_default_output_type('NIFTI_GZ')

    # I/O NODES
    inputnode = Node(util.IdentityInterface(fields=[
        'subject_id', 'par_moco', 'outlier_files', 'epi_deskulled',
        't1w_brain', 'mean_epi_structSpace', 'mean_epi_MNIspace',
        'struct_MNIspace', 'struct_brain_mask', 'brain_mask_epiSpace',
        'struct_2_MNI_warp', 'rs_preprocessed'
    ]),
                     name='inputnode')

    outputnode = Node(util.IdentityInterface(fields=['']), name='outputnode')

    ds = Node(nio.DataSink(base_directory=ds_dir), name='ds')
    ds.inputs.substitutions = [('_TR_id_', 'TR_')]

    # CALCULATED POWER FD
    FD_power = Node(util.Function(input_names=['in_file'],
                                  output_names=['out_file'],
                                  function=calculate_FD_P),
                    name='FD_power')
    qc_wf.connect(inputnode, 'par_moco', FD_power, 'in_file')
    qc_wf.connect(FD_power, 'out_file', ds, 'QC.FD.FD_ts')

    mean_FD_power = Node(util.Function(
        input_names=['in_file'],
        output_names=['mean_FD_power', 'out_file'],
        function=calculate_mean_FD_fct),
                         name='mean_FD_power')
    qc_wf.connect(FD_power, 'out_file', mean_FD_power, 'in_file')
    qc_wf.connect(mean_FD_power, 'out_file', ds, 'QC.FD.FD_mean')

    # EXTRACT NUMBER OF SPIKES (OUTLIERS)
    def get_n_spikes_fct(outliers_file):
        import numpy as np

        try:
            spikes = np.atleast_1d(np.genfromtxt(outliers_file))
        except IOError:
            spikes = np.empty((0))
        n_spikes = len(spikes)
        return n_spikes

    get_n_spikes = Node(util.Function(input_names=['outliers_file'],
                                      output_names=['n_spikes'],
                                      function=get_n_spikes_fct),
                        name='get_n_spikes')
    qc_wf.connect(inputnode, 'outlier_files', get_n_spikes, 'outliers_file')

    # CALCULATE TSNR
    tsnr_uglyname = Node(misc.TSNR(), name='tsnr_uglyname')
    qc_wf.connect(inputnode, 'epi_deskulled', tsnr_uglyname, 'in_file')

    tsnr = Node(niu.Rename(format_string='tsnr', keep_ext=True), name='tsnr')
    qc_wf.connect(tsnr_uglyname, 'tsnr_file', tsnr, 'in_file')
    qc_wf.connect(tsnr, 'out_file', ds, 'QC.tsnr')

    # GET MEAN TSNR IN BRAIN_MASK
    def get_values_inside_a_mask(main_file, mask_file, out_file):
        import nibabel as nb
        import numpy as np
        import os

        out_file = os.path.join(os.getcwd(), out_file + '.npy')
        main_nii = nb.load(main_file)
        main_data = main_nii.get_data()
        nan_mask = np.logical_not(np.isnan(main_data))
        mask = nb.load(mask_file).get_data() > 0

        data = main_data[np.logical_and(nan_mask, mask)]
        np.save(out_file, data)
        median_data = np.median(data)
        return (out_file, median_data)

    get_tsnr = Node(util.Function(
        input_names=['main_file', 'mask_file', 'out_file'],
        output_names=['out_file', 'median_data'],
        function=get_values_inside_a_mask),
                    name='get_tsnr')
    get_tsnr.inputs.out_file = 'tsnr'
    qc_wf.connect(tsnr, 'out_file', get_tsnr, 'main_file')
    qc_wf.connect(inputnode, 'brain_mask_epiSpace', get_tsnr, 'mask_file')
    qc_wf.connect(get_tsnr, 'out_file', ds, 'QC.tsnr.@out_file')

    ## CREATE SLICES OVERLAY
    slices_epi_structSpace = Node(util.Function(
        input_names=['in_file', 'in_file2'],
        output_names=['out_file'],
        function=fsl_slices_fct),
                                  name='slices_epi_structSpace')
    qc_wf.connect(inputnode, 'mean_epi_structSpace', slices_epi_structSpace,
                  'in_file')
    qc_wf.connect(inputnode, 't1w_brain', slices_epi_structSpace, 'in_file2')
    qc_wf.connect(slices_epi_structSpace, 'out_file', ds,
                  'QC.slices.epi_structSpace')

    slices_epi_MNIspace = Node(util.Function(
        input_names=['in_file', 'in_file2'],
        output_names=['out_file'],
        function=fsl_slices_fct),
                               name='slices_epi_MNIspace')
    slices_epi_MNIspace.inputs.in_file2 = fsl.Info.standard_image(
        'MNI152_T1_2mm_brain.nii.gz')
    qc_wf.connect(inputnode, 'mean_epi_MNIspace', slices_epi_MNIspace,
                  'in_file')
    qc_wf.connect(slices_epi_MNIspace, 'out_file', ds,
                  'QC.slices.epi_MNIspace')

    slices_struct_MNIspace = Node(util.Function(
        input_names=['in_file', 'in_file2'],
        output_names=['out_file'],
        function=fsl_slices_fct),
                                  name='slices_struct_MNIspace')
    qc_wf.connect(inputnode, 'struct_MNIspace', slices_struct_MNIspace,
                  'in_file')
    slices_struct_MNIspace.inputs.in_file2 = fsl.Info.standard_image(
        'MNI152_T1_2mm_brain.nii.gz')
    qc_wf.connect(slices_struct_MNIspace, 'out_file', ds,
                  'QC.slices.struct_MNIspace')

    # CREATE BRAIN MASK IN MNI SPACE
    struct_brain_mask_MNIspace = Node(fsl.ApplyWarp(),
                                      name='struct_brain_mask_MNIspace',
                                      interp='nn')
    struct_brain_mask_MNIspace.inputs.ref_file = fsl.Info.standard_image(
        'MNI152_T1_2mm_brain.nii.gz')
    struct_brain_mask_MNIspace.inputs.out_file = 'struct_brain_mask_MNIspace.nii.gz'
    qc_wf.connect(inputnode, 'struct_brain_mask', struct_brain_mask_MNIspace,
                  'in_file')
    qc_wf.connect(inputnode, 'struct_2_MNI_warp', struct_brain_mask_MNIspace,
                  'field_file')

    # CREATE STRUCT_BRAIN IN MNI SPACE
    struct_brain_MNIspace = Node(fsl.ApplyWarp(), name='struct_brain_MNIspace')
    struct_brain_MNIspace.inputs.ref_file = fsl.Info.standard_image(
        'MNI152_T1_2mm_brain.nii.gz')
    struct_brain_MNIspace.inputs.out_file = 'struct_MNIspace.nii.gz'
    qc_wf.connect(inputnode, 't1w_brain', struct_brain_MNIspace, 'in_file')
    qc_wf.connect(inputnode, 'struct_2_MNI_warp', struct_brain_MNIspace,
                  'field_file')

    def similarity_to_file_fct(similarity):
        import os
        import numpy as np

        out_file = os.path.join(os.getcwd(), 'similarity.txt')
        np.savetxt(out_file, np.array(similarity))
        return out_file

    # CALCULATE SIMILARITY FOR QC
    similarity_epi_struct = Node(interface=Similarity(metric='nmi'),
                                 name='similarity_epi_struct')
    qc_wf.connect(inputnode, 'mean_epi_structSpace', similarity_epi_struct,
                  'volume1')
    qc_wf.connect(inputnode, 't1w_brain', similarity_epi_struct, 'volume2')
    qc_wf.connect(inputnode, 'struct_brain_mask', similarity_epi_struct,
                  'mask1')
    qc_wf.connect(inputnode, 'struct_brain_mask', similarity_epi_struct,
                  'mask2')

    similarity_epi_struct_txt = Node(util.Function(
        input_names=['similarity'],
        output_names=['out_file'],
        function=similarity_to_file_fct),
                                     name='similarity_epi_struct_txt')
    qc_wf.connect(similarity_epi_struct, 'similarity',
                  similarity_epi_struct_txt, 'similarity')
    qc_wf.connect(similarity_epi_struct_txt, 'out_file', ds,
                  'QC.similarity.epi_struct')

    similarity_struct_MNI = Node(interface=Similarity(metric='nmi'),
                                 name='similarity_struct_MNI')
    qc_wf.connect(struct_brain_MNIspace, 'out_file', similarity_struct_MNI,
                  'volume1')
    similarity_struct_MNI.inputs.volume2 = fsl.Info.standard_image(
        'MNI152_T1_2mm_brain.nii.gz')
    qc_wf.connect(struct_brain_mask_MNIspace, 'out_file',
                  similarity_struct_MNI, 'mask1')
    qc_wf.connect(struct_brain_mask_MNIspace, 'out_file',
                  similarity_struct_MNI, 'mask2')

    similarity_struct_MNI_txt = Node(util.Function(
        input_names=['similarity'],
        output_names=['out_file'],
        function=similarity_to_file_fct),
                                     name='similarity_struct_MNI_txt')
    qc_wf.connect(similarity_struct_MNI, 'similarity',
                  similarity_struct_MNI_txt, 'similarity')
    qc_wf.connect(similarity_struct_MNI_txt, 'out_file', ds,
                  'QC.similarity.struct_MNI')

    def list_to_num(lst):
        return lst[0]

    def create_qc_df_fct(subject_id, similarity_epi_struct,
                         similarity_struct_MNI, mean_FD_Power, n_spikes,
                         median_tsnr):
        import pandas as pd
        import os

        out_file_df = os.path.join(os.getcwd(), 'qc_values.pkl')
        out_file_txt = os.path.join(os.getcwd(), 'qc_values.txt')
        data = [
            subject_id, similarity_epi_struct, similarity_struct_MNI,
            mean_FD_Power, n_spikes, median_tsnr
        ]
        header = [
            'subject_id', 'similarity_epi_struct', 'similarity_struct_MNI',
            'mean_FD_Power', 'n_spikes', 'median_tsnr'
        ]
        df = pd.DataFrame([data], columns=header)
        df = df.set_index(df.subject_id)
        df.to_pickle(out_file_df)
        df.to_csv(out_file_txt, sep='\t')
        return (out_file_df, out_file_txt)

    create_qc_df = Node(util.Function(
        input_names=[
            'subject_id', 'similarity_epi_struct', 'similarity_struct_MNI',
            'mean_FD_Power', 'n_spikes', 'median_tsnr'
        ],
        output_names=['out_file_df', 'out_file_txt'],
        function=create_qc_df_fct),
                        name='create_qc_df')

    qc_wf.connect(inputnode, 'subject_id', create_qc_df, 'subject_id')
    qc_wf.connect(similarity_epi_struct, ('similarity', list_to_num),
                  create_qc_df, 'similarity_epi_struct')
    qc_wf.connect(similarity_struct_MNI, ('similarity', list_to_num),
                  create_qc_df, 'similarity_struct_MNI')
    qc_wf.connect(mean_FD_power, 'mean_FD_power', create_qc_df,
                  'mean_FD_Power')
    qc_wf.connect(get_n_spikes, 'n_spikes', create_qc_df, 'n_spikes')
    qc_wf.connect(get_tsnr, 'median_data', create_qc_df, 'median_tsnr')

    qc_wf.connect(create_qc_df, 'out_file_df', ds, 'QC.df.@df')
    qc_wf.connect(create_qc_df, 'out_file_txt', ds, 'QC.df.@txt')

    qc_wf.write_graph(dotfilename=qc_wf.name, graph2use='flat', format='pdf')

    return qc_wf
Exemplo n.º 6
0
    r12.append(get_rigid_matrix(rigid_params, args.package)[:-1].ravel())
r12 = numpy.asarray(r12)
numpy.savetxt(r12_file, r12)
fd_jenkinson(r12_file, rmax=80., out_file=fd_file)

# > computes the time-course SNR for a time series,
# typically you want to run this on a realigned time-series.
funcrealign_file = os.path.join(subjectdir,
                                "nonan_" + os.path.basename(args.funcrealign))
im = nibabel.load(args.funcrealign)
data_array = im.get_data()
data_array[numpy.isnan(data_array)] = 0
nibabel.save(im, funcrealign_file)
cwd = os.getcwd()
os.chdir(subjectdir)
tsnr = nam.TSNR()
tsnr.inputs.in_file = funcrealign_file
tsnr.run()
tsnr = tsnr.aggregate_outputs()
os.chdir(cwd)
for out_name in ["tsnr_file", "mean_file", "stddev_file"]:
    path = getattr(tsnr, out_name)
    tmp_path = os.path.join(subjectdir, "tmp_" + os.path.basename(path))
    shutil.copyfile(path, tmp_path)
    im = nibabel.load(tmp_path)
    data_array = im.get_data()
    data_array[numpy.isnan(data_array)] = 0
    nibabel.save(im, path)
    os.remove(tmp_path)

# > compute functional temporal scores from QAP library
    def getbtthresh(medianvals):
        return [0.75 * val for val in medianvals]

    preprocessing.connect(medianval, ('out_stat', getbtthresh), smooth, 'brightness_threshold')
else:
    smooth=pe.Node(interface=fsl.utils.Smooth(), name="smooth")

smooth.inputs.fwhm=6

# Turn off smoothing for now - we will do it later on the constrast images
#preprocessing.connect(rescale,'out_file',smooth,'in_file')
#preprocessing.connect(smooth,'smoothed_file',datasink,'smooth')

fqc=pe.Node(interface=FunctionalQC(),name='fqc')

tsnr = pe.Node(nam.TSNR(), name='compute_tsnr')

preprocessing.connect(mcflirt, 'out_file',tsnr,'in_file')

preprocessing.connect(mcflirt,'mean_img',fqc,'in_epi')
preprocessing.connect(mcflirt, 'out_file',fqc,'in_hmc')
preprocessing.connect(bet_func, 'mask_file',fqc,'in_mask')
preprocessing.connect(tsnr, 'tsnr_file',fqc,'in_tsnr')

preprocessing.connect(mcflirt, 'par_file',fqc,'fd_movpar')


preprocessing.connect(fqc,'dvars',datasink,'mriqc.dvars')
preprocessing.connect(fqc,'summary',datasink,'mriqc.summary')
preprocessing.connect(fqc,'fd_stats',datasink,'mriqc.fd')
preprocessing.connect(tsnr,'tsnr_file',datasink,'mriqc.tsnr')
Exemplo n.º 8
0
def qap_functional_temporal_workflow(workflow, resource_pool, config):

    # resource pool should have:
    #     functional_brain_mask
    #     func_motion_correct
    #     coordinate_transformation

    import os
    import sys
    import nipype.interfaces.io as nio
    import nipype.pipeline.engine as pe
    import nipype.interfaces.utility as niu
    import nipype.algorithms.misc as nam

    from qap_workflows_utils import qap_functional_temporal
    from temporal_qc import fd_jenkinson
    from qap.viz.interfaces import PlotMosaic, PlotFD

    def _getfirst(inlist):
        if isinstance(inlist, list):
            return inlist[0]

        return inlist

    # if 'mean_functional' not in resource_pool.keys():
    #     from functional_preproc import mean_functional_workflow
    #     workflow, resource_pool = \
    #         mean_functional_workflow(workflow, resource_pool, config)

    if 'functional_brain_mask' not in resource_pool.keys():
        from functional_preproc import functional_brain_mask_workflow
        workflow, resource_pool = \
            functional_brain_mask_workflow(workflow, resource_pool, config)

    if ('func_motion_correct' not in resource_pool.keys()) or \
        ('coordinate_transformation' not in resource_pool.keys() and
            'mcflirt_rel_rms' not in resource_pool.keys()):
        from functional_preproc import func_motion_correct_workflow
        workflow, resource_pool = \
            func_motion_correct_workflow(workflow, resource_pool, config)

    fd = pe.Node(niu.Function(input_names=['in_file'],
                              output_names=['out_file'],
                              function=fd_jenkinson),
                 name='generate_FD_file')

    if 'mcflirt_rel_rms' in resource_pool.keys():
        fd.inputs.in_file = resource_pool['mcflirt_rel_rms']
    else:
        if len(resource_pool['coordinate_transformation']) == 2:
            node, out_file = resource_pool['coordinate_transformation']
            workflow.connect(node, out_file, fd, 'in_file')
        else:
            fd.inputs.in_file = resource_pool['coordinate_transformation']

    temporal = pe.Node(niu.Function(input_names=[
        'func_motion_correct', 'func_brain_mask', 'tsnr_volume', 'fd_file',
        'subject_id', 'session_id', 'scan_id', 'site_name'
    ],
                                    output_names=['qc'],
                                    function=qap_functional_temporal),
                       name='qap_functional_temporal')
    temporal.inputs.subject_id = config['subject_id']
    temporal.inputs.session_id = config['session_id']
    temporal.inputs.scan_id = config['scan_id']
    workflow.connect(fd, 'out_file', temporal, 'fd_file')

    if 'site_name' in config.keys():
        temporal.inputs.site_name = config['site_name']

    tsnr = pe.Node(nam.TSNR(), name='compute_tsnr')
    if len(resource_pool['func_motion_correct']) == 2:
        node, out_file = resource_pool['func_motion_correct']
        workflow.connect(node, out_file, tsnr, 'in_file')
        workflow.connect(node, out_file, temporal, 'func_motion_correct')
    else:
        from workflow_utils import check_input_resources
        check_input_resources(resource_pool, 'func_motion_correct')
        input_file = resource_pool['func_motion_correct']
        tsnr.inputs.in_file = input_file
        temporal.inputs.func_motion_correct = input_file

    if len(resource_pool['functional_brain_mask']) == 2:
        node, out_file = resource_pool['functional_brain_mask']
        workflow.connect(node, out_file, temporal, 'func_brain_mask')
    else:
        temporal.inputs.func_brain_mask = \
            resource_pool['functional_brain_mask']

    # Write mosaic and FD plot
    if config.get('write_report', False):
        plot = pe.Node(PlotMosaic(), name='plot_mosaic')
        plot.inputs.subject = config['subject_id']

        metadata = [config['session_id'], config['scan_id']]
        if 'site_name' in config.keys():
            metadata.append(config['site_name'])

        plot.inputs.metadata = metadata
        plot.inputs.title = 'tSNR volume'
        workflow.connect(tsnr, 'tsnr_file', plot, 'in_file')

        # Enable this if we want masks
        # if len(resource_pool['functional_brain_mask']) == 2:
        #     node, out_file = resource_pool['functional_brain_mask']
        #     workflow.connect(node, out_file, plot, 'in_mask')
        # else:
        #     plot.inputs.in_mask = resource_pool['functional_brain_mask']
        resource_pool['qap_mosaic'] = (plot, 'out_file')

        fdplot = pe.Node(PlotFD(), name='plot_fd')
        fdplot.inputs.subject = config['subject_id']
        fdplot.inputs.metadata = metadata
        workflow.connect(fd, 'out_file', fdplot, 'in_file')
        resource_pool['qap_fd'] = (fdplot, 'out_file')

    out_csv = op.join(config['output_directory'],
                      'qap_functional_temporal.csv')
    temporal_to_csv = pe.Node(nam.AddCSVRow(in_file=out_csv),
                              name='qap_functional_temporal_to_csv')

    workflow.connect(tsnr, 'tsnr_file', temporal, 'tsnr_volume')
    workflow.connect(temporal, 'qc', temporal_to_csv, '_outputs')
    resource_pool['qap_functional_temporal'] = (temporal_to_csv, 'csv_file')
    return workflow, resource_pool
Exemplo n.º 9
0
fslmaths = MeanImage()
fslmaths.inputs.in_file = 'corr_rest_roi.nii.gz'
fslmaths.inputs.out_file = 'mean_corr_rest_roi.nii.gz'
fslmaths.inputs.dimension = 'T'
fslmaths.run()

# Step#4 get binary mask & skull stripped imag
img_StMoco = os.path.abspath('corr_rest_roi.nii.gz')

btr = fsl.BET()
btr.inputs.in_file = img_StMoco
btr.inputs.mask = True
btr.run()

# Step#5 tsnr calculation on realigned image
tsnr = misc.TSNR()
tsnr.inputs.in_file = 'corr_rest_roi.nii.gz'
tsnr.inputs.mean_file = 'corr_rest_roi_tsnr_mean.nii.gz'
tsnr.inputs.tsnr_file = 'corr_rest_roi_tsnr.nii.gz'
tsnr.inputs.stddev_file = 'corr_rest_roi_tsnr_stddev.nii.gz'
tsnr.run()

# (optional) registration from restYY -->> restXX
if len(sys.argv) > 3:
    # e.g. dayXX = 'd01'
    dayXX = sys.argv[3]

    # create work_dir for transform matrices
    dir_trf = 'transforms2rest' + dayXX[1:]
    work_dir_trf = os.path.join(data_dir, subject_id, 'preprocessed/func',
                                dir_trf)
Exemplo n.º 10
0
def create_moco_pipeline(name='motion_correction'):

    # initiate workflow
    moco = Workflow(name='motion_correction')

    # set fsl output
    fsl.FSLCommand.set_default_output_type('NIFTI_GZ')

    # inputnode
    inputnode = Node(util.IdentityInterface(fields=['epi']), name='inputnode')

    # outputnode
    outputnode = Node(util.IdentityInterface(fields=[
        'epi_moco', 'par_moco', 'mat_moco', 'rms_moco', 'epi_mean', 'rotplot',
        'transplot', 'dispplots', 'tsnr_file'
    ]),
                      name='outputnode')

    # mcflirt motion correction to 1st volume
    mcflirt = Node(fsl.MCFLIRT(save_mats=True,
                               save_plots=True,
                               save_rms=True,
                               ref_vol=1,
                               out_file='rest_realigned.nii.gz'),
                   name='mcflirt')

    # plot motion parameters
    rotplotter = Node(fsl.PlotMotionParams(in_source='fsl',
                                           plot_type='rotations',
                                           out_file='rotation_plot.png'),
                      name='rotplotter')

    transplotter = Node(fsl.PlotMotionParams(in_source='fsl',
                                             plot_type='translations',
                                             out_file='translation_plot.png'),
                        name='transplotter')

    dispplotter = MapNode(interface=fsl.PlotMotionParams(
        in_source='fsl',
        plot_type='displacement',
    ),
                          name='dispplotter',
                          iterfield=['in_file'])
    dispplotter.iterables = ('plot_type', ['displacement'])

    # calculate tmean
    tmean = Node(fsl.maths.MeanImage(dimension='T',
                                     out_file='rest_realigned_mean.nii.gz'),
                 name='tmean')

    # calculate tsnr
    tsnr = Node(misc.TSNR(), name='tsnr')

    # create connections
    moco.connect([(inputnode, mcflirt, [('epi', 'in_file')]),
                  (mcflirt, tmean, [('out_file', 'in_file')]),
                  (mcflirt, rotplotter, [('par_file', 'in_file')]),
                  (mcflirt, transplotter, [('par_file', 'in_file')]),
                  (mcflirt, dispplotter, [('rms_files', 'in_file')]),
                  (tmean, outputnode, [('out_file', 'epi_mean')]),
                  (mcflirt, outputnode, [('out_file', 'epi_moco'),
                                         ('par_file', 'par_moco'),
                                         ('mat_file', 'mat_moco'),
                                         ('rms_files', 'rms_moco')]),
                  (rotplotter, outputnode, [('out_file', 'rotplot')]),
                  (transplotter, outputnode, [('out_file', 'transplot')]),
                  (dispplotter, outputnode, [('out_file', 'dispplots')]),
                  (mcflirt, tsnr, [('out_file', 'in_file')]),
                  (tsnr, outputnode, [('tsnr_file', 'tsnr_file')])])

    return moco
Exemplo n.º 11
0
def min_func_preproc(subject, sessions, data_dir, fs_dir, wd, sink, TR,
                     EPI_resolution):

    #initiate min func preproc workflow
    wf = pe.Workflow(name='MPP')
    wf.base_dir = wd
    wf.config['execution']['crashdump_dir'] = wf.base_dir + "/crash_files"

    ## set fsl output type to nii.gz
    fsl.FSLCommand.set_default_output_type('NIFTI_GZ')

    # I/O nodes
    inputnode = pe.Node(util.IdentityInterface(fields=['subjid', 'fs_dir']),
                        name='inputnode')
    inputnode.inputs.subjid = subject
    inputnode.inputs.fs_dir = fs_dir

    ds = pe.Node(nio.DataSink(base_directory=sink, parameterization=False),
                 name='sink')

    ds.inputs.substitutions = [('moco.nii.gz.par', 'moco.par'),
                               ('moco.nii.gz_', 'moco_')]

    #infosource to interate over sessions: COND, EXT1, EXT2
    sessions_infosource = pe.Node(util.IdentityInterface(fields=['session']),
                                  name='session')
    sessions_infosource.iterables = [('session', sessions)]

    #select files
    templates = {
        'func_data': '{session}/func_data.nii.gz',
        'T1_brain': 'T1/T1_brain.nii.gz',
        'wmedge': 'T1/MASKS/aparc_aseg.WMedge.nii.gz'
    }

    selectfiles = pe.Node(nio.SelectFiles(templates, base_directory=data_dir),
                          name='selectfiles')

    wf.connect(sessions_infosource, 'session', selectfiles, 'session')
    wf.connect(sessions_infosource, 'session', ds, 'container')

    ##########################################################################
    ########################    START   ######################################
    ##########################################################################

    ###########################################################################
    ########################    No. 3   ######################################

    #change the data type to float
    fsl_float = pe.Node(fsl.maths.MathsCommand(output_datatype='float'),
                        name='fsl_float')

    wf.connect(selectfiles, 'func_data', fsl_float, 'in_file')

    ###########################################################################
    ########################    No. 4   ######################################

    #get FD from fsl_motion_outliers
    FD = pe.Node(fsl.MotionOutliers(out_file='func_data_FD_outliers.txt',
                                    out_metric_values='func_data_FD.txt',
                                    metric='fd'),
                 name='FD')

    wf.connect(fsl_float, 'out_file', FD, 'in_file')
    wf.connect(FD, 'out_metric_values', ds, 'QC.@FD')
    wf.connect(FD, 'out_file', ds, 'QC.@FDoutliers')

    ###########################################################################
    ########################    No. 5   ######################################

    #slice timing correction: sequential ascending
    slicetimer = pe.Node(
        fsl.SliceTimer(
            index_dir=False,
            interleaved=False,
            #slice_direction=3, #z direction
            time_repetition=TR,
            out_file='func_data_stc.nii.gz'),
        name='slicetimer')

    wf.connect(fsl_float, 'out_file', slicetimer, 'in_file')
    wf.connect(slicetimer, 'slice_time_corrected_file', ds, 'TEMP.@slicetimer')

    ###########################################################################
    ########################    No. 6   ######################################
    #do realignment to the middle or first volume
    mcflirt = pe.Node(fsl.MCFLIRT(save_mats=True,
                                  save_plots=True,
                                  save_rms=True,
                                  ref_vol=1,
                                  out_file='func_data_stc_moco.nii.gz'),
                      name='mcflirt')

    wf.connect(slicetimer, 'slice_time_corrected_file', mcflirt, 'in_file')
    wf.connect(mcflirt, 'out_file', ds, 'TEMP.@mcflirt')
    wf.connect(mcflirt, 'par_file', ds, 'MOCO.@par_file')
    wf.connect(mcflirt, 'rms_files', ds, 'MOCO.@rms_files')
    wf.connect(mcflirt, 'mat_file', ds, 'MOCO_MAT.@mcflirt')

    # plot motion parameters
    rotplotter = pe.Node(fsl.PlotMotionParams(in_source='fsl',
                                              plot_type='rotations',
                                              out_file='rotation.png'),
                         name='rotplotter')

    transplotter = pe.Node(fsl.PlotMotionParams(in_source='fsl',
                                                plot_type='translations',
                                                out_file='translation.png'),
                           name='transplotter')

    dispplotter = pe.Node(
        interface=fsl.PlotMotionParams(in_source='fsl',
                                       plot_type='displacement',
                                       out_file='displacement.png'),
        name='dispplotter')

    wf.connect(mcflirt, 'par_file', rotplotter, 'in_file')
    wf.connect(mcflirt, 'par_file', transplotter, 'in_file')
    wf.connect(mcflirt, 'rms_files', dispplotter, 'in_file')
    wf.connect(rotplotter, 'out_file', ds, 'PLOTS.@rotplot')
    wf.connect(transplotter, 'out_file', ds, 'PLOTS.@transplot')
    wf.connect(dispplotter, 'out_file', ds, 'PLOTS.@disppplot')

    #calculate tSNR and the mean

    moco_Tmean = pe.Node(fsl.maths.MathsCommand(args='-Tmean',
                                                out_file='moco_Tmean.nii.gz'),
                         name='moco_Tmean')

    moco_Tstd = pe.Node(fsl.maths.MathsCommand(args='-Tstd',
                                               out_file='moco_Tstd.nii.gz'),
                        name='moco_Tstd')

    tSNR0 = pe.Node(fsl.maths.MultiImageMaths(op_string='-div %s',
                                              out_file='moco_tSNR.nii.gz'),
                    name='moco_tSNR')

    wf.connect(mcflirt, 'out_file', moco_Tmean, 'in_file')
    wf.connect(mcflirt, 'out_file', moco_Tstd, 'in_file')
    wf.connect(moco_Tmean, 'out_file', tSNR0, 'in_file')
    wf.connect(moco_Tstd, 'out_file', tSNR0, 'operand_files')
    wf.connect(moco_Tmean, 'out_file', ds, 'TEMP.@moco_Tmean')
    wf.connect(moco_Tstd, 'out_file', ds, 'TEMP.@moco_Tstd')
    wf.connect(tSNR0, 'out_file', ds, 'TEMP.@moco_Tsnr')

    ###########################################################################
    ########################    No. 7   ######################################

    #bias field correction of mean epi for better coregistration
    bias = pe.Node(
        fsl.FAST(
            img_type=2,
            #restored_image='epi_Tmeanrestored.nii.gz',
            output_biascorrected=True,
            out_basename='moco_Tmean',
            no_pve=True,
            probability_maps=False),
        name='bias')

    wf.connect(moco_Tmean, 'out_file', bias, 'in_files')
    wf.connect(bias, 'restored_image', ds, 'TEMP.@restored_image')

    #co-registration to anat using FS BBregister and mean EPI
    bbregister = pe.Node(fs.BBRegister(
        subject_id=subject,
        subjects_dir=fs_dir,
        contrast_type='t2',
        init='fsl',
        out_fsl_file='func2anat.mat',
        out_reg_file='func2anat.dat',
        registered_file='moco_Tmean_restored2anat.nii.gz',
        epi_mask=True),
                         name='bbregister')

    wf.connect(bias, 'restored_image', bbregister, 'source_file')
    wf.connect(bbregister, 'registered_file', ds, 'TEMP.@registered_file')
    wf.connect(bbregister, 'out_fsl_file', ds, 'COREG.@out_fsl_file')
    wf.connect(bbregister, 'out_reg_file', ds, 'COREG.@out_reg_file')
    wf.connect(bbregister, 'min_cost_file', ds, 'COREG.@min_cost_file')

    #inverse func2anat mat
    inverseXFM = pe.Node(fsl.ConvertXFM(invert_xfm=True,
                                        out_file='anat2func.mat'),
                         name='inverseXFM')

    wf.connect(bbregister, 'out_fsl_file', inverseXFM, 'in_file')
    wf.connect(inverseXFM, 'out_file', ds, 'COREG.@out_fsl_file_inv')

    #plot the corregistration quality
    slicer = pe.Node(fsl.Slicer(middle_slices=True, out_file='func2anat.png'),
                     name='slicer')

    wf.connect(selectfiles, 'wmedge', slicer, 'image_edges')
    wf.connect(bbregister, 'registered_file', slicer, 'in_file')
    wf.connect(slicer, 'out_file', ds, 'PLOTS.@func2anat')

    ###########################################################################
    ########################    No. 8   ######################################
    #MOCO and COREGISTRATION

    #resample T1 to EPI resolution to use it as a reference image
    resample_T1 = pe.Node(
        fsl.FLIRT(datatype='float',
                  apply_isoxfm=EPI_resolution,
                  out_file='T1_brain_EPI.nii.gz'),
        #interp='nearestneighbour'),keep spline so it looks nicer
        name='resample_T1')

    wf.connect(selectfiles, 'T1_brain', resample_T1, 'in_file')
    wf.connect(selectfiles, 'T1_brain', resample_T1, 'reference')
    wf.connect(resample_T1, 'out_file', ds, 'COREG.@resample_T1')

    #concate matrices (moco and func2anat) volume-wise
    concat_xfm = pe.MapNode(fsl.ConvertXFM(concat_xfm=True),
                            iterfield=['in_file'],
                            name='concat_xfm')

    wf.connect(mcflirt, 'mat_file', concat_xfm, 'in_file')
    wf.connect(bbregister, 'out_fsl_file', concat_xfm, 'in_file2')
    wf.connect(concat_xfm, 'out_file', ds, 'MOCO2ANAT_MAT.@concat_out')

    #split func_data
    split = pe.Node(fsl.Split(dimension='t'), name='split')

    wf.connect(slicetimer, 'slice_time_corrected_file', split, 'in_file')

    #motion correction and corregistration in one interpolation step
    flirt = pe.MapNode(fsl.FLIRT(apply_xfm=True,
                                 interp='spline',
                                 datatype='float'),
                       iterfield=['in_file', 'in_matrix_file'],
                       name='flirt')

    wf.connect(split, 'out_files', flirt, 'in_file')
    wf.connect(resample_T1, 'out_file', flirt, 'reference')
    wf.connect(concat_xfm, 'out_file', flirt, 'in_matrix_file')

    #merge the files to have 4d dataset motion corrected and co-registerd to T1
    merge = pe.Node(fsl.Merge(dimension='t',
                              merged_file='func_data_stc_moco2anat.nii.gz'),
                    name='merge')

    wf.connect(flirt, 'out_file', merge, 'in_files')
    wf.connect(merge, 'merged_file', ds, 'TEMP.@merged')

    ###########################################################################
    ########################    No. 9   ######################################

    #run BET on co-registered EPI in 1mm and get the mask
    bet = pe.Node(fsl.BET(mask=True,
                          functional=True,
                          out_file='moco_Tmean_restored2anat_BET.nii.gz'),
                  name='bet')

    wf.connect(bbregister, 'registered_file', bet, 'in_file')
    wf.connect(bet, 'out_file', ds, 'TEMP.@func_data_example')
    wf.connect(bet, 'mask_file', ds, 'TEMP.@func_data_mask')

    #resample BET mask to EPI resolution
    resample_mask = pe.Node(fsl.FLIRT(
        datatype='int',
        apply_isoxfm=EPI_resolution,
        interp='nearestneighbour',
        out_file='prefiltered_func_data_mask.nii.gz'),
                            name='resample_mask')

    wf.connect(bet, 'mask_file', resample_mask, 'in_file')
    wf.connect(resample_T1, 'out_file', resample_mask, 'reference')
    wf.connect(resample_mask, 'out_file', ds, '@mask')

    #apply the mask to 4D data to get rid of the "eyes and the rest"
    mask4D = pe.Node(fsl.maths.ApplyMask(), name='mask')

    wf.connect(merge, 'merged_file', mask4D, 'in_file')
    wf.connect(resample_mask, 'out_file', mask4D, 'mask_file')

    ###########################################################################
    ########################    No. 10   ######################################

    #get the values necessary for intensity normalization
    median = pe.Node(fsl.utils.ImageStats(op_string='-k %s -p 50'),
                     name='median')

    wf.connect(resample_mask, 'out_file', median, 'mask_file')
    wf.connect(mask4D, 'out_file', median, 'in_file')

    #compute the scaling factor
    def get_factor(val):

        factor = 10000 / val
        return factor

    get_scaling_factor = pe.Node(util.Function(input_names=['val'],
                                               output_names=['out_val'],
                                               function=get_factor),
                                 name='scaling_factor')

    #normalize the 4D func data with one scaling factor
    multiplication = pe.Node(fsl.maths.BinaryMaths(
        operation='mul', out_file='prefiltered_func_data.nii.gz'),
                             name='multiplication')

    wf.connect(median, 'out_stat', get_scaling_factor, 'val')
    wf.connect(get_scaling_factor, 'out_val', multiplication, 'operand_value')
    wf.connect(mask4D, 'out_file', multiplication, 'in_file')
    wf.connect(multiplication, 'out_file', ds, '@prefiltered_func_data')

    ###########################################################################
    ########################    No. 11   ######################################

    #calculate tSNR and the mean of the new prefiltered and detrend dataset

    tsnr_detrend = pe.Node(misc.TSNR(
        regress_poly=1,
        detrended_file='prefiltered_func_data_detrend.nii.gz',
        mean_file='prefiltered_func_data_detrend_Tmean.nii.gz',
        tsnr_file='prefiltered_func_data_detrend_tSNR.nii.gz'),
                           name='tsnr_detrend')

    wf.connect(multiplication, 'out_file', tsnr_detrend, 'in_file')
    wf.connect(tsnr_detrend, 'tsnr_file', ds, 'QC.@tsnr_detrend')
    wf.connect(tsnr_detrend, 'mean_file', ds, 'QC.@detrend_mean_file')
    wf.connect(tsnr_detrend, 'detrended_file', ds, '@detrend_file')

    #resample the EPI mask to original EPI dimensions
    convert2func = pe.Node(fsl.FLIRT(apply_xfm=True,
                                     interp='nearestneighbour',
                                     out_file='func_data_mask2func.nii.gz'),
                           name='conver2func')

    wf.connect(resample_mask, 'out_file', convert2func, 'in_file')
    wf.connect(bias, 'restored_image', convert2func, 'reference')
    wf.connect(inverseXFM, 'out_file', convert2func, 'in_matrix_file')
    wf.connect(convert2func, 'out_file', ds, 'QC.@inv')

    ###########################################################################
    ########################    RUN   ######################################
    wf.write_graph(dotfilename='wf.dot',
                   graph2use='colored',
                   format='pdf',
                   simple_form=True)
    wf.run(plugin='MultiProc', plugin_args={'n_procs': 2})
    #wf.run()
    return