Exemple #1
0
    def _fugue_pipeline(self, **name_maps):

        pipeline = self.new_pipeline(
            name='preprocess_pipeline',
            desc=("Fugue distortion correction pipeline"),
            citations=[fsl_cite],
            name_maps=name_maps)

        reorient_epi_in = pipeline.add(
            'reorient_epi_in',
            fsl.utils.Reorient2Std(output_type='NIFTI_GZ'),
            inputs={'in_file': ('series', nifti_gz_format)},
            requirements=[fsl_req.v('5.0.9')])

        fm_mag_reorient = pipeline.add(
            'reorient_fm_mag',
            fsl.utils.Reorient2Std(output_type='NIFTI_GZ'),
            inputs={'in_file': ('field_map_mag', nifti_gz_format)},
            requirements=[fsl_req.v('5.0.9')])

        fm_phase_reorient = pipeline.add(
            'reorient_fm_phase',
            fsl.utils.Reorient2Std(output_type='NIFTI_GZ'),
            inputs={'in_file': ('field_map_phase', nifti_gz_format)},
            requirements=[fsl_req.v('5.0.9')])

        bet = pipeline.add("bet",
                           BET(robust=True, output_type='NIFTI_GZ'),
                           inputs={'in_file': (fm_mag_reorient, 'out_file')},
                           wall_time=5,
                           requirements=[fsl_req.v('5.0.9')])

        create_fmap = pipeline.add(
            "prepfmap",
            PrepareFieldmap(
                # delta_TE=2.46
            ),
            inputs={
                'delta_TE': ('field_map_delta_te', float),
                "in_magnitude": (bet, "out_file"),
                'in_phase': (fm_phase_reorient, 'out_file')
            },
            wall_time=5,
            requirements=[fsl_req.v('5.0.9')])

        pipeline.add(
            'fugue',
            FUGUE(unwarp_direction='x',
                  dwell_time=self.parameter('fugue_echo_spacing'),
                  unwarped_file='example_func.nii.gz',
                  output_type='NIFTI_GZ'),
            inputs={
                'fmap_in_file': (create_fmap, 'out_fieldmap'),
                'in_file': (reorient_epi_in, 'out_file')
            },
            outputs={'series_preproc': ('unwarped_file', nifti_gz_format)},
            wall_time=5,
            requirements=[fsl_req.v('5.0.9')])

        return pipeline
Exemple #2
0
    def _fugue_pipeline(self, **kwargs):

        pipeline = self.create_pipeline(
            name='preproc_pipeline',
            inputs=[
                DatasetSpec('primary', nifti_gz_format),
                DatasetSpec('field_map_mag', nifti_gz_format),
                DatasetSpec('field_map_phase', nifti_gz_format),
                FieldSpec('field_map_delta_te', float)
            ],
            outputs=[DatasetSpec('preproc', nifti_gz_format)],
            desc=("Fugue distortion correction pipeline"),
            version=1,
            citations=[fsl_cite],
            **kwargs)

        reorient_epi_in = pipeline.create_node(fsl.utils.Reorient2Std(),
                                               name='reorient_epi_in',
                                               requirements=[fsl509_req])
        pipeline.connect_input('primary', reorient_epi_in, 'in_file')
        fm_mag_reorient = pipeline.create_node(fsl.utils.Reorient2Std(),
                                               name='reorient_fm_mag',
                                               requirements=[fsl509_req])
        pipeline.connect_input('field_map_mag', fm_mag_reorient, 'in_file')
        fm_phase_reorient = pipeline.create_node(fsl.utils.Reorient2Std(),
                                                 name='reorient_fm_phase',
                                                 requirements=[fsl509_req])
        pipeline.connect_input('field_map_phase', fm_phase_reorient, 'in_file')
        bet = pipeline.create_node(BET(),
                                   name="bet",
                                   wall_time=5,
                                   requirements=[fsl509_req])
        bet.inputs.robust = True
        pipeline.connect(fm_mag_reorient, 'out_file', bet, 'in_file')
        create_fmap = pipeline.create_node(PrepareFieldmap(),
                                           name="prepfmap",
                                           wall_time=5,
                                           requirements=[fsl509_req])
        #         create_fmap.inputs.delta_TE = 2.46
        pipeline.connect_input('field_map_delta_te', create_fmap, 'delta_TE')
        pipeline.connect(bet, "out_file", create_fmap, "in_magnitude")
        pipeline.connect(fm_phase_reorient, 'out_file', create_fmap,
                         'in_phase')

        fugue = pipeline.create_node(FUGUE(),
                                     name='fugue',
                                     wall_time=5,
                                     requirements=[fsl509_req])
        fugue.inputs.unwarp_direction = 'x'
        fugue.inputs.dwell_time = self.parameter('fugue_echo_spacing')
        fugue.inputs.unwarped_file = 'example_func.nii.gz'
        pipeline.connect(create_fmap, 'out_fieldmap', fugue, 'fmap_in_file')
        pipeline.connect(reorient_epi_in, 'out_file', fugue, 'in_file')
        pipeline.connect_output('preproc', fugue, 'unwarped_file')
        return pipeline
Exemple #3
0
def test_FUGUE_outputs():
    output_map = dict(fmap_out_file=dict(),
    shift_out_file=dict(),
    unwarped_file=dict(),
    warped_file=dict(),
    )
    outputs = FUGUE.output_spec()

    for key, metadata in output_map.items():
        for metakey, value in metadata.items():
            yield assert_equal, getattr(outputs.traits()[key], metakey), value
Exemple #4
0
def test_FUGUE_outputs():
    output_map = dict(unwarped_file=dict(),
    shift_out_file=dict(),
    fmap_out_file=dict(),
    warped_file=dict(),
    )
    outputs = FUGUE.output_spec()

    for key, metadata in output_map.items():
        for metakey, value in metadata.items():
            yield assert_equal, getattr(outputs.traits()[key], metakey), value
def create_workflow(unwarp_direction='y'):
    workflow = Workflow(name='func_unwarp')

    inputs = Node(
        IdentityInterface(fields=[
            # 'subject_id',
            # 'session_id',
            'funcs',
            'funcmasks',
            'fmap_phasediff',
            'fmap_magnitude',
            'fmap_mask',
        ]),
        name='in')

    outputs = Node(IdentityInterface(fields=[
        'funcs',
        'funcmasks',
    ]),
                   name='out')

    # --- --- --- --- --- --- --- Convert to radians --- --- --- --- --- ---

    # fslmaths $FUNCDIR/"$SUB"_B0_phase -div 100 -mul 3.141592653589793116
    #     -odt float $FUNCDIR/"$SUB"_B0_phase_rescaled

    # in_file --> out_file
    phase_radians = Node(fsl.ImageMaths(
        op_string='-mul 3.141592653589793116 -div 100',
        out_data_type='float',
        suffix='_radians',
    ),
                         name='phaseRadians')

    workflow.connect(inputs, 'fmap_phasediff', phase_radians, 'in_file')

    # --- --- --- --- --- --- --- Unwrap Fieldmap --- --- --- --- --- ---
    # --- Unwrap phase
    # prelude -p $FUNCDIR/"$SUB"_B0_phase_rescaled
    #         -a $FUNCDIR/"$SUB"_B0_magnitude
    #         -o $FUNCDIR/"$SUB"_fmri_B0_phase_rescaled_unwrapped
    #         -m $FUNCDIR/"$SUB"_B0_magnitude_brain_mask
    #  magnitude_file, phase_file [, mask_file] --> unwrapped_phase_file
    unwrap = MapNode(
        PRELUDE(),
        name='unwrap',
        iterfield=['mask_file'],
    )

    workflow.connect([
        (inputs, unwrap, [('fmap_magnitude', 'magnitude_file')]),
        (inputs, unwrap, [('fmap_mask', 'mask_file')]),
        (phase_radians, unwrap, [('out_file', 'phase_file')]),
    ])

    # --- --- --- --- --- --- --- Convert to Radians / Sec --- --- --- --- ---
    # fslmaths $FUNCDIR/"$SUB"_B0_phase_rescaled_unwrapped
    #          -mul 200 $FUNCDIR/"$SUB"_B0_phase_rescaled_unwrapped
    rescale = MapNode(
        fsl.ImageMaths(op_string='-mul 200'),
        name='rescale',
        iterfield=['in_file'],
    )

    workflow.connect(unwrap, 'unwrapped_phase_file', rescale, 'in_file')

    # --- --- --- --- --- --- --- Unmask fieldmap --- --- --- --- ---

    unmask_phase = MapNode(
        FUGUE(
            save_unmasked_fmap=True,
            unwarp_direction=unwarp_direction,
        ),
        name='unmask_phase',
        iterfield=['mask_file', 'fmap_in_file'],
    )

    workflow.connect(rescale, 'out_file', unmask_phase, 'fmap_in_file')
    workflow.connect(inputs, 'fmap_mask', unmask_phase, 'mask_file')

    # --- --- --- --- --- --- --- Undistort functionals --- --- --- --- ---
    # phasemap_in_file = phasediff
    # mask_file = mask
    # in_file = functional image
    # dwell_time = 0.0005585 s
    # unwarp_direction

    undistort = MapNode(
        FUGUE(
            dwell_time=0.0005585,
            # based on Process-NHP-MRI/Process_functional_data.md:
            asym_se_time=0.020,
            smooth3d=2.0,
            median_2dfilter=True,
            unwarp_direction=unwarp_direction,
        ),
        name='undistort',
        iterfield=['in_file', 'mask_file', 'fmap_in_file'],
    )

    workflow.connect(unmask_phase, 'fmap_out_file', undistort, 'fmap_in_file')
    workflow.connect(inputs, 'fmap_mask', undistort, 'mask_file')
    workflow.connect(inputs, 'funcs', undistort, 'in_file')

    undistort_masks = undistort.clone('undistort_masks')
    workflow.connect(unmask_phase, 'fmap_out_file', undistort_masks,
                     'fmap_in_file')
    workflow.connect(inputs, 'fmap_mask', undistort_masks, 'mask_file')
    workflow.connect(inputs, 'funcmasks', undistort_masks, 'in_file')

    workflow.connect(undistort, 'unwarped_file', outputs, 'funcs')

    workflow.connect(undistort_masks, 'unwarped_file', outputs, 'funcmasks')
    return workflow
Exemple #6
0
def test_FUGUE_inputs():
    input_map = dict(args=dict(argstr='%s',
    ),
    asym_se_time=dict(argstr='--asym=%.10f',
    ),
    despike_2dfilter=dict(argstr='--despike',
    ),
    despike_threshold=dict(argstr='--despikethreshold=%s',
    ),
    dwell_time=dict(argstr='--dwell=%.10f',
    ),
    dwell_to_asym_ratio=dict(argstr='--dwelltoasym=%.10f',
    ),
    environ=dict(nohash=True,
    usedefault=True,
    ),
    fmap_in_file=dict(argstr='--loadfmap=%s',
    ),
    fmap_out_file=dict(argstr='--savefmap=%s',
    ),
    forward_warping=dict(usedefault=True,
    ),
    fourier_order=dict(argstr='--fourier=%d',
    ),
    icorr=dict(argstr='--icorr',
    requires=['shift_in_file'],
    ),
    icorr_only=dict(argstr='--icorronly',
    requires=['unwarped_file'],
    ),
    ignore_exception=dict(nohash=True,
    usedefault=True,
    ),
    in_file=dict(argstr='--in=%s',
    ),
    mask_file=dict(argstr='--mask=%s',
    ),
    median_2dfilter=dict(argstr='--median',
    ),
    no_extend=dict(argstr='--noextend',
    ),
    no_gap_fill=dict(argstr='--nofill',
    ),
    nokspace=dict(argstr='--nokspace',
    ),
    output_type=dict(),
    pava=dict(argstr='--pava',
    ),
    phase_conjugate=dict(argstr='--phaseconj',
    ),
    phasemap_in_file=dict(argstr='--phasemap=%s',
    ),
    poly_order=dict(argstr='--poly=%d',
    ),
    save_fmap=dict(xor=['save_unmasked_fmap'],
    ),
    save_shift=dict(xor=['save_unmasked_shift'],
    ),
    save_unmasked_fmap=dict(argstr='--unmaskfmap',
    xor=['save_fmap'],
    ),
    save_unmasked_shift=dict(argstr='--unmaskshift',
    xor=['save_shift'],
    ),
    shift_in_file=dict(argstr='--loadshift=%s',
    ),
    shift_out_file=dict(argstr='--saveshift=%s',
    ),
    smooth2d=dict(argstr='--smooth2=%.2f',
    ),
    smooth3d=dict(argstr='--smooth3=%.2f',
    ),
    terminal_output=dict(nohash=True,
    ),
    unwarp_direction=dict(argstr='--unwarpdir=%s',
    ),
    unwarped_file=dict(argstr='--unwarp=%s',
    requires=['in_file'],
    xor=['warped_file'],
    ),
    warped_file=dict(argstr='--warp=%s',
    requires=['in_file'],
    xor=['unwarped_file'],
    ),
    )
    inputs = FUGUE.input_spec()

    for key, metadata in input_map.items():
        for metakey, value in metadata.items():
            yield assert_equal, getattr(inputs.traits()[key], metakey), value
Exemple #7
0
def test_FUGUE_inputs():
    input_map = dict(ignore_exception=dict(nohash=True,
    usedefault=True,
    ),
    dwell_time=dict(argstr='--dwell=%.10f',
    ),
    asym_se_time=dict(argstr='--asym=%.10f',
    ),
    smooth3d=dict(argstr='--smooth3=%.2f',
    ),
    no_gap_fill=dict(argstr='--nofill',
    ),
    forward_warping=dict(usedefault=True,
    ),
    phasemap_file=dict(argstr='--phasemap=%s',
    ),
    save_shift=dict(),
    poly_order=dict(argstr='--poly=%d',
    ),
    shift_in_file=dict(argstr='--loadshift=%s',
    ),
    shift_out_file=dict(hash_files=False,
    argstr='--saveshift=%s',
    ),
    median_2dfilter=dict(argstr='--median',
    ),
    save_unmasked_shift=dict(requires=['shift_out_file'],
    argstr='--unmaskshift',
    ),
    despike_2dfilter=dict(argstr='--despike',
    ),
    save_unmasked_fmap=dict(requires=['fmap_out_file'],
    argstr='--unmaskfmap',
    ),
    in_file=dict(argstr='--in=%s',
    ),
    warped_file=dict(hash_files=False,
    argstr='--warp=%s',
    ),
    dwell_to_asym_ratio=dict(argstr='--dwelltoasym=%.10f',
    ),
    unwarped_file=dict(argstr='--unwarp=%s',
    hash_files=False,
    genfile=True,
    ),
    icorr_only=dict(requires=['unwarped_file'],
    argstr='--icorronly',
    ),
    smooth2d=dict(argstr='--smooth2=%.2f',
    ),
    phase_conjugate=dict(argstr='--phaseconj',
    ),
    pava=dict(argstr='--pava',
    ),
    args=dict(argstr='%s',
    ),
    terminal_output=dict(mandatory=True,
    nohash=True,
    ),
    output_type=dict(),
    despike_theshold=dict(argstr='--despikethreshold=%s',
    ),
    icorr=dict(requires=['shift_in_file'],
    argstr='--icorr',
    ),
    fmap_in_file=dict(argstr='--loadfmap=%s',
    ),
    unwarp_direction=dict(argstr='--unwarpdir=%s',
    ),
    fmap_out_file=dict(hash_files=False,
    argstr='--savefmap=%s',
    ),
    environ=dict(nohash=True,
    usedefault=True,
    ),
    mask_file=dict(argstr='--mask=%s',
    ),
    no_extend=dict(argstr='--noextend',
    ),
    fourier_order=dict(argstr='--fourier=%d',
    ),
    nokspace=dict(argstr='--nokspace',
    ),
    )
    inputs = FUGUE.input_spec()

    for key, metadata in input_map.items():
        for metakey, value in metadata.items():
            yield assert_equal, getattr(inputs.traits()[key], metakey), value
Exemple #8
0
def topup(blip_up_file,
          blip_down_file,
          blip_up_phase_enc_dir,
          blip_down_phase_enc_dir,
          outdir,
          fsl_sh,
          apply_to=None,
          unwarp_direction=None,
          dwell_time=None,
          verbose=0):
    """ Bias field correction using topup.

    Note: we do not set the total readout times for both acquisitons, and we
    expect that the readout time is identical for all acquisitions. This 
    parameter simply serves to ensure that the estimated field is correctly
    scaled in Hz, but it doesn't affect the result in terms of undistorted
    images. We set it to 1, meaning that the field will be scaled as 'voxels 
    displacement' instead.

    Parameters
    ----------
    blip_up_file:  str
        path to EPI file acquired in opposite phase enc. directions: blip up.
    blip_down_file:  str
        path to EPI file acquired in opposite phase enc. directions: blip down.
    blip_up_phase_enc_dir: str
        the phase enc. direction for the blip up.
    blip_down_phase_enc_dir: str
        the phase enc. direction for the blip down.
    phase_enc_dirs: list of str
        the phase enc. directions.
    outdir: str
        directory for outputs.
    fsl_sh: str
        path to fsl setup sh file.
    apply_to: str, default None
        apply the topup correction to the EPI volume.
    unwarp_direction: str, default None
        apply topup correction in this direction.
    dwell_time: float, default None
        set the EPI dwell time per phase-encode line, same as echo spacing (ms).
    verbose: int, default 0
        control the verbosity level.

    Returns
    -------
    fieldmap_hz_file: str
        the fieldmap in Hz
    unwarped_epi_file: str
        unwarped EPI file.
    """
    # Call topup
    fieldmap_hz_file, _, _ = _topup(
        b0s=[blip_up_file, blip_down_file],
        phase_enc_dirs=[blip_up_phase_enc_dir, blip_down_phase_enc_dir],
        readout_time=1,
        outroot=outdir,
        apply_to=None,
        fsl_sh=fsl_sh)

    # Convert the fieldmap in rad/s to Hz
    fieldmap_file = fieldmap_hz_file.replace(".nii.gz", "_rads.nii.gz")
    cmd = ["fslmaths", fieldmap_hz_file, "-mul", "6.28", fieldmap_file]
    fslprocess = FSLWrapper(shfile=fsl_sh)
    fslprocess(cmd=cmd)

    # Update env
    fslenv = environment(fsl_sh)
    if (fslenv["FSLDIR"] != os.environ.get("FSLDIR", "")):
        os.environ = concat_environment(os.environ, fslenv)

    # Apply topup
    # Unwarping an input image (fieldmap in rad/s is known)
    unwarp_direction = DIR_MAP[unwarp_direction]
    unwarped_epi_file = os.path.join(outdir, "unwarped_epi_file.nii.gz")
    fugue = FUGUE()
    fugue.inputs.in_file = apply_to
    fugue.inputs.fmap_in_file = fieldmap_file
    fugue.inputs.unwarp_direction = unwarp_direction
    fugue.inputs.unwarped_file = unwarped_epi_file
    fugue.inputs.dwell_time = dwell_time * 1e-3
    fugue.inputs.output_type = "NIFTI_GZ"
    if verbose > 0:
        print(fugue.cmdline)
    returncode = fugue.run()

    return fieldmap_hz_file, unwarped_epi_file
Exemple #9
0
def fugue(epi_file,
          phase_file,
          magnitude_file,
          delta_te,
          dwell_time,
          unwarp_direction,
          manufacturer,
          outdir,
          fsl_sh,
          verbose=0):
    """ Unwarping of an EPI image based on fieldmap data using fugue.

    Note: Brain extraction of the EPI image is very important and must be
    tight - that is, it must exclude all non-brain voxels and any voxels with
    only a small partial volume contribution. The reason for this is that
    these areas are normally very noisy in the phase image. The exclusion
    of brain voxels is actually fine and will have no repercussions, since the
    fieldmap is extrapolated beyond this mask.

    Note: If parallel acceleration is used in the EPI acquisition then the
    *effective* echo spacing (dwell time) is the actual echo spacing between
    acquired lines in k-space divided by the acceleration factor.

    Parameters
    ----------
    epi_file: str
        the EPI file to unwarp.
    phase_file: str
        the phase image in the EPI space.
    magnitude_file: str
        the magnitude image in the EPI space.
    delta_te: float
        the echo time difference of the fieldmap sequence - find this out form
        the operator (defaults are *usually* 2.46ms on SIEMENS).
    dwell_time: float
        set the EPI dwell time per phase-encode line, same as echo spacing (ms).
    unwarp_direction: str
        specifies direction of warping: ('x' or 'y' or 'z' or 'x-' or 'y-'
        or 'z-')
    manufacturer: str
        must be SIEMENS.
    outdir: str
        directory for outputs.
    fsl_sh: str
        path to fsl setup sh file.
    verbose: int, default 0
        control the verbosity level.

    Returns
    -------
    magnitude_brain_mask_file: str
        the brain mask.
    vsm_file: str
        voxel shift map file.
    unwarped_epi_file: str
        unwarped EPI file.
    """
    # Extract brain
    avgmagnitude_file = os.path.join(outdir, "avgmag.nii.gz")
    average_timeserie(magnitude_file, avgmagnitude_file, fslconfig=fsl_sh)
    outputs = bet2(avgmagnitude_file, outdir, mask=True, f=0.35, shfile=fsl_sh)
    #outputs = bet2(outputs[0], outdir, mask=True, f=0.6, shfile=fsl_sh)
    magnitude_brain_file, magnitude_brain_mask_file = outputs[:2]

    # Update env
    fslenv = environment(fsl_sh)
    if (fslenv["FSLDIR"] != os.environ.get("FSLDIR", "")):
        os.environ = concat_environment(os.environ, fslenv)

    # Prepare a rad/s fieldmap
    fieldmap_file = os.path.join(outdir, "fieldmap.nii.gz")
    fieldmap_file, fieldmap_hz_file = fsl_prepare_fieldmap(
        manufacturer=manufacturer.upper(),
        phase_file=phase_file,
        brain_magnitude_file=magnitude_brain_file,
        output_file=fieldmap_file,
        delta_te=str(delta_te),
        fsl_sh=fsl_sh)

    # Computing the vsm (unwrapped phase map is known)
    unwarp_direction = DIR_MAP[unwarp_direction]
    vsm_file = os.path.join(outdir, "vsm.nii.gz")
    fugue = FUGUE()
    fugue.inputs.fmap_in_file = fieldmap_file
    fugue.inputs.mask_file = magnitude_brain_mask_file
    fugue.inputs.dwell_time = dwell_time * 1e-3
    fugue.inputs.asym_se_time = delta_te * 1e-3
    fugue.inputs.unwarp_direction = unwarp_direction
    fugue.inputs.save_unmasked_shift = True
    fugue.inputs.shift_out_file = vsm_file
    fugue.inputs.smooth2d = 2
    fugue.inputs.output_type = "NIFTI_GZ"
    fugue.environ = {}
    if verbose > 0:
        print(fugue.cmdline)
    returncode = fugue.run()
    #outputs = returncode.outputs.get()
    #vsm_file = outputs["shift_out_file"]

    # Unwarping an input image (shift map is known)
    unwarped_epi_file = os.path.join(outdir, "unwarped_epi_file.nii.gz")
    fugue = FUGUE()
    fugue.inputs.in_file = epi_file
    fugue.inputs.mask_file = magnitude_brain_mask_file
    fugue.inputs.shift_in_file = vsm_file
    fugue.inputs.unwarp_direction = unwarp_direction
    fugue.inputs.unwarped_file = unwarped_epi_file
    fugue.inputs.output_type = "NIFTI_GZ"
    if verbose > 0:
        print(fugue.cmdline)
    returncode = fugue.run()
    #outputs = returncode.outputs.get()
    #unwarped_epi_file = outputs["unwarped_file"]

    return magnitude_brain_mask_file, vsm_file, unwarped_epi_file