Esempio n. 1
0
def reg_bbr(wsp):
    """
    Perform BBR registration

    :param reg_img: Data to register, e.g. PWI or calibration image. Normally would be brain extracted
    :param struc_img: Structural image
    :param struc_brain_img: Brain-extracted structural image

    Optional keyword arguments:

    :param inweight:
    :param init: Initial transform matrix

    Optional keyword arguments for fieldmap distortion correction:

    :param fmap: Fieldmap image
    :param fmapmag: Fieldmap magnitude image
    :param fmapmagbrain: Fieldmap magnitude image - brain extracted
    :param pedir: Phase encoding direction (x, -x, y, -y, z, -z)
    :param echospacing: Echo spacing

    :return Tuple of registered image, transform matrix
    """
    struc.segment(wsp)

    wsp.log.write("  - BBR registration using epi_reg...")
    # 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, wsp.reg.nativeref)
    else:
        result = epi_reg(epi=wsp.reg.nativeref,
                         t1=wsp.structural.struc,
                         t1brain=wsp.structural.brain,
                         out=fsl.LOAD,
                         wmseg=wsp.structural.wm_seg,
                         init=wsp.reg.asl2struc,
                         inweight=wsp.inweight,
                         log=wsp.fsllog)
    wsp.log.write(" DONE\n")
    return result["out%s" % defaultExt()], result["out"]
Esempio n. 2
0
def get_rois(wsp):
    """
    Generate ROIs for GM and noise
    
    Existing ROIs may be provided. If provided in structural space, the ASL data is registered
    to the structural image and the ROIS will be transformed to ASL space

    If (either) of the noise or GM ROIs are not provided they are automatically generated as follows

     - Grey matter: From segmentation of structural image (via FAST or FSL_ANAT output if provided)
     - Noise: By inverting brain mask from brain-extracted structural image

    A structural image is therefore required if either ROI needs to be generated, or if either ROI
    is supplied in structural space. 

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

     - ``regfrom`` : Reference image for registration of ASL to structural data
     - ``asldata`` : Single TI ASL data. Middle volume will be used as reference if ``regfrom`` is required and not set
     - ``gm_roi`` : Grey matter ROI in ASL or structural space
     - ``noise_roi`` : Noise ROI in ASL or structural space
     - ``noise_from_struc`` : If True, existing ``noise_roi`` image is in structural space
     - ``gm_from_struc`` : If True, existing ``gm_roi`` image is in structural space
     - ``struc`` : Structural image
     
    Workspace attributes set
    ------------------------

     - ``gm_roi`` : Grey matter ROI in ASL space
     - ``noise_roi`` : Noise ROI in ASL space
    """
    wsp.log.write("Generating ROIs...\n")

    if wsp.regfrom is None:
        wsp.log.write(" - Reference image for registration not provided - using ASL data middle volume\n")
        middle = int(wsp.asldata.shape[3]/2)
        wsp.regfrom = Image(wsp.asldata.data[:, :, :, middle], header=wsp.asldata.header)
        
    struc.init(wsp)
    if (wsp.gm_roi is None or wsp.noise_roi is None or wsp.noise_from_struc or wsp.gm_from_struc) and wsp.structural.struc is None:
        raise RuntimeError("Need to specify a structural image unless you provide both noise and GM ROIs in ASL space")

    if wsp.gm_roi is None:
        struc.segment(wsp)
        wsp.log.write("Taking GM ROI from segmentation of structural image\n")
        wsp.gm_roi = Image((wsp.structural.gm_pv.data > 0).astype(np.int), header=wsp.structural.struc.header)
        wsp.gm_from_struc = True

    if wsp.noise_roi is None:
        wsp.log.write("Generating noise ROI by inverting T1 brain mask\n")
        wsp.noise_roi = Image(1-wsp.structural.brain_mask.data, header=wsp.structural.struc.header)
        wsp.noise_from_struc = True

    if wsp.noise_from_struc or wsp.gm_from_struc:
        # Need struc->ASL registration space so we can apply to noise and/or GM ROIs
        wsp.do_flirt = True
        wsp.do_bbr = False
        reg.reg_asl2struc(wsp)

    if wsp.noise_from_struc:
        wsp.log.write(" - Registering noise ROI to ASL space since it was defined in structural space\n\n")
        wsp.noise_roi_struc = wsp.noise_roi
        wsp.noise_roi = reg.struc2asl(wsp, wsp.noise_roi_struc, interp="nn")

    if wsp.gm_from_struc:
        wsp.log.write(" - Registering GM ROI to ASL space since it was defined in structural space\n\n")
        wsp.gm_roi_struc = wsp.gm_roi
        wsp.gm_roi = reg.struc2asl(wsp, wsp.gm_roi_struc, interp="nn")

    wsp.log.write("DONE\n\n")
Esempio n. 3
0
def model_basil(wsp):
    """
    Do model fitting on TC/CT or subtracted data

    Workspace attributes updated
    ----------------------------

     - ``basil``         - Contains model fitting output on data without partial volume correction
     - ``basil_pvcorr``  - Contains model fitting output with partial volume correction if
                           ``wsp.pvcorr`` is ``True``
     - ``output.native`` - Native (ASL) space output from last Basil modelling output
     - ``output.struc``  - Structural space output
    """
    wsp.basil_options = wsp.ifnone("basil_options", {})

    basil.basil(wsp, output_wsp=wsp.sub("basil"))
    redo_reg(wsp, wsp.basil.finalstep.mean_ftiss)

    wsp.sub("output")
    output_native(wsp.output, wsp.basil)
    output_trans(wsp.output)

    # If the user has provided manual PV maps (pvgm and pvgm) then do PVEc, even if they
    # have not explicitly given the --pvcorr option
    user_pv_flag = ((wsp.pvwm is not None) and (wsp.pvgm is not None))
    if (wsp.pvcorr) or (wsp.surf_pvcorr) or user_pv_flag:
        # Partial volume correction is very sensitive to the mask, so recreate it
        # if it came from the structural image as this requires accurate ASL->Struc registration
        if wsp.rois.mask_src == "struc":
            wsp.rois.mask_orig = wsp.rois.mask
            wsp.rois.mask = None
            mask.generate_mask(wsp)

        if wsp.pvcorr or user_pv_flag:
            # Do partial volume correction fitting
            #
            # FIXME: We could at this point re-apply all corrections derived from structural space?
            # But would need to make sure corrections module re-transforms things like sensitivity map

            # Prepare GM and WM partial volume maps from FAST segmentation
            if user_pv_flag:
                wsp.log.write("\nUsing user-supplied PV estimates\n")
                wsp.structural.wm_pv_asl = wsp.pvwm
                wsp.structural.gm_pv_asl = wsp.pvgm
            else:
                struc.segment(wsp)
                wsp.structural.wm_pv_asl = reg.struc2asl(
                    wsp, wsp.structural.wm_pv)
                wsp.structural.gm_pv_asl = reg.struc2asl(
                    wsp, wsp.structural.gm_pv)

            wsp.basil_options.update({
                "pwm": wsp.structural.wm_pv_asl,
                "pgm": wsp.structural.gm_pv_asl
            })
            basil.basil(wsp, output_wsp=wsp.sub("basil_pvcorr"), prefit=False)

            wsp.sub("output_pvcorr")
            output_native(wsp.output_pvcorr, wsp.basil_pvcorr)
            output_trans(wsp.output_pvcorr)

        if wsp.surf_pvcorr:
            if oxasl_surfpvc is None:
                raise RuntimeError(
                    "Surface-based PVC requested but oxasl_surfpvc is not installed"
                )
            if user_pv_flag:
                wsp.log.write(
                    " - WARNING: Performing surface based PVC ignores user-specified PV maps\n"
                )
            # Prepare GM and WM partial volume maps from surface using Toblerone plugin
            # Then reform the ASL ROI mask - Toblerone does not handle the cerebellum so need
            # to mask it out
            oxasl_surfpvc.prepare_surf_pvs(wsp)
            wsp.rois.mask_pvcorr = wsp.rois.mask
            min_pv = 0.01
            new_roi = (wsp.basil_options["pwm"].data >
                       min_pv) | (wsp.basil_options["pgm"].data > min_pv)
            wsp.rois.mask = Image(new_roi.astype(np.int8),
                                  header=wsp.rois.mask_pvcorr.header)
            basil.basil(wsp,
                        output_wsp=wsp.sub("basil_surf_pvcorr"),
                        prefit=False)

            wsp.sub('output_surf_pvcorr')
            output_native(wsp.output_surf_pvcorr, wsp.basil_surf_pvcorr)
            output_trans(wsp.output_surf_pvcorr)
Esempio n. 4
0
def get_sensitivity_correction(wsp):
    """
    Get sensitivity correction image

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

     - ``asldata`` : ASL data

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

     - ``isen`` : User supplied sensitivity image
     - ``cact`` : Calibration image. Used in conjunction with ``cref`` to calculate sensitivity map
     - ``calib`` : Calibration image. Used as alternative to cact provided ``mode`` is ``longtr``
     - ``cref`` : Calibration reference image
     - ``senscorr_auto`` : If True, automatically calculate sensitivity correction using FAST
     - ``senscorr_off`` If True, do not apply sensitivity correction

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

     - ``sensitivity``    : Sensitivity correction image in ASL space
    """
    if wsp.senscorr is not None:
        return

    wsp.log.write("\nCalculating Sensitivity correction\n")
    sensitivity = None
    bias = None
    if wsp.senscorr_off:
        wsp.log.write(" - Sensitivity correction disabled\n")
    elif wsp.isen is not None:
        wsp.log.write(" - Sensitivity image supplied by user\n")
        sensitivity = wsp.isen
    elif wsp.cact is not None and wsp.cref is not None:
        wsp.log.write(
            " - Sensitivity image calculated from calibration actual and reference images\n"
        )
        cref_data = np.copy(wsp.cref.data)
        cref_data[cref_data == 0] = 1
        sensitivity = Image(wsp.cact.data.astype(np.float) / cref_data,
                            header=wsp.calib.header)
    elif wsp.calib is not None and wsp.cref is not None:
        if wsp.ifnone("mode", "longtr") != "longtr":
            raise ValueError(
                "Calibration reference image specified but calibration image was not in longtr mode - need to provided additional calibration image using the ASL coil"
            )
        wsp.log.write(
            " - Sensitivity image calculated from calibration and reference images\n"
        )
        cref_data = np.copy(wsp.cref.data)
        cref_data[cref_data == 0] = 1
        sensitivity = Image(wsp.calib.data.astype(np.float) / cref_data,
                            header=wsp.calib.header)
    elif wsp.senscorr_auto and wsp.structural.bias is not None:
        struc.segment(wsp)
        wsp.log.write(" - Sensitivity image calculated from bias field\n")
        bias = reg.struc2asl(wsp, wsp.structural.bias)
        sensitivity = Image(np.reciprocal(bias.data), header=bias.header)
    else:
        wsp.log.write(" - No source of sensitivity correction was found\n")

    if sensitivity is not None:
        sdata = sensitivity.data
        sdata[sdata < 1e-12] = 1
        sdata[np.isnan(sdata)] = 1
        sdata[np.isinf(sdata)] = 1
        wsp.sub("senscorr")
        wsp.senscorr.sensitivity = Image(sdata, header=sensitivity.header)

        page = wsp.report.page("sensitivity")
        page.heading("Sensitivity correction", level=0)
        page.heading("Sensitivity map", level=1)
        page.image("sensitivity", LightboxImage(wsp.senscorr.sensitivity))

    if bias is not None:
        wsp.senscorr.bias = bias
Esempio n. 5
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.fieldmap is not None:
        return
    elif wsp.fmap is None or wsp.fmapmag is None or wsp.fmapmagbrain is None:
        wsp.log.write("\nNo fieldmap images for distortion correction\n")
        return
    elif wsp.pedir is None or wsp.echospacing is None:
        wsp.log.write(
            "\nWARNING: Fieldmap images supplied but pedir and echospacing required for distortion correction\n"
        )
        return

    struc.segment(wsp)
    wsp.sub("fieldmap")
    wsp.log.write(
        "\nCalculating 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.regfrom, **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)

    wsp.fieldmap.warp_struc = result["out_warp"]
    wsp.fieldmap.asl2struc = result["out"]
    wsp.fieldmap.struc2asl = np.linalg.inv(wsp.fieldmap.asl2struc)

    result = fsl.convertwarp(out=fsl.LOAD,
                             ref=wsp.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))
Esempio n. 6
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
Esempio n. 7
0
def get_tissrefmask(wsp):
    """
    Calculate a calibration reference mask for a particular known tissue type
    """
    struc.segment(wsp)

    page = wsp.report.page("auto_calib_mask")
    page.heading("Calibration reference region")
    page.text(
        "Reference region was automatically generated for tissue type: %s" %
        wsp.tissref.upper())
    page.heading(
        "Partial volume map for %s tissue (from structural segmentation)" %
        wsp.tissref.upper(),
        level=1)
    wsp.calibration.refpve = getattr(wsp.structural,
                                     "%s_pv" % wsp.tissref.lower())
    page.image(
        "refpve",
        LightboxImage(wsp.calibration.refpve, bgimage=wsp.structural.brain))

    if wsp.tissref == "csf" and not wsp.csfmaskingoff:
        wsp.log.write(
            " - Doing automatic ventricle selection using standard atlas\n")
        # By deafult now we do FNRIT transformation of ventricle mask
        # FIXME disabled as not being used in ASL_CALIB at present
        #wsp.calibration.struc2stdfnirt = wsp.ifnone("stdmaskfnirt", True)

        # Select ventricles based on standard space atlas
        page.heading("Automatic ventricle selection", level=1)
        page.text(
            "Standard space ventricles mask (from Harvard-Oxford atlas) eroded by 1 pixel"
        )
        atlases = AtlasRegistry()
        atlases.rescanAtlases()
        atlas = atlases.loadAtlas("harvardoxford-subcortical",
                                  loadSummary=False,
                                  resolution=2)
        ventricles = ((atlas.data[..., 2] + atlas.data[..., 13]) > 0.1).astype(
            np.int)
        wsp.calibration.ventricles = Image(
            scipy.ndimage.binary_erosion(ventricles,
                                         structure=np.ones([3, 3, 3]),
                                         border_value=1).astype(np.int),
            header=atlas.header)
        std_img = Image(
            os.path.join(os.environ["FSLDIR"], "data", "standard",
                         'MNI152_T1_2mm_brain'))
        page.image("ventricles_std",
                   LightboxImage(wsp.calibration.ventricles, bgimage=std_img))

        page.heading("Structural space ventricles mask", level=1)
        reg.reg_struc2std(wsp)
        # FIXME nearest neighbour interpolation?
        wsp.calibration.ventricles_struc = reg.std2struc(
            wsp, wsp.calibration.ventricles)
        page.text(
            "This is the above image transformed into structural space. The transformation was obtained by registering the structural image to the standard brain image"
        )
        page.image(
            "ventricles_struc",
            LightboxImage(wsp.calibration.ventricles_struc,
                          bgimage=wsp.structural.brain))

        wsp.log.write(
            " - Masking FAST output with standard space derived ventricle mask\n"
        )
        wsp.calibration.refpve_pre_mask = wsp.calibration.refpve
        refpve_data = np.copy(wsp.calibration.refpve.data)
        refpve_data[wsp.calibration.ventricles_struc.data == 0] = 0
        wsp.calibration.refpve = Image(refpve_data,
                                       header=wsp.calibration.refpve.header)
        wsp.calibration.refpve_post = wsp.calibration.refpve

        page.heading("Structural space ventricles PVE", level=1)
        page.text(
            "This is the CSF partial volume masked by the ventricles mask. It should select only the ventricles from the original partial volume image."
        )
        page.image(
            "refpve_post",
            LightboxImage(wsp.calibration.refpve,
                          bgimage=wsp.structural.brain))

    wsp.log.write(" - Transforming tissue reference mask into ASL space\n")
    # FIXME calibration image may not be in ASL space! Oxford_asl does not handle this currently
    wsp.calibration.refpve_calib = reg.struc2asl(wsp, wsp.calibration.refpve)
    #wsp.calibration.refpve_calib.data[wsp.calibration.refpve_calib.data < 0.001] = 0 # Better for display
    page.heading("Reference region in ASL space", level=1)
    page.text("Partial volume map")
    page.image("refpve_calib",
               LightboxImage(wsp.calibration.refpve_calib, bgimage=wsp.calib))

    # Threshold reference mask conservatively to select only reference tissue
    wsp.log.write(" - Thresholding reference mask\n")
    wsp.calibration.refmask = Image(
        (wsp.calibration.refpve_calib.data > 0.9).astype(np.int),
        header=wsp.calibration.refpve_calib.header)

    page.text("Reference Mask (thresholded at 0.9")
    page.image("refmask",
               LightboxImage(wsp.calibration.refmask, bgimage=wsp.calib))
Esempio n. 8
0
def get_m0_wholebrain(wsp):
    """
    Get a whole-brain M0 value

    This calculates an M0 map for the whole brain using the T1, T2 and PC
    values for each tissue type with the contribution at each voxel weighted
    by the tissue partial volume

    :param wsp: Workspace object
    :return: Image containing voxelwise M0 map

    Required Workspace attributes
    -----------------------------

      - ``calib``     - Calibration Image in ASL native space
      - ``rois.mask`` - Brain mask Image in ASL native space
      - ``struc``     - Structural image
    """
    struc.segment(wsp)
    wsp.log.write("\n - Doing wholebrain region calibration\n")

    tr = wsp.ifnone("tr", 3.2)
    te = wsp.ifnone("te", 0)
    taq = wsp.ifnone("taq", 0)
    wsp.log.write(" - Using TE=%f, TR=%f, Readout time (TAQ)=%f\n" %
                  (te, tr, taq))

    t2star = wsp.ifnone("t2star", False)
    if t2star:
        t2b = wsp.ifnone("t2sb", 50)
    else:
        t2b = wsp.ifnone("t2b", 150)

    # Check the data and masks
    calib_data = np.copy(wsp.calib.data)
    if wsp.rois is not None and wsp.rois.mask is not None:
        brain_mask = wsp.rois.mask.data
    else:
        brain_mask = np.ones(wsp.calib.shape[:3])

    ### Sensitivity image calculation (if we have a sensitivity image)
    if wsp.sens:
        wsp.log.write(" - Using sensitivity image: %s\n" % wsp.sens.name)
        calib_data /= wsp.sens.data

    m0 = np.zeros(calib_data.shape, dtype=np.float)
    for tiss_type in ("wm", "gm", "csf"):
        pve_struc = getattr(wsp.structural, "%s_pv" % tiss_type)
        wsp.log.write(" - Transforming %s tissue PVE into ASL space\n" %
                      tiss_type)
        pve = reg.struc2asl(wsp, pve_struc)
        t1r, t2r, t2sr, pcr = tissue_defaults(tiss_type)
        if t2star:
            t2r = t2sr
        t1_corr = 1 / (1 - math.exp(-(tr - taq) / t1r))
        t2_corr = 1 / math.exp(-te / t2r)
        wsp.log.write("Correction factors: T1: %f, T2 %f, PC: %f" %
                      (t1_corr, t2_corr, pcr))
        tiss_m0 = calib_data * t1_corr * t2_corr / pcr
        wsp.log.write(" - Mean %s M0: %f (weighted by PV)\n" %
                      (tiss_type, np.average(tiss_m0, weights=pve.data)))
        tiss_m0 *= pve.data
        setattr(wsp.calibration, "m0_img_%s" % tiss_type,
                Image(tiss_m0, header=wsp.calib.header))
        m0 += tiss_m0

    m0 = m0 * math.exp(-te / t2b)
    gain = wsp.ifnone("calib_gain", 1)
    wsp.log.write(" - Calibration gain: %f\n" % gain)
    if gain != 1:
        m0 = m0 * gain

    wsp.calibration.m0_img = Image(m0, header=wsp.calib.header)
    m0 = np.mean(m0[brain_mask != 0])
    wsp.log.write(" - M0 of brain: %f\n" % m0)

    # Reporting
    page = wsp.report.page("m0")
    page.heading("Whole-brain M0 calculation")
    page.text(
        "Whole-brain calibration calculates an M0 value for each voxel from the calibration image based on partial volume estimates"
    )
    page.text("- Calibration gain: %f" % gain)
    page.text(" - TR: %f" % tr)
    page.text(" - TE: %f" % te)

    page.heading("M0", level=1)
    page.text("Mean M0 value (within mask): %f" % m0)
    page.image("m0img", LightboxImage(wsp.calibration.m0_img))

    return float(m0)