Exemplo n.º 1
0
def test_convertwarp():
    with asrt.disabled(), run.dryrun(), mockFSLDIR(
            bin=('convertwarp', )) as fsldir:
        cnvwarp = op.join(fsldir, 'bin', 'convertwarp')
        result = fw.convertwarp('out', 'ref', absout=True, jacobian='jacobian')
        expected = (cnvwarp + ' --ref=ref --out=out', ('--absout',
                                                       '--jacobian=jacobian'))
        assert checkResult(result.stdout[0], *expected)
Exemplo n.º 2
0
def get_fieldmap_correction(wsp):
    """
    Get the fieldmap based distortion correction warp

    Required workspace attributes
    -----------------------------

     - ``pwi``          : Perfusion weighted image (generated by preproc_asl)
     - ``fmap``         : Fieldmap image
     - ``fmapmag``      : Fieldmap magnitude image
     - ``fmapmagbrain`` : Fieldmap magnitude brain image
     - ``echospacing``  :
     - ``pedir``        :

    Optional workspace attributes
    -----------------------------

     - ``nofmapreg``       : If True assume fieldmap in structural space

    Updated workspace attributes
    ----------------------------

     - ``fmap_warp``    : Fieldmap distortion correction warp image in ASL space
    """
    if wsp.fmap is None or wsp.fmapmag is None or wsp.fmapmagbrain is None:
        wsp.log.write(" - No fieldmap images for distortion correction\n")
        return
    elif wsp.pedir is None or wsp.echospacing is None:
        wsp.log.write(
            " -WARNING: Fieldmap images supplied but pedir and echospacing required for distortion correction\n"
        )
        return

    wsp.sub("fieldmap")
    wsp.log.write(
        " - Calculating distortion correction from fieldmap images using EPI_REG\n"
    )

    epi_reg_opts = {
        "inweight": wsp.inweight,
        "init": wsp.reg.asl2struc,
        "fmap": wsp.fmap,
        "fmapmag": wsp.fmapmag,
        "fmapmagbrain": wsp.fmapmagbrain,
        "pedir": wsp.pedir,
        "echospacing": wsp.echospacing,
        "nofmapreg": wsp.ifnone("nofmapreg", False),
    }

    # Windows can't run epi_reg as it's a batch script. Use our experimental python
    # implementation but use the standard epi_reg on other platforms until the python
    # version is better tested
    if sys.platform.startswith("win"):
        import oxasl.epi_reg as pyepi
        result = pyepi.epi_reg(wsp, epi=wsp.reg.nativeref, **epi_reg_opts)
    else:
        result = epi_reg(epi=wsp.asldata.perf_weighted(),
                         t1=wsp.structural.struc,
                         t1brain=wsp.structural.brain,
                         out=fsl.LOAD,
                         wmseg=wsp.structural.wm_seg,
                         log=wsp.fsllog,
                         **epi_reg_opts)

    # Occasionally we end up with NaN in the output of epi_reg and this will ruin the entire distcorr warp.
    # So remove any NaN values and replace with zero.
    warp_struc = result["out_warp"]
    wsp.fieldmap.warp_struc = Image(np.nan_to_num(warp_struc.data, nan=0),
                                    header=warp_struc.header)
    wsp.fieldmap.asl2struc = result["out"]
    wsp.fieldmap.struc2asl = np.linalg.inv(wsp.fieldmap.asl2struc)

    result = fsl.convertwarp(out=fsl.LOAD,
                             ref=wsp.reg.nativeref,
                             warp1=wsp.fieldmap.warp_struc,
                             postmat=wsp.fieldmap.struc2asl,
                             rel=True,
                             log=wsp.fsllog)
    wsp.fieldmap.warp = result["out"]

    page = wsp.report.page("fmap")
    page.heading("Fieldmap distortion correction", level=0)
    page.text("PE direction: %s" % wsp.pedir)
    page.text("Echo spacing: %f s" % wsp.echospacing)
    page.heading("Correction warps", level=1)
    for dim in range(3):
        img = Image(wsp.fieldmap.warp.data[..., dim],
                    header=wsp.fieldmap.warp.header)
        page.text("Dimension %i" % dim)
        page.image("fmap_warp%i" % dim, LightboxImage(img))
Exemplo n.º 3
0
def run(wsp):
    """
    Apply distortion and motion corrections to ASL and calibration data

    Required workspace attributes
    -----------------------------

     - ``asldata_orig`` : Uncorrected ASL data image

    Optional workspace attributes
    -----------------------------

     - ``calib_orig``      : Calibration image
     - ``cref_orig``       : Calibration reference image
     - ``cblip_orig``      : Calibration BLIP image
     - ``asldata_mc_mats`` : ASL motion correction matrices
     - ``calib2asl``       : Calibration -> ASL transformation matrix
     - ``distcorr_warp``   : Distortion correction warp image
     - ``gdc_warp``        : Gradient distortion correction warp image

    Updated workspace attributes
    ----------------------------

     - ``asldata``    : Corrected ASL data
     - ``calib``      : Corrected calibration image
     - ``cref``       : Corrected calibration reference image
     - ``cblip``      : Corrected calibration BLIP image
    """
    wsp.sub("corrected")
    wsp.log.write("\nApplying data corrections\n")

    warps, moco_mats = [], None

    if wsp.moco is not None:
        wsp.log.write(" - Using motion correction\n")
        moco_mats = wsp.moco.mc_mats

    if wsp.distcorr is not None:
        if wsp.distcorr.fieldmap is not None:
            wsp.log.write(" - Using fieldmap distortion correction\n")
            warps.append(wsp.distcorr.fieldmap.warp)

        if wsp.distcorr.gdc_warp:
            wsp.log.write(" - Using user-supplied GDC warp\n")
            warps.distcorr.append(wsp.gdc_warp)

    if warps:
        kwargs = {}
        for idx, warp in enumerate(warps):
            kwargs["warp%i" % (idx + 1)] = warp

        wsp.log.write(
            " - Converting all warps to single transform and extracting Jacobian\n"
        )
        result = fsl.convertwarp(ref=wsp.reg.nativeref,
                                 out=fsl.LOAD,
                                 rel=True,
                                 jacobian=fsl.LOAD,
                                 log=wsp.fsllog,
                                 **kwargs)
        wsp.corrected.total_warp = result["out"]

        # Calculation of the jacobian for the warp - method suggested in:
        # https://www.jiscmail.ac.uk/cgi-bin/webadmin?A2=FSL;d3fee1e5.0908
        wsp.corrected.warp_coef = fnirtfileutils(wsp.corrected.total_warp,
                                                 outformat="spline",
                                                 out=fsl.LOAD,
                                                 log=wsp.fsllog)["out"]
        jacobian = fnirtfileutils(wsp.corrected.warp_coef,
                                  jac=fsl.LOAD,
                                  log=wsp.fsllog)["jac"]
        wsp.corrected.jacobian = Image(jacobian.data,
                                       header=wsp.corrected.total_warp.header)

    if not warps and moco_mats is None:
        wsp.log.write(" - No corrections to apply to ASL data\n")
        wsp.corrected.asldata = wsp.preproc.asldata
    else:
        # Apply all corrections to ASL data - note that we make sure the output keeps all the ASL metadata
        wsp.log.write(" - Applying corrections to ASL data\n")
        asldata_corr = correct_img(wsp, wsp.preproc.asldata, moco_mats)
        wsp.corrected.asldata = wsp.preproc.asldata.derived(asldata_corr.data)

    if wsp.preproc.calib is not None:
        # Apply corrections to calibration images if we have calib2asl registration and any other correction
        if not warps and wsp.reg is None:
            wsp.log.write(" - No corrections to apply to calibration data\n")
            wsp.corrected.calib = wsp.preproc.calib
            if wsp.cref is not None:
                wsp.corrected.cref = wsp.preproc.cref
            if wsp.cblip is not None:
                wsp.corrected.cblip = wsp.preproc.cblip
        else:
            wsp.log.write(" - Applying corrections to calibration data\n")
            wsp.corrected.calib = correct_img(wsp, wsp.preproc.calib,
                                              wsp.reg.calib2asl)

            if wsp.cref is not None:
                wsp.corrected.cref = correct_img(wsp, wsp.preproc.cref,
                                                 wsp.reg.calib2asl)
            if wsp.cblip is not None:
                wsp.corrected.cblip = correct_img(wsp, wsp.preproc.cblip,
                                                  wsp.reg.calib2asl)

    if wsp.distcorr is not None and wsp.distcorr.topup is not None:
        wsp.log.write(" - Adding TOPUP distortion correction\n")
        # This can't currently be done using the FSL wrappers - we need the TOPUP output as two prefixed files
        # Only workaround currently is to create a temp directory to store appropriately named input files
        topup_input = tempfile.mkdtemp(prefix="topup_input")
        try:
            wsp.distcorr.topup.fieldcoef.save("%s/topup_fieldcoef" %
                                              topup_input)
            movpar_file = open("%s/topup_movpar.txt" % topup_input, "w")
            for row in wsp.distcorr.topup.movpar:
                movpar_file.write("\t".join([str(val) for val in row]) + "\n")
            movpar_file.close()
            # TOPUP does not do the jacobian magntiude correction - so only okay if using voxelwise calibration
            wsp.corrected.calib = fsl.applytopup(
                wsp.corrected.calib,
                datain=wsp.distcorr.topup.params,
                index=1,
                topup="%s/topup" % topup_input,
                out=fsl.LOAD,
                method="jac",
                log=wsp.fsllog)["out"]
            if wsp.cref is not None:
                wsp.corrected.cref = fsl.applytopup(
                    wsp.corrected.cref,
                    datain=wsp.distcorr.topup.params,
                    index=1,
                    topup="%s/topup" % topup_input,
                    out=fsl.LOAD,
                    method="jac",
                    log=wsp.fsllog)["out"]
            if wsp.cblip is not None:
                wsp.corrected.cblip = fsl.applytopup(
                    wsp.corrected.cblip,
                    datain=wsp.distcorr.topup.params,
                    index=2,
                    topup="%s/topup" % topup_input,
                    out=fsl.LOAD,
                    method="jac",
                    log=wsp.fsllog)["out"]
            post_topup = fsl.applytopup(wsp.corrected.asldata,
                                        datain=wsp.distcorr.topup.params,
                                        index=1,
                                        topup="%s/topup" % topup_input,
                                        out=fsl.LOAD,
                                        method="jac",
                                        log=wsp.fsllog)["out"]
            wsp.corrected.asldata = wsp.corrected.asldata.derived(
                post_topup.data)
            # FIXME warning below
            # FIXME do we need to correct anything else in ASL or calibration space, e.g. mask, reference region mask
            #if wsp.calib_method != "voxel":
            #    wsp.log.write("WARNING: Using TOPUP does not correct for magntiude using the jocbian in distortion correction")
            #    wsp.log.write("         This is not optimal when not using voxelwise calibration\n")
            #    wsp.log.write("         To avoid this supply structural image(s)\n")
        finally:
            shutil.rmtree(topup_input)
Exemplo n.º 4
0
def epi_reg(wsp, epi_img, use_fmap=False, **kwargs):
    """
    Do EPI registration
    """
    struc.segment(wsp)
    wmseg = wsp.structural.wm_seg
    bbr_sch = os.path.join(os.environ["FSLDIR"], "etc/flirtsch/bbr.sch")

    if wsp.asl2struc is None:
        # Do pre-alignment in the same was as epi_reg
        wsp.asl2struc = fsl.flirt(epi_img,
                                  ref=wsp.structural.brain,
                                  omat=fsl.LOAD,
                                  dof=6,
                                  log=wsp.fsllog)["omat"]

    if not use_fmap:
        wsp.log.write(" - Running BBR\n")
        trans = fsl.flirt(epi_img,
                          ref=wsp.structural.struc,
                          dof=6,
                          cost="bbr",
                          wmseg=wmseg,
                          init=wsp.asl2struc,
                          omat=fsl.LOAD,
                          out=fsl.LOAD,
                          schedule=bbr_sch,
                          log=wsp.fsllog)["omat"]
        out_img = fsl.applywarp(epi_img,
                                ref=wsp.structural.struc,
                                out=fsl.LOAD,
                                premat=trans,
                                interp="spline",
                                log=wsp.fsllog)["out"]
        return {"out.nii.gz": out_img, "out": trans}
    else:
        dirmap = {
            "x": (1, "x"),
            "y": (2, "y"),
            "z": (3, "z"),
            "-x": (-1, "x-"),
            "-y": (-2, "y-"),
            "-z": (-3, "z-"),
            "x-": (-1, "x-"),
            "y-": (-2, "y-"),
            "z-": (-3, "z-"),
        }
        pedir, fdir = dirmap.get(wsp.pedir, (None, None))
        if pedir is None:
            raise ValueError("Invalid phase encode direction specified: %s" %
                             wsp.pedir)

        if wsp.nofmapreg:
            wsp.fmap2struc = np.identity(4)
            wsp.fmapmag_struc = wsp.fmapmag
        else:
            # Register fmap to structural image
            wsp.log.write(" - Registering fieldmap to structural\n")
            wsp.fmap2struc = fsl.flirt(wsp.fmapmagbrain,
                                       ref=wsp.structural.brain,
                                       dof=6,
                                       omat=fsl.LOAD)["omat"]
            flirt_result = fsl.flirt(wsp.fmapmag,
                                     ref=wsp.structural.struc,
                                     dof=6,
                                     init=wsp.fmap2struc,
                                     omat=fsl.LOAD,
                                     out=fsl.LOAD,
                                     nosearch=True)
            wsp.fmap2struc = flirt_result["omat"]
            wsp.fmapmag_struc = flirt_result["out"]

        # Unmask the fieldmap (necessary to avoid edge effects)
        wsp.fmap_mask = fsl.fslmaths(wsp.fmapmagbrain).abs().bin().run()
        wsp.fmap_mask = fsl.fslmaths(wsp.fmap).abs().bin().mul(
            wsp.fmap_mask).run()

        # The direction here should take into account the initial affine (it needs to be the direction in the EPI)
        wsp.fmap_unmasked = fsl.fugue(loadfmap=wsp.fmap,
                                      mask=wsp.fmap_mask,
                                      unmaskfmap=True,
                                      savefmap=fsl.LOAD,
                                      unwarpdir=fdir)["out"]

        # The following is a NEW HACK to fix extrapolation when fieldmap is too small
        wsp.fmap_struc_pad0 = fsl.applywarp(wsp.fmap_unmasked,
                                            ref=wsp.structural.struc,
                                            premat=wsp.fmap2struc,
                                            out=fsl.LOAD)["out"]
        wsp.fmap_struc_innermask = fsl.fslmaths(
            wsp.fmap_struc_pad0).abs().bin().run()
        wsp.fmap_struc_dilated = fsl.fugue(loadfmap=wsp.fmap_struc_pad0,
                                           mask=wsp.fmap_struc_innermask,
                                           unmaskfmap=True,
                                           unwarpdir=fdir,
                                           savefmap=fsl.LOAD)["savefmap"]
        wsp.fmap_struc = wsp.fmap_struc_dilated

        # Run bbr with fieldmap
        wsp.log.write("Running BBR with fieldmap\n")
        if not wsp.epi_reg_use_weighting:
            refweight = None

        wsp.reg.epi2struc = fsl.flirt(epi_img,
                                      ref=wsp.structural.struc,
                                      dof=6,
                                      cost="bbr",
                                      wmseg=wmseg,
                                      init=wsp.reg.asl2struc,
                                      omat=fsl.LOAD,
                                      schedule=bbr_sch,
                                      echospacing=wsp.echospacing,
                                      pedir=pedir,
                                      fieldmap=wsp.fmap_struc,
                                      refweight=refweight)["omat"]

        # Make equivalent warp fields
        wsp.log.write(
            "Making warp fields and applying registration to EPI series\n")
        wsp.reg.struc2epi = np.linalg.inv(wsp.reg.epi2struc)
        fsl.concatxfm(wsp.reg.struc2epi, wsp.fmap2struc, outmat=fsl.LOAD)
        fsl.applywarp(wsp.fmap, ref=epi_img, premat=wsp.fmap2epi, out=fsl.LOAD)
        wsp.fmap2epi_mask = fsl.fslmaths(wsp.fmap2epi).abs().bin().run()
        # ${vout}_fieldmaprads2epi -abs -bin ${vout}_fieldmaprads2epi_mask
        ret = fsl.fugue(loadfmap=wsp.fmap2epi,
                        mask=wsp.fmap2epi_mask,
                        saveshift=fsl.LOAD,
                        unmaskshift=True,
                        dwell=wsp.dwell,
                        unwarpdir=fdir)
        print(ret)
        wsp.fmap2epi_shift = ret["fieldmaprads2epi_shift"]
        ret = fsl.convertwarp(wsp.structural.struc,
                              s=wsp.fmap2epi_shift,
                              postmat=wsp.epi2struc,
                              out=fsl.LOAD,
                              shiftdir=fdir,
                              relout=True)
        print(ret)
        warp = ret["out"]
        ret = fsl.applywarp(epi_img,
                            ref=wsp.structural.struc,
                            out=fsl.LOAD,
                            warp1=warp,
                            interp="spline",
                            rel=True)
        print(ret)
        return ret["out"], warp