コード例 #1
0
def cruise_cortex_extraction(init_image,
                             wm_image,
                             gm_image,
                             csf_image,
                             vd_image=None,
                             data_weight=0.4,
                             regularization_weight=0.1,
                             max_iterations=500,
                             normalize_probabilities=False,
                             correct_wm_pv=True,
                             wm_dropoff_dist=1.0,
                             topology='wcs',
                             topology_lut_dir=None,
                             save_data=False,
                             overwrite=False,
                             output_dir=None,
                             file_name=None,
                             log_file="timelog.json"):
    """ CRUISE cortex extraction

    Segments the cortex from a whole brain segmented data set with the CRUISE
    method (includes customized partial voluming corrections and the
    Anatomically-Consistent Enhancement (ACE) of sulcal fundi).

    Note that the main input images are generated by the nighres module
    :func:`nighres.brain.extract_brain_region`.

    Parameters
    ----------
    init_image: niimg
        Initial white matter (WM) segmentation mask (binary mask>0 inside WM)
    wm_image: niimg
        Filled WM probability map (values in [0,1], including subcortical GM
        and ventricles)
    gm_image: niimg
        Cortical gray matter (GM) probability map (values in [0,1], highest
        inside the cortex)
    csf_image: niimg
        Sulcal cerebro-spinal fluid (CSf) and background probability map
        (values in [0,1], highest in CSf and masked regions)
    vd_image: niimg, optional
        Additional probability map of vessels and dura mater to be excluded
    data_weight: float
        Weighting of probability-based balloon forces in CRUISE (default 0.4,
        sum of {data_weight,regularization_weight} should be below or equal
        to 1)
    regularization_weight: float
        Weighting of curvature regularization forces in CRUISE (default 0.1,
        sum of {data_weight,regularization_weight} should be below or equal
        to 1)
    max_iterations: int
        Maximum number of iterations in CRUISE (default is 500)
    normalize_probabilities: bool
        Whether to normalize the wm, gm, and csf probabilities
        (default is False)
    correct_wm_pv: bool
        Whether to correct for WM partial voluming in gyral crowns
        (default is True)
    wm_dropoff_dist: float
        Distance parameter to lower WM probabilities away from current
        segmentation (default is 1.0 voxel)
    topology: {'wcs', 'no'}
        Topology setting, choose 'wcs' (well-composed surfaces) for strongest
        topology constraint, 'no' for no topology constraint (default is 'wcs')
    topology_lut_dir: str
        Path to directory in which topology files are stored (default is stored
        in TOPOLOGY_LUT_DIR)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * cortex (niimg): Hard segmentation of the cortex with labels
          background=0, gm=1, and wm=2 (_cruise_cortex)
        * gwb (niimg): Gray-White matter Boundary (GWB) level set function
          (_cruise_gwb)
        * cgb (niimg): CSF-Gray matter Boundary (CGB) level set function
          (_cruise_cgb)
        * avg (niimg): Central level set function, obtained as geometric
          average of GWB and CGB (*not* the middle depth of the
          cortex, use volumetric_layering if you want accurate
          depth measures) (_cruise-avg)
        * thickness (niimg): Simple cortical thickness estimate: distance to
          the GWB and CGB surfaces, in mm (_cruise-thick)
        * pwm (niimg): Optimized WM probability, including partial volume and
          distant values correction (_cruise-pwm)
        * pgm (niimg): Optimized GM probability, including CSF sulcal ridges
          correction (_cruise_pgm)
        * pcsf (niimg): Optimized CSF probability, including sulcal ridges and
          vessel/dura correction (_cruise-pwm)

    Notes
    ----------
    Original algorithm by Xiao Han. Java module by Pierre-Louis Bazin.
    Algorithm details can be found in [1]_

    References
    ----------
    .. [1] X. Han, D.L. Pham, D. Tosun, M.E. Rettmann, C. Xu, and J. L. Prince,
       CRUISE: Cortical Reconstruction Using Implicit Surface Evolution,
       NeuroImage, vol. 23, pp. 997--1012, 2004
    """

    print('\nCRUISE Cortical Extraction')
    start = time.time()

    # check topology_lut_dir and set default if not given
    topology_lut_dir = _check_topology_lut_dir(topology_lut_dir)

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, gm_image)

        cortex_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-cortex',
            ))

        gwb_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-gwb',
            ))

        cgb_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-cgb',
            ))

        avg_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-avg',
            ))

        thick_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-thick',
            ))

        pwm_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-pwm',
            ))

        pgm_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-pgm',
            ))

        pcsf_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=gm_image,
                suffix='cruise-pcsf',
            ))
        if overwrite is False \
            and os.path.isfile(cortex_file) \
            and os.path.isfile(gwb_file) \
            and os.path.isfile(cgb_file) \
            and os.path.isfile(avg_file) \
            and os.path.isfile(thick_file) \
            and os.path.isfile(pwm_file) \
            and os.path.isfile(pgm_file) \
            and os.path.isfile(pcsf_file) :

            print("skip computation (use existing results)")
            output = {
                'cortex': cortex_file,
                'gwb': gwb_file,
                'cgb': cgb_file,
                'avg': avg_file,
                'thickness': thick_file,
                'pwm': pwm_file,
                'pgm': pgm_file,
                'pcsf': pcsf_file
            }
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    cruise = nighresjava.CortexOptimCRUISE()

    # set parameters
    cruise.setDataWeight(data_weight)
    cruise.setRegularizationWeight(regularization_weight)
    cruise.setMaxIterations(max_iterations)
    cruise.setNormalizeProbabilities(normalize_probabilities)
    cruise.setCorrectForWMGMpartialVoluming(correct_wm_pv)
    cruise.setWMdropoffDistance(wm_dropoff_dist)
    cruise.setTopology(topology)
    cruise.setTopologyLUTdirectory(topology_lut_dir)

    # load images
    init = load_volume(init_image, log_file=log_file)
    init_data = init.get_data()
    affine = init.affine
    header = init.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = init_data.shape
    cruise.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    cruise.setResolutions(resolution[0], resolution[1], resolution[2])
    cruise.importInitialWMSegmentationImage(
        nighresjava.JArray('int')(
            (init_data.flatten('F')).astype(int).tolist()))

    wm_data = load_volume(wm_image, log_file=log_file).get_data()
    cruise.setFilledWMProbabilityImage(
        nighresjava.JArray('float')((wm_data.flatten('F')).astype(float)))

    gm_data = load_volume(gm_image, log_file=log_file).get_data()
    cruise.setGMProbabilityImage(
        nighresjava.JArray('float')((gm_data.flatten('F')).astype(float)))

    csf_data = load_volume(csf_image, log_file=log_file).get_data()
    cruise.setCSFandBGProbabilityImage(
        nighresjava.JArray('float')((csf_data.flatten('F')).astype(float)))

    if vd_image is not None:
        vd_data = load_volume(vd_image, log_file=log_file).get_data()
        cruise.setVeinsAndDuraProbabilityImage(
            nighresjava.JArray('float')((vd_data.flatten('F')).astype(float)))

    # execute
    try:
        cruise.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    cortex_data = np.reshape(np.array(cruise.getCortexMask(), dtype=np.int32),
                             dimensions, 'F')
    gwb_data = np.reshape(np.array(cruise.getWMGMLevelset(), dtype=np.float32),
                          dimensions, 'F')
    cgb_data = np.reshape(
        np.array(cruise.getGMCSFLevelset(), dtype=np.float32), dimensions, 'F')
    avg_data = np.reshape(
        np.array(cruise.getCentralLevelset(), dtype=np.float32), dimensions,
        'F')
    thick_data = np.reshape(
        np.array(cruise.getCorticalThickness(), dtype=np.float32), dimensions,
        'F')
    pwm_data = np.reshape(
        np.array(cruise.getCerebralWMprobability(), dtype=np.float32),
        dimensions, 'F')
    pgm_data = np.reshape(
        np.array(cruise.getCorticalGMprobability(), dtype=np.float32),
        dimensions, 'F')
    pcsf_data = np.reshape(
        np.array(cruise.getSulcalCSFprobability(), dtype=np.float32),
        dimensions, 'F')

    # adapt header min, max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmax(cortex_data)
    header['cal_max'] = np.nanmax(cortex_data)
    cortex = nb.Nifti1Image(cortex_data, affine, header)

    header['cal_min'] = np.nanmax(gwb_data)
    header['cal_max'] = np.nanmax(gwb_data)
    gwb = nb.Nifti1Image(gwb_data, affine, header)

    header['cal_min'] = np.nanmax(cgb_data)
    header['cal_max'] = np.nanmax(cgb_data)
    cgb = nb.Nifti1Image(cgb_data, affine, header)

    header['cal_min'] = np.nanmax(avg_data)
    header['cal_max'] = np.nanmax(avg_data)
    avg = nb.Nifti1Image(avg_data, affine, header)

    header['cal_min'] = np.nanmax(thick_data)
    header['cal_max'] = np.nanmax(thick_data)
    thickness = nb.Nifti1Image(thick_data, affine, header)

    header['cal_min'] = np.nanmax(pwm_data)
    header['cal_max'] = np.nanmax(pwm_data)
    pwm = nb.Nifti1Image(pwm_data, affine, header)

    header['cal_min'] = np.nanmax(pgm_data)
    header['cal_max'] = np.nanmax(pgm_data)
    pgm = nb.Nifti1Image(pgm_data, affine, header)

    header['cal_min'] = np.nanmax(pcsf_data)
    header['cal_max'] = np.nanmax(pcsf_data)
    pcsf = nb.Nifti1Image(pcsf_data, affine, header)

    if save_data:
        save_volume(cortex_file, cortex, log_file=log_file)
        save_volume(gwb_file, gwb, log_file=log_file)
        save_volume(cgb_file, cgb, log_file=log_file)
        save_volume(avg_file, avg, log_file=log_file)
        save_volume(thick_file, thickness, log_file=log_file)
        save_volume(pwm_file, pwm, log_file=log_file)
        save_volume(pgm_file, pgm, log_file=log_file)
        save_volume(pcsf_file, pcsf, log_file=log_file)

        result = {
            'cortex': cortex_file,
            'gwb': gwb_file,
            'cgb': cgb_file,
            'avg': avg_file,
            'thickness': thick_file,
            'pwm': pwm_file,
            'pgm': pgm_file,
            'pcsf': pcsf_file
        }
    else:
        result = {
            'cortex': cortex,
            'gwb': gwb,
            'cgb': cgb,
            'avg': avg,
            'thickness': thickness,
            'pwm': pwm,
            'pgm': pgm,
            'pcsf': pcsf
        }

    end = time.time()
    time_log(log_file, "cruise_cortex_extraction", "makespan", None, start,
             end)

    return result
コード例 #2
0
ファイル: phase_unwrapping.py プロジェクト: thm200103/nighres
def phase_unwrapping(image,
                     mask=None,
                     nquadrants=3,
                     tv_flattening=False,
                     tv_scale=0.5,
                     save_data=False,
                     overwrite=False,
                     output_dir=None,
                     file_name=None):
    """ Fast marching phase unwrapping

    Fast marching method for unwrapping phase images, based on _[1]

    Parameters
    ----------
    image: niimg
        Input phase image to unwrap
    mask: niimg, optional
        Data mask to specify acceptable seeding regions
    nquadrants: int, optional
        Number of image quadrants to use (default is 3)
    tv_flattening: bool, optional 
        Whether or not to run a post-processing step to remove background
        phase variations with a total variation filter (default is False)
    tv_scale: float, optional
        Relative intensity scale for the TV filter (default is 0.5)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): The unwrapped image rescaled in radians

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Algorithm adapted from [1]_
    with additional seeding in multiple image quadrants to reduce the effects
    of possible phase singularities

    References
    ----------
    .. [1] Abdul-Rahman, Gdeisat, Burton and Lalor. Fast three-dimensional 
           phase-unwrapping algorithm based on sorting by reliability following 
           a non-continuous path. doi: 10.1117/12.611415
    """

    print('\nFast marching phase unwrapping')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image)

        out_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image,
                           suffix='unwrap-img'))

        if overwrite is False \
            and os.path.isfile(out_file) :
            print("skip computation (use existing results)")
            output = {'result': out_file}
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    unwrap = nighresjava.FastMarchingPhaseUnwrapping()

    # set parameters

    # load image and use it to set dimensions and resolution
    img = load_volume(image)
    data = img.get_data()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape
    dimensions3D = (dimensions[0], dimensions[1], dimensions[2])

    unwrap.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    unwrap.setResolutions(resolution[0], resolution[1], resolution[2])

    unwrap.setPhaseImage(
        nighresjava.JArray('float')(
            (data.flatten('F')).astype(float)[0:dimensions[0] * dimensions[1] *
                                              dimensions[2]]))

    if mask is not None:
        unwrap.setMaskImage(
            idx,
            nighresjava.JArray('int')(
                (load_volume(mask).get_data().flatten('F')
                 ).astype(int).tolist()))

    # set algorithm parameters
    unwrap.setQuadrantNumber(nquadrants)
    if tv_flattening: unwrap.setTVPostProcessing("TV-residuals")
    unwrap.setTVScale(tv_scale)

    # execute the algorithm
    try:
        unwrap.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    unwrap_data = np.reshape(
        np.array(unwrap.getCorrectedImage(), dtype=np.float32), dimensions3D,
        'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(unwrap_data)
    header['cal_max'] = np.nanmax(unwrap_data)
    out = nb.Nifti1Image(unwrap_data, affine, header)

    if save_data:
        save_volume(out_file, out)
        return {'result': out_file}
    else:
        return {'result': out}
コード例 #3
0
def filter_ridge_structures(input_image,
                            structure_intensity='bright',
                            output_type='probability',
                            use_strict_min_max_filter=True,
                            save_data=False, overwrite=False, output_dir=None,
                            file_name=None):

    """ Filter Ridge Structures

    Uses an image filter to make a probabilistic image of ridge
    structures.


    Parameters
    ----------
    input_image: niimg
        Image containing structure-of-interest
    structure_intensity: {'bright', 'dark', 'both}
        Image intensity of structure-of-interest'
    output_type: {'probability','intensity'}
        Whether the image should be normalized to reflect probabilities
    use_strict_min_max_filter: bool, optional
        Choose between the more specific recursive ridge filter or a more
        sensitive bidirectional filter (default is True)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * ridge_structure_image: Image that reflects the presensence of ridges
          in the image (_rdg-img)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    """

    if save_data:
        output_dir = _output_dir_4saving(output_dir, input_image)

        ridge_file = os.path.join(output_dir,
                        _fname_4saving(module=__name__,file_name=file_name,
                                       rootfile=input_image,
                                       suffix='rdg-img', ))
        if overwrite is False \
            and os.path.isfile(ridge_file) :

            print("skip computation (use existing results)")
            output = {'result': ridge_file}
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    filter_ridge = nighresjava.FilterRidgeStructures()

    # set parameters
    filter_ridge.setStructureIntensity(structure_intensity)
    filter_ridge.setOutputType(output_type)
    filter_ridge.setUseStrictMinMaxFilter(use_strict_min_max_filter)


    # load images and set dimensions and resolution
    input_image = load_volume(input_image)
    data = input_image.get_fdata()
    affine = input_image.affine
    header = input_image.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = input_image.shape


    filter_ridge.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    filter_ridge.setResolutions(resolution[0], resolution[1], resolution[2])

    data = load_volume(input_image).get_fdata()
    filter_ridge.setInputImage(nighresjava.JArray('float')(
                               (data.flatten('F')).astype(float)))


    # execute
    try:
        filter_ridge.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # Collect output
    ridge_structure_image_data = np.reshape(np.array(
                                    filter_ridge.getRidgeStructureImage(),
                                    dtype=np.float32), dimensions, 'F')

    if output_type == 'probability':
        header['cal_min'] = 0.0
        header['cal_max'] = 1.0
    else:
        header['cal_min'] = np.nanmin(ridge_structure_image_data)
        header['cal_max'] = np.nanmax(ridge_structure_image_data)

    ridge_structure_image = nb.Nifti1Image(ridge_structure_image_data, affine,
                                           header)
    if save_data:
        save_volume(ridge_file, ridge_structure_image)
        outputs = {'result': ridge_file}
    else:
        outputs = {'result': ridge_structure_image}
    return outputs
コード例 #4
0
def intensity_propagation(image, mask=None, combine='mean', distance_mm=5.0,
                      target='zero', scaling=1.0, domain=None,
                      save_data=False, overwrite=False, output_dir=None,
                      file_name=None):
    """ Intensity Propogation

    Propagates the values inside the mask (or non-zero) into the neighboring voxels

    Parameters
    ----------
    image: niimg
        Input image
    mask: niimg, optional
        Data mask to specify acceptable seeding regions
    combine: {'min','mean','max'}, optional
        Propagate using the mean (default), max or min data from neighboring voxels
    distance_mm: float, optional 
        Distance for the propagation (note: this algorithm will be slow for 
        large distances)
    target: {'zero','mask','lower','higher'}, optional
        Propagate into zero (default), masked out, lower or higher neighboring voxels
    scaling: float, optional
        Multiply the propagated values by a factor <=1 (default is 1)
    domain: niimg, optional
        Domain mask to specify acceptable regions to grow into
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): The propagated intensity image

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.

    """

    print('\nIntensity Propagation')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image)

        out_file = os.path.join(output_dir, 
                        _fname_4saving(module=__name__,file_name=file_name,
                                   rootfile=image,
                                   suffix='ppag-img'))

        if overwrite is False \
            and os.path.isfile(out_file) :
                print("skip computation (use existing results)")
                output = {'result': out_file}
                return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    propag = nighresjava.IntensityPropagate()

    # set parameters
    
    # load image and use it to set dimensions and resolution
    img = load_volume(image)
    data = img.get_fdata()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    if len(dimensions)>2:
        propag.setDimensions(dimensions[0], dimensions[1], dimensions[2])
        propag.setResolutions(resolution[0], resolution[1], resolution[2])
    else:
        propag.setDimensions(dimensions[0], dimensions[1])
        propag.setResolutions(resolution[0], resolution[1])
        
    propag.setInputImage(nighresjava.JArray('float')(
                                    (data.flatten('F')).astype(float)))
    
    
    if mask is not None:
        propag.setMaskImage(nighresjava.JArray('int')(
                (load_volume(mask).get_fdata().flatten('F')).astype(int).tolist()))
    
    if domain is not None:
        propag.setDomainImage(nighresjava.JArray('int')(
                (load_volume(domain).get_fdata().flatten('F')).astype(int).tolist()))
    
    # set algorithm parameters
    propag.setCombinationMethod(combine)
    propag.setPropagationDistance(distance_mm)
    propag.setTargetVoxels(target)
    propag.setPropogationScalingFactor(scaling)
    
    # execute the algorithm
    try:
        propag.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    propag_data = np.reshape(np.array(propag.getResultImage(),
                                    dtype=np.float32), dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(propag_data)
    header['cal_max'] = np.nanmax(propag_data)
    out = nb.Nifti1Image(propag_data, affine, header)

    if save_data:
        save_volume(out_file, out)
        return {'result': out_file}
    else:
        return {'result': out}
コード例 #5
0
def mp2rage_skullstripping(second_inversion,
                           t1_weighted=None,
                           t1_map=None,
                           skip_zero_values=True,
                           topology_lut_dir=None,
                           save_data=False,
                           overwrite=False,
                           output_dir=None,
                           file_name=None):
    """ MP2RAGE skull stripping

    Estimates a brain mask from MRI data acquired with the MP2RAGE sequence.
    At least a T1-weighted or a T1 map image is required

    Parameters
    ----------
    second_inversion: niimg
        Second inversion image derived from MP2RAGE sequence
    t1_weighted: niimg
        T1-weighted image derived from MP2RAGE sequence (also referred to as
        "uniform" image)
        At least one of t1_weighted and t1_map is required
    t1_map: niimg
        Quantitative T1 map image derived from MP2RAGE sequence
        At least one of t1_weighted and t1_map is required
    skip_zero_values: bool
         Ignores voxels with zero value (default is True)
    topology_lut_dir: str, optional
        Path to directory in which topology files are stored (default is stored
        in TOPOLOGY_LUT_DIR)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * brain_mask (niimg): Binary brain mask (_strip-mask)
        * inv2_masked (niimg): Masked second inversion imamge (_strip-inv2)
        * t1w_masked (niimg): Masked T1-weighted image (_strip-t1w)
        * t1map_masked (niimg): Masked T1 map (_strip-t1map)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Details on the algorithm can 
    be found in [1]_ and a presentation of the MP2RAGE sequence in [2]_

    References
    ----------
    .. [1] Bazin et al. (2014). A computational framework for ultra-high 
       resolution cortical segmentation at 7 Tesla.
       DOI: 10.1016/j.neuroimage.2013.03.077
    .. [2] Marques et al. (2010). MP2RAGE, a self bias-field corrected sequence
       for improved segmentation and T1-mapping at high field.
       DOI: 10.1016/j.neuroimage.2009.10.002
    """

    print('\nMP2RAGE Skull Stripping')

    # check topology lut dir and set default if not given
    topology_lut_dir = _check_topology_lut_dir(topology_lut_dir)

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, second_inversion)

        inv2_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=second_inversion,
                           suffix='strip-inv2'))
        mask_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=second_inversion,
                           suffix='strip-mask'))
        if t1_weighted is not None:
            t1w_file = os.path.join(
                output_dir,
                _fname_4saving(module=__name__,
                               file_name=file_name,
                               rootfile=t1_weighted,
                               suffix='strip-t1w'))
        else:
            t1w_file = None

        if t1_map is not None:
            t1map_file = os.path.join(
                output_dir,
                _fname_4saving(module=__name__,
                               file_name=file_name,
                               rootfile=t1_map,
                               suffix='strip-t1map'))
        else:
            t1map_file = None

        if overwrite is False \
            and os.path.isfile(mask_file) \
            and os.path.isfile(inv2_file) :

            print("skip computation (use existing results)")
            output = {'brain_mask': mask_file, 'inv2_masked': inv2_file}
            if t1w_file is not None:
                if os.path.isfile(t1w_file):
                    output['t1w_masked'] = t1w_file
            if t1map_file is not None:
                if os.path.isfile(t1map_file):
                    output['t1map_masked'] = t1map_file
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # create skulltripping instance
    algo = nighresjava.BrainMp2rageSkullStripping()

    # get dimensions and resolution from second inversion image
    inv2_img = load_volume(second_inversion)
    inv2_data = inv2_img.get_fdata()
    inv2_affine = inv2_img.affine
    inv2_hdr = inv2_img.header
    resolution = [x.item() for x in inv2_hdr.get_zooms()]
    dimensions = inv2_data.shape
    algo.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    algo.setResolutions(resolution[0], resolution[1], resolution[2])
    algo.setSecondInversionImage(
        nighresjava.JArray('float')((inv2_data.flatten('F')).astype(float)))

    # pass other inputs
    if (t1_weighted is None and t1_map is None):
        raise ValueError('You must specify at least one of '
                         't1_weighted and t1_map')
    if t1_weighted is not None:
        t1w_img = load_volume(t1_weighted)
        t1w_data = t1w_img.get_fdata()
        t1w_affine = t1w_img.affine
        t1w_hdr = t1w_img.header
        algo.setT1weightedImage(
            nighresjava.JArray('float')((t1w_data.flatten('F')).astype(float)))
    if t1_map is not None:
        t1map_img = load_volume(t1_map)
        t1map_data = t1map_img.get_fdata()
        t1map_affine = t1map_img.affine
        t1map_hdr = t1map_img.header
        algo.setT1MapImage(
            nighresjava.JArray('float')(
                (t1map_data.flatten('F')).astype(float)))

    algo.setSkipZeroValues(skip_zero_values)
    algo.setTopologyLUTdirectory(topology_lut_dir)

    # execute skull stripping
    try:
        algo.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs and potentially save
    inv2_masked_data = np.reshape(
        np.array(algo.getMaskedSecondInversionImage(), dtype=np.float32),
        dimensions, 'F')
    inv2_hdr['cal_max'] = np.nanmax(inv2_masked_data)
    inv2_masked = nb.Nifti1Image(inv2_masked_data, inv2_affine, inv2_hdr)

    mask_data = np.reshape(np.array(algo.getBrainMaskImage(), dtype=np.uint32),
                           dimensions, 'F')
    inv2_hdr['cal_max'] = np.nanmax(mask_data)
    mask = nb.Nifti1Image(mask_data, inv2_affine, inv2_hdr)

    if save_data:
        save_volume(inv2_file, inv2_masked)
        save_volume(mask_file, mask)
        outputs = {'brain_mask': mask_file, 'inv2_masked': inv2_file}
    else:
        outputs = {'brain_mask': mask, 'inv2_masked': inv2_masked}

    if t1_weighted is not None:
        t1w_masked_data = np.reshape(
            np.array(algo.getMaskedT1weightedImage(), dtype=np.float32),
            dimensions, 'F')
        t1w_hdr['cal_max'] = np.nanmax(t1w_masked_data)
        t1w_masked = nb.Nifti1Image(t1w_masked_data, t1w_affine, t1w_hdr)

        if save_data:
            save_volume(t1w_file, t1w_masked)
            outputs['t1w_masked'] = t1w_file
        else:
            outputs['t1w_masked'] = t1w_masked

    if t1_map is not None:
        t1map_masked_data = np.reshape(
            np.array(algo.getMaskedT1MapImage(), dtype=np.float32), dimensions,
            'F')
        t1map_hdr['cal_max'] = np.nanmax(t1map_masked_data)
        t1map_masked = nb.Nifti1Image(t1map_masked_data, t1map_affine,
                                      t1map_hdr)

        if save_data:
            save_volume(t1map_file, t1map_masked)
            outputs['t1map_masked'] = t1map_file
        else:
            outputs['t1map_masked'] = t1map_masked

    return outputs
コード例 #6
0
def topology_correction(image,
                        shape_type,
                        connectivity='wcs',
                        propagation='object->background',
                        minimum_distance=0.00001,
                        topology_lut_dir=None,
                        save_data=False,
                        overwrite=False,
                        output_dir=None,
                        file_name=None):
    """Topology correction

    Corrects the topology of a binary image, a probability map or a levelset
    surface to spherical with a fast marching technique [1]_.

    Parameters
    ----------
    image: niimg
        Image representing the shape of interest
    shape_type: {'binary_object','probability_map','signed_distance_function'}
        Which type of image is used as input
    connectivity: {'wcs','6/18','6/26','18/6','26/6'}
        What connectivity type to use (default is wcs: well-composed surfaces)
    propagation: {'object->background','background->object'}
        Which direction to use to enforce topology changes
        (default is 'object->background' )
    minimum_distance: float, optional
        Minimum distance to impose between successive voxels (default is 1e-5)
    topology_lut_dir: str, optional
        Path to directory in which topology files are stored (default is stored
        in TOPOLOGY_LUT_DIR)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool, optional
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * corrected (niimg): Corrected image (output file suffix _tpc-img)
        * object (niimg): Corrected binary object (output file suffix _tpc-obj)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin

    References
    ----------
    .. [1] Bazin and Pham (2007). Topology correction of segmented medical
        images using a fast marching algorithm
        doi:10.1016/j.cmpb.2007.08.006
    """

    print("\nTopology Correction")

    # check topology_lut_dir and set default if not given
    topology_lut_dir = _check_topology_lut_dir(topology_lut_dir)

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image)

        corrected_file = os.path.join(
            output_dir,
            _fname_4saving(file_name=file_name,
                           rootfile=image,
                           suffix='tpc-img'))

        corrected_obj_file = os.path.join(
            output_dir,
            _fname_4saving(file_name=file_name,
                           rootfile=image,
                           suffix='tpc-obj'))
        if overwrite is False \
            and os.path.isfile(corrected_file) \
            and os.path.isfile(corrected_obj_file) :

            print("skip computation (use existing results)")
            output = {
                'corrected': load_volume(corrected_file),
                'object': load_volume(corrected_obj_file)
            }
            return output

    # start virtual machine if not running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # initiate class
    algorithm = nighresjava.ShapeTopologyCorrection2()

    # load the data
    img = load_volume(image)
    hdr = img.header
    aff = img.affine
    data = img.get_data()
    resolution = [x.item() for x in hdr.get_zooms()]
    dimensions = data.shape

    algorithm.setResolutions(resolution[0], resolution[1], resolution[2])
    algorithm.setDimensions(dimensions[0], dimensions[1], dimensions[2])

    algorithm.setShapeImage(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    algorithm.setShapeImageType(shape_type)

    algorithm.setTopology(connectivity)
    algorithm.setTopologyLUTdirectory(topology_lut_dir)

    algorithm.setPropagationDirection(propagation)

    algorithm.setMinimumDistance(minimum_distance)

    # execute class
    try:
        algorithm.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs
    corrected_data = np.reshape(
        np.array(algorithm.getCorrectedImage(), dtype=np.float32), dimensions,
        'F')

    hdr['cal_min'] = np.nanmin(corrected_data)
    hdr['cal_max'] = np.nanmax(corrected_data)
    corrected = nb.Nifti1Image(corrected_data, aff, hdr)

    corrected_obj_data = np.reshape(
        np.array(algorithm.getCorrectedObjectImage(), dtype=np.int32),
        dimensions, 'F')

    hdr['cal_min'] = np.nanmin(corrected_obj_data)
    hdr['cal_max'] = np.nanmax(corrected_obj_data)
    corrected_obj = nb.Nifti1Image(corrected_obj_data, aff, hdr)

    if save_data:
        save_volume(corrected_file, corrected)
        save_volume(corrected_obj_file, corrected_obj)

    return {'corrected': corrected, 'object': corrected_obj}
コード例 #7
0
def levelset_thickness(input_image,
                       shape_image_type='signed_distance',
                       save_data=False,
                       overwrite=False,
                       output_dir=None,
                       file_name=None):
    """ Levelset Thickness

    Using a medial axis representation, derive a thickness map for a levelset surface


    Parameters
    ----------
    input_image: niimg
        Image containing structure-of-interest
    shape_image_type: str
        shape of the input image: either 'signed_distance', 'probability_map', or 'parcellation'.
    save_data: bool, optional
        Save output data to file (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * thickness (niimg): Estimated thickness map (_lth-map)
        * axis (niimg): Medial axis extracted (_lth-ax)
        * dist (niimg): Medial axis distance (_lth-dist)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    """

    print("\nLevelset Thickness")

    if save_data:
        output_dir = _output_dir_4saving(output_dir, input_image)

        thickness_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='lth-map'))

        axis_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='lth-ax'))

        dist_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='lth-dist'))

        if overwrite is False \
            and os.path.isfile(thickness_file) \
            and os.path.isfile(axis_file) \
            and os.path.isfile(dist_file) :
            output = {
                'thickness': thickness_file,
                'axis': axis_file,
                'dist': dist_file
            }
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    algorithm = nighresjava.LevelsetThickness()

    # set parameters
    algorithm.setShapeImageType(shape_image_type)

    # load images and set dimensions and resolution
    input_image = load_volume(input_image)
    data = input_image.get_data()
    affine = input_image.get_affine()
    header = input_image.get_header()
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = input_image.shape

    algorithm.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    algorithm.setResolutions(resolution[0], resolution[1], resolution[2])

    data = load_volume(input_image).get_data()
    if (shape_image_type == 'parcellation'):
        algorithm.setLabelImage(
            nighresjava.JArray('int')(
                (data.flatten('F')).astype(int).tolist()))
    else:
        algorithm.setShapeImage(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # execute
    try:
        algorithm.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # Collect output
    axis_data = np.reshape(
        np.array(algorithm.getMedialAxisImage(), dtype=np.float32), dimensions,
        'F')
    dist_data = np.reshape(
        np.array(algorithm.getMedialDistanceImage(), dtype=np.float32),
        dimensions, 'F')

    thickness_data = np.reshape(
        np.array(algorithm.geThicknessImage(), dtype=np.float32), dimensions,
        'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(axis_data)
    header['cal_max'] = np.nanmax(axis_data)
    axis_img = nb.Nifti1Image(axis_data, affine, header)

    header['cal_min'] = np.nanmin(dist_data)
    header['cal_max'] = np.nanmax(dist_data)
    dist_img = nb.Nifti1Image(dist_data, affine, header)

    header['cal_min'] = np.nanmin(thickness_data)
    header['cal_max'] = np.nanmax(thickness_data)
    thickness_img = nb.Nifti1Image(thickness_data, affine, header)

    if save_data:
        save_volume(axis_file, axis_img)
        save_volume(dist_file, dist_img)
        save_volume(thickness_file, thickness_img)

        return {
            'thickness': thickness_file,
            'axis': axis_file,
            'dist': dist_file
        }
    else:
        return {'thickness': thickness_img, 'axis': axis_img, 'dist': dist_img}
コード例 #8
0
def laminar_iterative_smoothing(profile_surface_image,
                                intensity_image,
                                fwhm_mm,
                                roi_mask_image=None,
                                save_data=False,
                                overwrite=False,
                                output_dir=None,
                                file_name=None):
    '''Smoothing data on multiple intracortical layers

    Parameters
    -----------
    data_image: niimg
        Image from which data should be sampled
    profile_surface_image: niimg
        4D image containing levelset representations of different intracortical
        surfaces on which data should be sampled
    fwhm_mm: float
        Full width half maximum distance to use in smoothing (in mm)
    roi_mask_image: niimg, optional
        Mask image defining a region of interest to restrict the smoothing
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    -----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): smoothed intensity image (_lis-smooth)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin

    Important: this method assumes isotropic voxels
    '''

    print('\nLaminar iterative smoothing')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, intensity_image)

        smoothed_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=intensity_image,
                           suffix='lis-smooth'))
        if overwrite is False \
            and os.path.isfile(smoothed_file) :

            print("skip computation (use existing results)")
            output = {"result": smoothed_file}
            return output

    # start VM if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # initate class
    smoother = nighresjava.LaminarIterativeSmoothing()

    # load the data
    surface_img = load_volume(profile_surface_image)
    surface_data = surface_img.get_fdata()
    layers = surface_data.shape[3] - 1

    intensity_img = load_volume(intensity_image)
    intensity_data = intensity_img.get_fdata()
    hdr = intensity_img.header
    aff = intensity_img.affine
    resolution = [x.item() for x in hdr.get_zooms()]
    dimensions = intensity_data.shape

    if (roi_mask_image != None):
        roi_mask_data = load_volume(data_image).get_fdata()
    else:
        roi_mask_data = None

    # pass inputs
    smoother.setIntensityImage(
        nighresjava.JArray('float')(
            (intensity_data.flatten('F')).astype(float)))
    smoother.setProfileSurfaceImage(
        nighresjava.JArray('float')((surface_data.flatten('F')).astype(float)))
    smoother.setResolutions(resolution[0], resolution[1], resolution[2])
    smoother.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    smoother.setLayers(layers)
    if (len(dimensions) > 3):
        smoother.set4thDimension(dimensions[3])
    else:
        smoother.set4thDimension(1)

    if (roi_mask_data != None):
        smoother.setROIMask(
            nighresjava.JArray('int')(
                (roi_mask_data.flatten('F')).astype(int).tolist()))
    smoother.setFWHMmm(float(fwhm_mm))

    # execute class
    try:
        smoother.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collecting outputs
    smoothed_data = np.reshape(
        np.array(smoother.getSmoothedIntensityImage(), dtype=np.float32),
        dimensions, 'F')

    hdr['cal_max'] = np.nanmax(smoothed_data)
    smoothed = nb.Nifti1Image(smoothed_data, aff, hdr)

    if save_data:
        save_volume(smoothed_file, smoothed)
        return {"result": smoothed_file}
    else:
        return {"result": smoothed}
コード例 #9
0
def apply_coordinate_mappings_2d(image,
                                 mapping1,
                                 mapping2=None,
                                 mapping3=None,
                                 mapping4=None,
                                 interpolation="nearest",
                                 padding="closest",
                                 save_data=False,
                                 overwrite=False,
                                 output_dir=None,
                                 file_name=None):
    '''Apply a 2D coordinate mapping (or a succession of coordinate mappings) to
        a 2D or 3D image.

    Parameters
    ----------
    image: niimg
        Image to deform
    mapping1 : niimg
        First coordinate mapping to apply
    mapping2 : niimg, optional
        Second coordinate mapping to apply
    mapping3 : niimg, optional
        Third coordinate mapping to apply
    mapping4 : niimg, optional
        Fourth coordinate mapping to apply
    interpolation: {'nearest', 'linear'}
        Interpolation method (default is 'nearest')
    padding: {'closest', 'zero', 'max'}
        Image padding method (default is 'closest')
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): Result image (_def-img)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin

    '''

    print('\nApply coordinate mappings (2D)')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image)

        deformed_file = os.path.join(
            output_dir,
            _fname_4saving(file_name=file_name,
                           rootfile=image,
                           suffix='def-img'))
        if overwrite is False \
            and os.path.isfile(deformed_file) :

            print("skip computation (use existing results)")
            output = {'result': load_volume(deformed_file)}
            return output

    # start virutal machine if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # initate class
    applydef = nighresjava.RegistrationApplyDeformations2D()

    # load the data
    img = load_volume(image)
    data = img.get_data()
    hdr = img.header
    aff = img.affine
    imgres = [x.item() for x in hdr.get_zooms()]
    imgdim = data.shape

    # set parameters from input images
    if len(imgdim) is 3:
        applydef.setImageDimensions(imgdim[0], imgdim[1], imgdim[2])
    else:
        applydef.setImageDimensions(imgdim[0], imgdim[1])
    applydef.setImageResolutions(imgres[0], imgres[1])

    applydef.setImageToDeform(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    def1 = load_volume(mapping1)
    def1data = def1.get_data()
    aff = def1.affine
    hdr = def1.header
    trgdim = def1data.shape
    applydef.setDeformationMapping1(
        nighresjava.JArray('float')((def1data.flatten('F')).astype(float)))
    applydef.setDeformation1Dimensions(def1data.shape[0], def1data.shape[1])
    applydef.setDeformationType1("mapping(voxels)")

    if not (mapping2 == None):
        def2 = load_volume(mapping2)
        def2data = def2.get_data()
        aff = def2.affine
        hdr = def2.header
        trgdim = def2data.shape
        applydef.setDeformationMapping2(
            nighresjava.JArray('float')((def2data.flatten('F')).astype(float)))
        applydef.setDeformation2Dimensions(def2data.shape[0],
                                           def2data.shape[1])
        applydef.setDeformationType2("mapping(voxels)")

        if not (mapping3 == None):
            def3 = load_volume(mapping3)
            def3data = def3.get_data()
            aff = def3.affine
            hdr = def3.header
            trgdim = def3data.shape
            applydef.setDeformationMapping3(
                nighresjava.JArray('float')(
                    (def3data.flatten('F')).astype(float)))
            applydef.setDeformation3Dimensions(def3data.shape[0],
                                               def3data.shape[1])
            applydef.setDeformationType3("mapping(voxels)")

            if not (mapping4 == None):
                def4 = load_volume(mapping4)
                def4data = def4.get_data()
                aff = def4.affine
                hdr = def4.header
                trgdim = def4data.shape
                applydef.setDeformationMapping4(
                    nighresjava.JArray('float')(
                        (def4data.flatten('F')).astype(float)))
                applydef.setDeformation4Dimensions(def4data.shape[0],
                                                   def4data.shape[1])
                applydef.setDeformationType4("mapping(voxels)")

    applydef.setInterpolationType(interpolation)
    applydef.setImagePadding(padding)

    # execute class
    try:
        applydef.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect data
    if len(imgdim) is 3:
        trgdim = [trgdim[0], trgdim[1], imgdim[2]]
    else:
        trgdim = [trgdim[0], trgdim[1]]
    deformed_data = np.reshape(
        np.array(applydef.getDeformedImage(), dtype=np.float32), trgdim, 'F')
    hdr['cal_min'] = np.nanmin(deformed_data)
    hdr['cal_max'] = np.nanmax(deformed_data)
    deformed = nb.Nifti1Image(deformed_data, aff, hdr)

    if save_data:
        save_volume(deformed_file, deformed)

    return {'result': deformed}
コード例 #10
0
def mgdm_segmentation(contrast_image1,
                      contrast_type1,
                      contrast_image2=None,
                      contrast_type2=None,
                      contrast_image3=None,
                      contrast_type3=None,
                      contrast_image4=None,
                      contrast_type4=None,
                      n_steps=5,
                      max_iterations=800,
                      topology='wcs',
                      atlas_file=None,
                      topology_lut_dir=None,
                      adjust_intensity_priors=False,
                      normalize_qmaps=True,
                      compute_posterior=False,
                      posterior_scale=5.0,
                      diffuse_probabilities=False,
                      save_data=False,
                      overwrite=False,
                      output_dir=None,
                      file_name=None):
    """ MGDM segmentation

    Estimates brain structures from an atlas for MRI data using
    a Multiple Object Geometric Deformable Model (MGDM)

    Parameters
    ----------
    contrast_image1: niimg
        First input image to perform segmentation on
    contrast_type1: str
        Contrast type of first input image, must be listed as a prior in used
        atlas(specified in atlas_file). Possible inputs by default are DWIFA3T,
        DWIMD3T, T1map9T, Mp2rage9T, T1map7T, Mp2rage7T, PV, Filters, T1pv,
        Mprage3T, T1map3T, Mp2rage3T, HCPT1w, HCPT2w, NormMPRAGE.
    contrast_image2: niimg, optional
        Additional input image to inform segmentation, must be in the same
        space as constrast_image1, requires contrast_type2
    contrast_type2: str, optional
        Contrast type of second input image, must be listed as a prior in used
        atlas (specified in atlas_file). Possible inputs by default are the same
        as with parameter contrast_type1 (see above).
    contrast_image3: niimg, optional
        Additional input image to inform segmentation, must be in the same
        space as constrast_image1, requires contrast_type3
    contrast_type3: str, optional
        Contrast type of third input image, must be listed as a prior in used
        atlas (specified in atlas_file). Possible inputs by default are the same
        as with parameter contrast_type1 (see above).
    contrast_image4: niimg, optional
        Additional input image to inform segmentation, must be in the same
        space as constrast_image1, requires contrast_type4
    contrast_type4: str, optional
        Contrast type of fourth input image, must be listed as a prior in used
        atlas (specified in atlas_file). Possible inputs by default are the same
        as with parameter contrast_type1 (see above).
    n_steps: int, optional
        Number of steps for MGDM (default is 5, set to 0 for quick testing of
        registration of priors, which does not perform true segmentation)
    max_iterations: int, optional
        Maximum number of iterations per step for MGDM (default is 800, set
        to 1 for quick testing of registration of priors, which does not
        perform true segmentation)
    topology: {'wcs', 'no'}, optional
        Topology setting, choose 'wcs' (well-composed surfaces) for strongest
        topology constraint, 'no' for no topology constraint (default is 'wcs')
    atlas_file: str, optional
        Path to plain text atlas file (default is stored in DEFAULT_ATLAS)
        or atlas name to be searched in ATLAS_DIR
    topology_lut_dir: str, optional
        Path to directory in which topology files are stored (default is stored
        in TOPOLOGY_LUT_DIR)
    normalize_qmaps: bool
        Normalize quantitative maps into [0,1] (default is False)
    adjust_intensity_priors: bool
        Adjust intensity priors based on dataset (default is False)
    normalize_qmaps: bool
        Normalize quantitative maps in [0,1] (default in True, change this if using
        one of the -quant atlas text files in ATLAS_DIR) 
    compute_posterior: bool
        Compute posterior probabilities for segmented structures
        (default is False)
    posterior_scale: float
        Posterior distance scale from segmented structures to compute posteriors
        (default is 5.0 mm)
    diffuse_probabilities: bool
        Regularize probability distribution with a non-linear diffusion scheme
        (default is False)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * segmentation (niimg): Hard brain segmentation with topological
          constraints (if chosen) (_mgdm_seg)
        * labels (niimg): Maximum tissue probability labels (_mgdm_lbls)
        * memberships (niimg): Maximum tissue probability values, 4D image
          where the first dimension shows each voxel's highest probability to
          belong to a specific tissue, the second dimension shows the second
          highest probability to belong to another tissue etc. (_mgdm_mems)
        * distance (niimg): Minimum distance to a segmentation boundary
          (_mgdm_dist)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Algorithm details can be
    found in [1]_ and [2]_

    References
    ----------
    .. [1] Bazin et al. (2014). A computational framework for ultra-high 
       resolution cortical segmentation at 7 Tesla.
       doi: 10.1016/j.neuroimage.2013.03.077
    .. [2] Bogovic et al. (2013). A multiple object geometric deformable model 
       for image segmentation.
       doi:10.1016/j.cviu.2012.10.006.A
    """

    print('\nMGDM Segmentation')

    # Check data file parameters
    if not save_data and return_filename:
        raise ValueError('save_data must be True if return_filename is True ')

    # check atlas_file and set default if not given
    atlas_file = _check_atlas_file(atlas_file)

    # check topology_lut_dir and set default if not given
    topology_lut_dir = _check_topology_lut_dir(topology_lut_dir)

    # find available intensity priors in selected MGDM atlas
    mgdm_intensity_priors = _get_mgdm_intensity_priors(atlas_file)

    # sanity check contrast types
    contrasts = [
        contrast_image1, contrast_image2, contrast_image3, contrast_image4
    ]
    ctypes = [contrast_type1, contrast_type2, contrast_type3, contrast_type4]
    for idx, ctype in enumerate(ctypes):
        if ctype is None and contrasts[idx] is not None:
            raise ValueError(
                ("If specifying contrast_image{0}, please also "
                 "specify contrast_type{0}".format(idx + 1, idx + 1)))

        elif ctype is not None and ctype not in mgdm_intensity_priors:
            raise ValueError(("{0} is not a valid contrast type for  "
                              "contrast_type{1} please choose from the "
                              "following contrasts provided by the chosen "
                              "atlas: ").format(ctype, idx + 1),
                             ", ".join(mgdm_intensity_priors))

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, contrast_image1)

        seg_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=contrast_image1,
                suffix='mgdm-seg',
            ))

        lbl_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=contrast_image1,
                           suffix='mgdm-lbls'))

        mems_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=contrast_image1,
                           suffix='mgdm-mems'))

        dist_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=contrast_image1,
                           suffix='mgdm-dist'))
        if overwrite is False \
            and os.path.isfile(seg_file) \
            and os.path.isfile(lbl_file) \
            and os.path.isfile(mems_file) \
            and os.path.isfile(dist_file) :

            print("skip computation (use existing results)")
            output = {
                'segmentation': seg_file,
                'labels': lbl_file,
                'memberships': mems_file,
                'distance': dist_file
            }
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create mgdm instance
    mgdm = nighresjava.BrainMgdmMultiSegmentation2()

    # set mgdm parameters
    mgdm.setAtlasFile(atlas_file)
    mgdm.setTopologyLUTdirectory(topology_lut_dir)
    mgdm.setOutputImages('label_memberships')
    mgdm.setAdjustIntensityPriors(adjust_intensity_priors)
    mgdm.setComputePosterior(compute_posterior)
    mgdm.setPosteriorScale_mm(posterior_scale)
    mgdm.setDiffuseProbabilities(diffuse_probabilities)
    mgdm.setSteps(n_steps)
    mgdm.setMaxIterations(max_iterations)
    mgdm.setTopology(topology)
    mgdm.setNormalizeQuantitativeMaps(normalize_qmaps)
    # set to False for "quantitative" brain prior atlases
    # (version quant-3.0.5 and above)

    # load contrast image 1 and use it to set dimensions and resolution
    img = load_volume(contrast_image1)
    data = img.get_data()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    mgdm.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    mgdm.setResolutions(resolution[0], resolution[1], resolution[2])

    # convert orientation information to mgdm slice and orientation info
    sliceorder, LR, AP, IS = _get_mgdm_orientation(affine, mgdm)
    mgdm.setOrientations(sliceorder, LR, AP, IS)

    # input image 1
    mgdm.setContrastImage1(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))
    mgdm.setContrastType1(contrast_type1)

    # if further contrast are specified, input them
    if contrast_image2 is not None:
        data = load_volume(contrast_image2).get_data()
        mgdm.setContrastImage2(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))
        mgdm.setContrastType2(contrast_type2)

        if contrast_image3 is not None:
            data = load_volume(contrast_image3).get_data()
            mgdm.setContrastImage3(
                nighresjava.JArray('float')((data.flatten('F')).astype(float)))
            mgdm.setContrastType3(contrast_type3)

            if contrast_image4 is not None:
                data = load_volume(contrast_image4).get_data()
                mgdm.setContrastImage4(
                    nighresjava.JArray('float')(
                        (data.flatten('F')).astype(float)))
                mgdm.setContrastType4(contrast_type4)

    # execute MGDM
    try:
        mgdm.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    seg_data = np.reshape(
        np.array(mgdm.getSegmentedBrainImage(), dtype=np.int32), dimensions,
        'F')

    dist_data = np.reshape(
        np.array(mgdm.getLevelsetBoundaryImage(), dtype=np.float32),
        dimensions, 'F')

    # membership and labels output has a 4th dimension, set to 6
    dimensions4d = [dimensions[0], dimensions[1], dimensions[2], 6]
    lbl_data = np.reshape(
        np.array(mgdm.getPosteriorMaximumLabels4D(), dtype=np.int32),
        dimensions4d, 'F')
    mems_data = np.reshape(
        np.array(mgdm.getPosteriorMaximumMemberships4D(), dtype=np.float32),
        dimensions4d, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_max'] = np.nanmax(seg_data)
    seg = nb.Nifti1Image(seg_data, affine, header)

    header['cal_max'] = np.nanmax(dist_data)
    dist = nb.Nifti1Image(dist_data, affine, header)

    header['cal_max'] = np.nanmax(lbl_data)
    lbls = nb.Nifti1Image(lbl_data, affine, header)

    header['cal_max'] = np.nanmax(mems_data)
    mems = nb.Nifti1Image(mems_data, affine, header)

    if save_data:
        save_volume(seg_file, seg)
        save_volume(dist_file, dist)
        save_volume(lbl_file, lbls)
        save_volume(mems_file, mems)
        output = {
            'segmentation': seg_file,
            'labels': lbl_file,
            'memberships': mems_file,
            'distance': dist_file
        }
    else:
        output = {
            'segmentation': seg,
            'labels': lbls,
            'memberships': mems,
            'distance': dist
        }

    return output
コード例 #11
0
def multiscale_vessel_filter(input_image,
                             structure_intensity='bright',
                             filterType='RRF',
                             propagationtype='diffusion',
                             threshold=0.5,
                             factor=0.5,
                             max_diff=0.001,
                             max_itr=100,
                             scale_step=1.0,
                             scales=4,
                             prior_image=None,
                             invert_prior=False,
                             save_data=False,
                             overwrite=False,
                             output_dir=None,
                             file_name=None):
    """ Vessel filter with prior

    Uses an image filter to make a probabilistic image of ridge
    structures.


    Parameters
    ----------
    input_image: niimg
        Image containing structure-of-interest
    structure_intensity: str
        Image intensity of structure-of-interest 'bright', 'dark', or 'both'
        (default is 'bright').
    filterType: str
	    Decide for a filter type: either RRF or Hessian (default is 'RRF')
    propagationtype: str
	    Set the diffusion model of the filter: either 'diffusion' or 'belief'
	    propagation model (default is 'diffusion')
    threshold: float
	    Set the propability treshold to decide at what probability the detected
	    structure should be seen as a vessel (default is 0.5)
    factor: float
	    Diffusion factor between 0 and 100 (default is 0.5)
    max_diff: float
	    maximal difference for stopping (default is 0.001)
    max_itr: int
	    maximale iteration number (default is 100)
    scale_step: float
	    Scaling step between diameters (default is 1)
    scales: int
	    Number of scales to use (default is 4)
    prior_image: niimg (opt)
        Image prior for the region to include (positive) or exclude (negative)
    invert_prior: boolean, optional (default is False)
 	    In case there is a prior, the prior can be considered as negative prior
 	    (False) or as positive prior (True)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * segmentation: segmented vessel centerlines (_mvf-seg)
        * filtered: result of the vessel filtering step (_mvf-filter)
        * probability: probability score of segmented centerlines (_mvf-proba)
        * scale: discrete scale at which the centerlines are detected (_mvf-scale)
        * diameter: estimated vessel diameter (_mvf-dia)
        * length: lenght of continuous vessel segments (_mvf-length)
        * pv: partial volume estimate of vessels (_mvf-pv)
        * label: labeling of individual vessel segments (_mvf-label)
        * direction: estimated vessel direction (_mvf-dir)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin and Julia Huck.
    """

    print('\n Multiscale Vessel Filter')

    if save_data:
        output_dir = _output_dir_4saving(output_dir, input_image)

        vesselImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-seg'))

        filterImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-filter'))

        probaImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-proba'))

        scaleImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-scale'))

        diameterImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-dia'))

        lengthImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-length'))

        pvImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-pv'))

        labelImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-label'))

        directionImage_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=input_image,
                           suffix='mvf-dir'))

        if overwrite is False \
            and os.path.isfile(vesselImage_file) \
            and os.path.isfile(filterImage_file) \
            and os.path.isfile(probaImage_file) \
            and os.path.isfile(scaleImage_file) \
            and os.path.isfile(diameterImage_file) \
            and os.path.isfile(pvImage_file) \
            and os.path.isfile(lengthImage_file) \
            and os.path.isfile(labelImage_file) \
     and os.path.isfile(directionImage_file) :
            output = {
                'segmentation': vesselImage_file,
                'filtered': filterImage_file,
                'probability': probaImage_file,
                'scale': scaleImage_file,
                'diameter': diameterImage_file,
                'pv': pvImage_file,
                'length': lengthImage_file,
                'label': labelImage_file,
                'direction': directionImage_file
            }
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    vessel_filter = nighresjava.MultiscaleVesselFilter()

    # set parameters
    vessel_filter.setStructureIntensity(structure_intensity)
    vessel_filter.setFilterShape(filterType)
    vessel_filter.setThreshold(threshold)
    vessel_filter.setScaleStep(scale_step)
    vessel_filter.setScaleNumber(scales)
    vessel_filter.setPropagationModel(propagationtype)
    vessel_filter.setDiffusionFactor(factor)
    vessel_filter.setMaxDiff(max_diff)
    vessel_filter.setMaxItr(max_itr)
    vessel_filter.setInvertPrior(invert_prior)

    # load images and set dimensions and resolution
    input_image = load_volume(input_image)
    data = input_image.get_data()
    affine = input_image.get_affine()
    header = input_image.get_header()
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = input_image.shape

    # direction output has a 4th dimension, set to 3
    dimensions4d = [dimensions[0], dimensions[1], dimensions[2], 3]

    vessel_filter.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    vessel_filter.setResolutions(resolution[0], resolution[1], resolution[2])

    data = load_volume(input_image).get_data()
    vessel_filter.setInputImage(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    if not (prior_image == None):
        prior = load_volume(prior_image)
        data_prior = prior.get_data()
        vessel_filter.setPriorImage(
            nighresjava.JArray('float')(
                (data_prior.flatten('F')).astype(float)))

    # execute
    try:
        vessel_filter.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # Collect output
    vesselImage_data = np.reshape(
        np.array(vessel_filter.getSegmentedVesselImage(), dtype=np.float32),
        dimensions, 'F')
    filterImage_data = np.reshape(
        np.array(vessel_filter.getFilteredImage(), dtype=np.float32),
        dimensions, 'F')
    probaImage_data = np.reshape(
        np.array(vessel_filter.getProbabilityImage(), dtype=np.float32),
        dimensions, 'F')
    scaleImage_data = np.reshape(
        np.array(vessel_filter.getScaleImage(), dtype=np.float32), dimensions,
        'F')
    diameterImage_data = np.reshape(
        np.array(vessel_filter.getDiameterImage(), dtype=np.float32),
        dimensions, 'F')
    pvImage_data = np.reshape(
        np.array(vessel_filter.getPVimage(), dtype=np.float32), dimensions,
        'F')
    lengthImage_data = np.reshape(
        np.array(vessel_filter.getLengthImage(), dtype=np.float32), dimensions,
        'F')
    labelImage_data = np.reshape(
        np.array(vessel_filter.getLabelImage(), dtype=np.float32), dimensions,
        'F')
    directionImage_data = np.reshape(
        np.array(vessel_filter.getDirectionImage(), dtype=np.float32),
        dimensions4d, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_max'] = np.nanmax(vesselImage_data)
    vesselImage = nb.Nifti1Image(vesselImage_data, affine, header)

    header['cal_max'] = np.nanmax(filterImage_data)
    filterImage = nb.Nifti1Image(filterImage_data, affine, header)

    header['cal_max'] = np.nanmax(probaImage_data)
    probaImage = nb.Nifti1Image(probaImage_data, affine, header)

    header['cal_max'] = np.nanmax(scaleImage_data)
    scaleImage = nb.Nifti1Image(scaleImage_data, affine, header)

    header['cal_max'] = np.nanmax(diameterImage_data)
    diameterImage = nb.Nifti1Image(diameterImage_data, affine, header)

    header['cal_max'] = np.nanmax(pvImage_data)
    pvImage = nb.Nifti1Image(pvImage_data, affine, header)

    header['cal_max'] = np.nanmax(lengthImage_data)
    lengthImage = nb.Nifti1Image(lengthImage_data, affine, header)

    header['cal_max'] = np.nanmax(labelImage_data)
    labelImage = nb.Nifti1Image(labelImage_data, affine, header)

    header['cal_max'] = np.nanmax(directionImage_data)
    directionImage = nb.Nifti1Image(directionImage_data, affine, header)

    if save_data:
        save_volume(vesselImage_file, vesselImage)
        save_volume(filterImage_file, filterImage)
        save_volume(probaImage_file, probaImage)
        save_volume(scaleImage_file, scaleImage)
        save_volume(diameterImage_file, diameterImage)
        save_volume(pvImage_file, pvImage)
        save_volume(lengthImage_file, lengthImage)
        save_volume(labelImage_file, labelImage)
        save_volume(directionImage_file, directionImage)

        return {
            'segmentation': vesselImage_file,
            'filtered': filterImage_file,
            'probability': probaImage_file,
            'scale': scaleImage_file,
            'diameter': diameterImage_file,
            'pv': pvImage_file,
            'length': lengthImage_file,
            'label': labelImage_file,
            'direction': directionImage_file
        }
    else:
        return {
            'segmentation': vesselImage,
            'filtered': filterImage,
            'probability': probaImage,
            'scale': scaleImage,
            'diameter': diameterImage,
            'pv': pvImage,
            'length': lengthImage,
            'label': labelImage,
            'direction': directionImage
        }
コード例 #12
0
ファイル: massp.py プロジェクト: thm200103/nighres
def massp_atlasing(subjects,
                   structures,
                   contrasts,
                   levelset_images=None,
                   skeleton_images=None,
                   contrast_images=None,
                   save_data=False,
                   overwrite=False,
                   output_dir=None,
                   file_name=None):
    """ MASSP Atlasing

    Builds a multi-atlas prior for MASSP

    Parameters
    ----------
    subjects: int
        Number of atlas subjects
    structures: int
        Number of structures to parcellate
    contrasts: int
       Number of image intensity contrasts
    levelset_images: [niimg]
        Atlas shape levelsets indexed by (subjects,structures)
    skeleton_images: [niimg]
        Atlas shape skeletons indexed by (subjects,structures)
    contrast_images: [niimg]
        Atlas images to use in the parcellation, indexed by (subjects, contrasts)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * max_spatial_proba (niimg): Maximum spatial probability map (_massp-sproba)
        * max_spatial_label (niimg): Maximum spatial probability labels (_massp-slabel)
        * cond_hist (niimg): Conditional intensity histograms (_massp-chist)
        * max_skeleton_proba (niimg): Maximum skeleton probability map (_massp-kproba)
        * max_skeleton_label (niimg): Maximum skeleton probability labels (_massp-klabel)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    """

    print('\nMASSP Atlasing')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, contrast_images[0][0])

        spatial_proba_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=contrast_images[0][0],
                suffix='massp-sproba',
            ))

        spatial_label_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=contrast_images[0][0],
                           suffix='massp-slabel'))

        condhist_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=contrast_images[0][0],
                           suffix='massp-chist'))

        skeleton_proba_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=contrast_images[0][0],
                suffix='massp-kproba',
            ))

        skeleton_label_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=contrast_images[0][0],
                           suffix='massp-klabel'))


        if overwrite is False \
            and os.path.isfile(spatial_proba_file) \
            and os.path.isfile(spatial_label_file) \
            and os.path.isfile(condhist_file) \
            and os.path.isfile(skeleton_proba_file) \
            and os.path.isfile(skeleton_label_file):

            print("skip computation (use existing results)")
            output = {
                'max_spatial_proba': spatial_proba_file,
                'max_spatial_label': spatial_label_file,
                'cond_hist': condhist_file,
                'max_skeleton_proba': skeleton_proba_file,
                'max_skeleton_label': skeleton_label_file
            }

            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    massp = nighresjava.ConditionalShapeSegmentation()

    # set parameters
    massp.setNumberOfSubjectsObjectsBgAndContrasts(subjects, structures, 1,
                                                   contrasts)
    massp.setOptions(True, False, False, False, True)

    # load target image for parameters
    # load a first image for dim, res
    img = load_volume(contrast_images[0][0])
    data = img.get_data()
    header = img.get_header()
    affine = img.get_affine()
    trg_resolution = [x.item() for x in header.get_zooms()]
    trg_dimensions = data.shape

    massp.setTargetDimensions(trg_dimensions[0], trg_dimensions[1],
                              trg_dimensions[2])
    massp.setTargetResolutions(trg_resolution[0], trg_resolution[1],
                               trg_resolution[2])

    resolution = trg_resolution
    dimensions = trg_dimensions

    massp.setAtlasDimensions(dimensions[0], dimensions[1], dimensions[2])
    massp.setAtlasResolutions(resolution[0], resolution[1], resolution[2])

    # load the atlas structures and contrasts, if needed
    for sub in range(subjects):
        for struct in range(structures):
            print("load: " + str(levelset_images[sub][struct]))
            data = load_volume(levelset_images[sub][struct]).get_data()
            massp.setLevelsetImageAt(
                sub, struct,
                nighresjava.JArray('float')((data.flatten('F')).astype(float)))
        for contrast in range(contrasts):
            print("load: " + str(contrast_images[sub][contrast]))
            data = load_volume(contrast_images[sub][contrast]).get_data()
            massp.setContrastImageAt(
                sub, contrast,
                nighresjava.JArray('float')((data.flatten('F')).astype(float)))
    # execute first step
    scale = 1.0
    try:
        scale = massp.computeAtlasPriors()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # clean up and go to second step
    levelset_images = None
    contrast_images = None

    for sub in range(subjects):
        for struct in range(structures):
            print("load: " + str(skeleton_images[sub][struct]))
            data = load_volume(skeleton_images[sub][struct]).get_data()
            massp.setSkeletonImageAt(
                sub, struct,
                nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    try:
        massp.computeSkeletonPriors(scale)

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    skeleton_images = None

    # reshape output to what nibabel likes
    dimensions = (dimensions[0], dimensions[1], dimensions[2],
                  massp.getBestDimension())
    dimskel = (dimensions[0], dimensions[1], dimensions[2],
               int(massp.getBestDimension() / 4))
    dims3Dtrg = (trg_dimensions[0], trg_dimensions[1], trg_dimensions[2])

    intens_dims = (structures + 1, structures + 1, contrasts)
    intens_hist_dims = ((structures + 1) * (structures + 1),
                        massp.getNumberOfBins() + 6, contrasts)

    spatial_proba_data = np.reshape(
        np.array(massp.getBestSpatialProbabilityMaps(dimensions[3]),
                 dtype=np.float32), dimensions, 'F')

    spatial_label_data = np.reshape(
        np.array(massp.getBestSpatialProbabilityLabels(dimensions[3]),
                 dtype=np.int32), dimensions, 'F')

    intens_hist_data = np.reshape(
        np.array(massp.getConditionalHistogram(), dtype=np.float32),
        intens_hist_dims, 'F')

    skeleton_proba_data = np.reshape(
        np.array(massp.getBestSkeletonProbabilityMaps(dimskel[3]),
                 dtype=np.float32), dimskel, 'F')

    skeleton_label_data = np.reshape(
        np.array(massp.getBestSkeletonProbabilityLabels(dimskel[3]),
                 dtype=np.int32), dimskel, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_max'] = np.nanmax(spatial_proba_data)
    spatial_proba = nb.Nifti1Image(spatial_proba_data, affine, header)

    header['cal_max'] = np.nanmax(spatial_label_data)
    spatial_label = nb.Nifti1Image(spatial_label_data, affine, header)

    chist = nb.Nifti1Image(intens_hist_data, None, None)

    header['cal_max'] = np.nanmax(skeleton_proba_data)
    skeleton_proba = nb.Nifti1Image(skeleton_proba_data, affine, header)

    header['cal_max'] = np.nanmax(skeleton_label_data)
    skeleton_label = nb.Nifti1Image(skeleton_label_data, affine, header)

    if save_data:
        save_volume(spatial_proba_file, spatial_proba)
        save_volume(spatial_label_file, spatial_label)
        save_volume(condhist_file, chist)
        save_volume(skeleton_proba_file, skeleton_proba)
        save_volume(skeleton_label_file, skeleton_label)
        output = {
            'max_spatial_proba': spatial_proba_file,
            'max_spatial_label': spatial_label_file,
            'cond_hist': condhist_file,
            'max_skeleton_proba': skeleton_proba_file,
            'max_skeleton_label': skeleton_label_file
        }
        return output
    else:
        output = {
            'max_spatial_proba': spatial_proba,
            'max_spatial_label': spatial_label,
            'cond_hist': chist,
            'max_skeleton_proba': skeleton_proba,
            'max_skeleton_label': skeleton_label
        }
        return output
コード例 #13
0
ファイル: massp.py プロジェクト: thm200103/nighres
def massp(target_images,
          structures=31,
          shape_atlas_probas=None,
          shape_atlas_labels=None,
          intensity_atlas_hist=None,
          skeleton_atlas_probas=None,
          skeleton_atlas_labels=None,
          map_to_target=None,
          max_iterations=80,
          max_difference=0.1,
          save_data=False,
          overwrite=False,
          output_dir=None,
          file_name=None):
    """ Multi-contrast Anatomical Subcortical Structure parcellation (MASSP)

    Estimates subcortical structures based on a multi-atlas approach on shape

    Parameters
    ----------
    target_images: [niimg]
        Input images to perform the parcellation from
    structures: int
        Number of structures to parcellate
    shape_atlas_probas: niimg (opt)
        Pre-computed shape atlas probabilities (default is loaded from nighres atlas)
    shape_atlas_labels: niimg (opt)
        Pre-computed shape atlas labels (default is loaded from nighres atlas)
    intensity_atlas_hist: niimg (opt)
        Pre-computed intensity atlas from the contrast images  (default is loaded from nighres atlas)
    skeleton_atlas_probas: niimg (opt)
        Pre-computed skeleton atlas probabilities (default is loaded from nighres atlas)
    skeleton_atlas_labels: niimg (opt)
        Pre-computed skeleton atlas labels (default is loaded from nighres atlas)
    map_to_target: niimg
        Coordinate mapping from the atlas to the target (opt)
    max_iterations: int
        Maximum number of diffusion iterations to perform
    max_difference: float
        Maximum difference between diffusion steps
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * max_proba (niimg): Maximum probability map (_massp-proba)
        * max_label (niimg): Maximum probability labels (_massp-label)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    """

    print('\nMASSP')

    # check topology_lut_dir and set default if not given
    topology_lut_dir = _check_topology_lut_dir(None)

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, target_images[0])

        proba_file = os.path.join(
            output_dir,
            _fname_4saving(
                module=__name__,
                file_name=file_name,
                rootfile=target_images[0],
                suffix='massp-proba',
            ))

        label_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=target_images[0],
                           suffix='massp-label'))

        if overwrite is False \
            and os.path.isfile(proba_file) \
            and os.path.isfile(label_file):

            print("skip computation (use existing results)")
            output = {'max_proba': proba_file, 'max_label': label_file}
            return output

    contrasts = len(target_images)

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    massp = nighresjava.ConditionalShapeSegmentation()

    # set parameters
    massp.setNumberOfSubjectsObjectsBgAndContrasts(1, structures, 1, contrasts)
    massp.setOptions(True, False, False, False, True)
    massp.setDiffusionParameters(max_iterations, max_difference)

    # load target image for parameters
    print("load: " + str(target_images[0]))
    img = load_volume(target_images[0])
    data = img.get_data()
    trg_affine = img.get_affine()
    trg_header = img.get_header()
    trg_resolution = [x.item() for x in trg_header.get_zooms()]
    trg_dimensions = data.shape

    massp.setTargetDimensions(trg_dimensions[0], trg_dimensions[1],
                              trg_dimensions[2])
    massp.setTargetResolutions(trg_resolution[0], trg_resolution[1],
                               trg_resolution[2])

    # target image 1
    massp.setTargetImageAt(
        0,
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # if further contrast are specified, input them
    for contrast in range(1, contrasts):
        print("load: " + str(target_images[contrast]))
        data = load_volume(target_images[contrast]).get_data()
        massp.setTargetImageAt(
            contrast,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # if not specified, check if standard atlases are available or download them
    if ((intensity_atlas_hist is None) or (shape_atlas_probas is None)
            or (shape_atlas_labels is None) or (skeleton_atlas_probas is None)
            or (skeleton_atlas_labels is None)):

        if (not os.path.exists(DEFAULT_MASSP_ATLAS)):
            download_MASSP_atlas(overwrite=False)

        intensity_atlas_hist = DEFAULT_MASSP_HIST
        shape_atlas_probas = DEFAULT_MASSP_SPATIAL_PROBA
        shape_atlas_labels = DEFAULT_MASSP_SPATIAL_LABEL
        skeleton_atlas_probas = DEFAULT_MASSP_SKEL_PROBA
        skeleton_atlas_labels = DEFAULT_MASSP_SKEL_LABEL

    # load the shape and intensity atlases
    print("load: " + str(intensity_atlas_hist))
    hist = load_volume(intensity_atlas_hist).get_data()
    massp.setConditionalHistogram(
        nighresjava.JArray('float')((hist.flatten('F')).astype(float)))

    print("load: " + str(shape_atlas_probas))

    # load a first image for dim, res
    img = load_volume(shape_atlas_probas)
    pdata = img.get_data()
    header = img.get_header()
    affine = img.get_affine()
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = pdata.shape

    massp.setAtlasDimensions(dimensions[0], dimensions[1], dimensions[2])
    massp.setAtlasResolutions(resolution[0], resolution[1], resolution[2])

    print("load: " + str(shape_atlas_labels))
    ldata = load_volume(shape_atlas_labels).get_data()

    if map_to_target is not None:
        print("map atlas to subject")
        print("load: " + str(map_to_target))
        mdata = load_volume(map_to_target).get_data()
        massp.setMappingToTarget(
            nighresjava.JArray('float')((mdata.flatten('F')).astype(float)))

    massp.setShapeAtlasProbasAndLabels(
        nighresjava.JArray('float')((pdata.flatten('F')).astype(float)),
        nighresjava.JArray('int')((ldata.flatten('F')).astype(int).tolist()))

    print("load: " + str(skeleton_atlas_probas))
    pdata = load_volume(skeleton_atlas_probas).get_data()

    print("load: " + str(skeleton_atlas_labels))
    ldata = load_volume(skeleton_atlas_labels).get_data()

    massp.setSkeletonAtlasProbasAndLabels(
        nighresjava.JArray('float')((pdata.flatten('F')).astype(float)),
        nighresjava.JArray('int')((ldata.flatten('F')).astype(int).tolist()))

    # execute
    try:
        massp.estimateTarget()
        massp.fastSimilarityDiffusion(4)
        massp.collapseToJointMaps()
        massp.precomputeStoppingStatistics(3.0)
        massp.topologyBoundaryDefinition("wcs", topology_lut_dir)
        massp.conditionalPrecomputedDirectVolumeGrowth(3.0)
        massp.collapseSpatialPriorMaps()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    dims3Dtrg = (trg_dimensions[0], trg_dimensions[1], trg_dimensions[2])

    proba_data = np.reshape(np.array(massp.getFinalProba(), dtype=np.float32),
                            dims3Dtrg, 'F')

    label_data = np.reshape(np.array(massp.getFinalLabel(), dtype=np.int32),
                            dims3Dtrg, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    trg_header['cal_max'] = np.nanmax(proba_data)
    proba = nb.Nifti1Image(proba_data, trg_affine, trg_header)

    trg_header['cal_max'] = np.nanmax(label_data)
    label = nb.Nifti1Image(label_data, trg_affine, trg_header)

    if save_data:
        save_volume(proba_file, proba)
        save_volume(label_file, label)

        output = {'max_proba': proba_file, 'max_label': label_file}
        return output
    else:
        output = {'max_proba': proba, 'max_label': label}
        return output
コード例 #14
0
def intensity_based_skullstripping(main_image, extra_image=None,
                            noise_model='exponential', skip_zero_values=True,
                            iterate=False, dilate_mask=0, topology_lut_dir=None,
                            save_data=False, overwrite=False, output_dir=None,
                            file_name=None):
    """ Intensity-based skull stripping

    Estimate a brain mask for a dataset with good brain/background intensity 
    separation (e.g. PD-weighted). An extra image can be used to ensure high 
    intensities are preserved (e.g. T1 map, T2-weighted data or a probability 
    map for a ROI).
		
    Parameters
    ----------
    main_image: niimg
        Main Intensity Image
    extra_image: niimg, optional
        Extra image with high intensity at brain boundary
    noise_model: {'exponential','half-normal','exp+log-normal','half+log-normal'}
        Background noise model (default is 'exponential')
    skip_zero_values: bool
        Ignores voxels with zero value (default is True)
    iterate: bool
        Whether to iterate the estimation (may be unstable in some cases, 
        default is False)
    dilate_mask: int
         Additional dilation (or erosion, if negative) of the brain mask 
         (default is 0)
    topology_lut_dir: str, optional
        Path to directory in which topology files are stored (default is stored
        in TOPOLOGY_LUT_DIR)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * brain_mask (niimg): Binary brain mask (_istrip-mask)
        * brain_proba (niimg): Probability brain map (_istrip-proba)
        * main_masked (niimg): Masked main image (_istrip-main)
        * extra_masked (niimg): Masked extra map (_istrip-extra)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Details on the algorithm can 
    be found in [1]_ 
    
    References
    ----------
    .. [1] Bazin et al. (2014). A computational framework for ultra-high 
       resolution cortical segmentation at 7 Tesla.
       DOI: 10.1016/j.neuroimage.2013.03.077
    """

    print('\nIntensity-based Skull Stripping')

    # check topology lut dir and set default if not given
    topology_lut_dir = _check_topology_lut_dir(topology_lut_dir)

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, main_image)

        mask_file = os.path.join(output_dir, 
                        _fname_4saving(module=__name__,file_name=file_name,
                                   rootfile=main_image,
                                   suffix='istrip-mask'))
        proba_file = os.path.join(output_dir, 
                        _fname_4saving(module=__name__,file_name=file_name,
                                   rootfile=main_image,
                                   suffix='istrip-proba'))
        main_file = os.path.join(output_dir, 
                    _fname_4saving(module=__name__,file_name=file_name,
                                  rootfile=main_image,
                                  suffix='istrip-main'))

        if extra_image is not None:
            extra_file = os.path.join(output_dir, 
                        _fname_4saving(module=__name__,file_name=file_name,
                                        rootfile=extra_image,
                                        suffix='istrip-extra'))
        else:
            extra_file = None
        
        if overwrite is False \
            and os.path.isfile(mask_file) \
            and os.path.isfile(proba_file) \
            and os.path.isfile(main_file) :
            
            print("skip computation (use existing results)")
            output = {'brain_mask': mask_file, 
                    'brain_proba': proba_file, 
                    'main_masked': main_file}
            if extra_file is not None:
                if os.path.isfile(extra_file) :     
                    output['extra_masked'] = extra_file
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # create skulltripping instance
    algo = nighresjava.BrainIntensityBasedSkullStripping()

    # get dimensions and resolution from second inversion image
    main_img = load_volume(main_image)
    main_data = main_img.get_data()
    main_affine = main_img.affine
    main_hdr = main_img.header
    resolution = [x.item() for x in main_hdr.get_zooms()]
    dimensions = main_data.shape
    algo.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    algo.setResolutions(resolution[0], resolution[1], resolution[2])
    algo.setMainIntensityImage(nighresjava.JArray('float')(
                                    (main_data.flatten('F')).astype(float)))

    # pass other inputs
    if extra_image is not None:
        extra_img = load_volume(extra_image)
        extra_data = extra_img.get_data()
        extra_affine = extra_img.affine
        extra_hdr = extra_img.header
        algo.setExtraIntensityImage(nighresjava.JArray('float')(
                                    (extra_data.flatten('F')).astype(float)))

    algo.setBackgroundNoiseModel(noise_model)
    algo.setIterativeEstimation(iterate)
    algo.setSkipZeroValues(skip_zero_values)
    algo.setAdditionalMaskDilation(dilate_mask)
    algo.setTopologyLUTdirectory(topology_lut_dir)

    # execute skull stripping
    try:
        algo.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs and potentially save
    main_masked_data = np.reshape(np.array(
                                algo.getMaskedMainImage(),
                                dtype=np.float32), dimensions, 'F')
    main_hdr['cal_max'] = np.nanmax(main_masked_data)
    main_masked = nb.Nifti1Image(main_masked_data, main_affine, main_hdr)

    mask_data = np.reshape(np.array(algo.getBrainMaskImage(),
                                    dtype=np.uint32), dimensions, 'F')
    main_hdr['cal_max'] = np.nanmax(mask_data)
    mask = nb.Nifti1Image(mask_data, main_affine, main_hdr)

    proba_data = np.reshape(np.array(
                                algo.getForegroundProbabilityImage(),
                                dtype=np.float32), dimensions, 'F')
    main_hdr['cal_max'] = np.nanmax(proba_data)
    proba = nb.Nifti1Image(proba_data, main_affine, main_hdr)

    if extra_image is not None:
        extra_data = np.reshape(np.array(
                                algo.getMaskedExtraImage(),
                                dtype=np.float32), dimensions, 'F')
        extra_hdr['cal_max'] = np.nanmax(extra_data)
        extra_masked = nb.Nifti1Image(extra_data, extra_affine, extra_hdr)

    if save_data:
        save_volume(main_file, main_masked)
        save_volume(mask_file, mask)
        save_volume(proba_file, proba)
        outputs = {'brain_mask': mask_file, 'brain_proba': proba_file, 'main_masked': main_file}
        if extra_image is not None:
            save_volume(extra_file, extra_masked)
            outputs['extra_masked'] = extra_file
    else:
        outputs = {'brain_mask': mask, 'brain_proba': proba, 'main_masked': main_masked}
        if extra_image is not None:
            outputs['extra_masked'] = extra_masked
            
    return outputs
コード例 #15
0
def mp2rage_dura_estimation(second_inversion,
                            skullstrip_mask,
                            background_distance=5.0,
                            output_type='dura_region',
                            save_data=False,
                            overwrite=False,
                            output_dir=None,
                            file_name=None):
    """ MP2RAGE dura estimation

    Filters a MP2RAGE brain image to obtain a probability map of dura matter.

    Parameters
    ----------
    second_inversion: niimg
        Second inversion image derived from MP2RAGE sequence
    skullstrip_mask: niimg
        Skullstripping mask defining the approximate region including the brain
    background_distance: float
        Maximum distance within the mask for dura (default is 5.0 mm)
    output_type: {'dura_region','boundary','dura_prior','bg_prior',
        'intens_prior'}
        Type of output result (default is 'dura_region')
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)
    return_filename: bool, optional
        Return filename instead of object

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): Dura probability image (_dura-proba)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Details on the algorithm can
    be found in [1]_ and a presentation of the MP2RAGE sequence in [2]_

    References
    ----------
    .. [1] Bazin et al. (2014). A computational framework for ultra-high
       resolution cortical segmentation at 7 Tesla.
       DOI: 10.1016/j.neuroimage.2013.03.077
    .. [2] Marques et al. (2010). MP2RAGE, a self bias-field corrected sequence
       for improved segmentation and T1-mapping at high field.
       DOI: 10.1016/j.neuroimage.2009.10.002
    """

    print('\nMP2RAGE Dura Estimation')

    # Check data file parameters
    if not save_data and return_filename:
        raise ValueError('save_data must be True if return_filename is True ')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, second_inversion)

        result_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=second_inversion,
                           suffix='dura-proba'))

        if overwrite is False \
            and os.path.isfile(result_file) :

            print("skip computation (use existing results)")
            output = {'result': result_file}
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # create skulltripping instance
    algo = nighresjava.BrainMp2rageDuraEstimation()

    # get dimensions and resolution from second inversion image
    inv2_img = load_volume(second_inversion)
    inv2_data = inv2_img.get_data()
    inv2_affine = inv2_img.affine
    inv2_hdr = inv2_img.header
    resolution = [x.item() for x in inv2_hdr.get_zooms()]
    dimensions = inv2_data.shape
    algo.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    algo.setResolutions(resolution[0], resolution[1], resolution[2])
    algo.setSecondInversionImage(
        nighresjava.JArray('float')((inv2_data.flatten('F')).astype(float)))

    # pass other inputs
    mask_data = load_volume(skullstrip_mask).get_data()
    algo.setSkullStrippingMask(
        nighresjava.JArray('int')(
            (mask_data.flatten('F')).astype(int).tolist()))

    algo.setDistanceToBackground_mm(background_distance)
    algo.setOutputType(output_type)

    # execute skull stripping
    try:
        algo.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs and potentially save
    result_data = np.reshape(np.array(algo.getDuraImage(), dtype=np.float32),
                             dimensions, 'F')
    inv2_hdr['cal_max'] = np.nanmax(result_data)
    result_img = nb.Nifti1Image(result_data, inv2_affine, inv2_hdr)

    if save_data:
        save_volume(result_file, result_img)
        outputs = {'result': result_file}
    else:
        outputs = {'result': result_img}

    return outputs
コード例 #16
0
def surface_inflation(surface_mesh,
                      step_size=0.75,
                      max_iter=2000,
                      max_curv=10.0,
                      save_data=False,
                      overwrite=False,
                      output_dir=None,
                      file_name=None):
    """Surface inflation

    Inflate a surface with the method of Tosun et al _[1].

    Parameters
    ----------
    surface_mesh: mesh
        Mesh model of the surface
    step_size: float
        Relaxation rate in [0, 1]: values closer to 1 are more stable but slower 
        (default is 0.75)
    max_iter: int
        Maximum number of iterations (default is 2000)
    max_curv: float
        Desired maximum curvature (default is 10.0)        
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (mesh): Surface mesh dictionary of "points", "faces" and 
          "data" showing the SOM coordinates on the mesh 

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin
    
    """

    print("\nSurface inflation")

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, surface_mesh)

        infl_file = os.path.join(
            output_dir,
            _fname_4saving(file_name=file_name,
                           rootfile=surface_mesh,
                           suffix='infl-mesh',
                           ext='vtk'))

        if overwrite is False \
            and os.path.isfile(infl_file) :

            print("skip computation (use existing results)")
            output = {'result': load_mesh(infl_file)}
            return output

    # start virtual machine if not running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # initiate class
    algorithm = nighresjava.SurfaceInflation()

    # load the data
    orig_mesh = load_mesh(surface_mesh)

    algorithm.setSurfacePoints(
        nighresjava.JArray('float')(
            (orig_mesh['points'].flatten('C')).astype(float)))
    algorithm.setSurfaceTriangles(
        nighresjava.JArray('int')(
            (orig_mesh['faces'].flatten('C')).astype(int).tolist()))

    algorithm.setStepSize(step_size)
    algorithm.setMaxIter(max_iter)
    algorithm.setMaxCurv(max_curv)

    # execute class
    try:
        algorithm.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs
    print("collect outputs")

    npt = int(
        np.array(algorithm.getInflatedSurfacePoints(),
                 dtype=np.float32).shape[0] / 3)
    nfc = int(
        np.array(algorithm.getInflatedSurfaceTriangles(),
                 dtype=np.int32).shape[0] / 3)

    print("surface...")
    orig_points = np.reshape(
        np.array(algorithm.getInflatedSurfacePoints(), dtype=np.float32),
        (npt, 3), 'C')
    orig_faces = np.reshape(
        np.array(algorithm.getInflatedSurfaceTriangles(), dtype=np.int32),
        (nfc, 3), 'C')
    orig_data = np.reshape(
        np.array(algorithm.getInflatedSurfaceValues(), dtype=np.float32),
        (npt), 'F')

    # create the mesh dictionary
    inflated_orig_mesh = {
        "points": orig_points,
        "faces": orig_faces,
        "data": orig_data
    }

    if save_data:
        print("saving...")
        save_mesh(infl_file, inflated_orig_mesh)

    return {'result': inflated_orig_mesh}
コード例 #17
0
def parcellation_to_meshes(parcellation_image, connectivity="18/6", 
                     spacing = 0.0, smoothing=1.0,
                     save_data=False, overwrite=False,
                     output_dir=None, file_name=None):

    """Parcellation to meshes

    Creates a collection of triangulated meshes from a parcellation
    using a connectivity-consistent marching cube algorithm.

    Parameters
    ----------
    parcellation_image: niimg
        Parcellation image to be turned into meshes
    connectivity: {"6/18","6/26","18/6","26/6"}, optional
        Choice of digital connectivity to build the mesh (default is 18/6)
    spacing: float, optional
        Added spacing between meshes for better visualization (default is 0.0)
    smoothing: float, optional
        Smoothing of the boundary for prettier meshes, high values may bring 
        small distortions (default is 1.0)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool, optional
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result ([mesh]): A list of surface mesh dictionaries of "points" and "faces"
          (_p2m-mesh)

    Notes
    ----------
    Ported from original Java module by Pierre-Louis Bazin. Original algorithm
    from [1]_ and adapted from [2]_.

    References
    ----------
    .. [1] Han et al (2003). A Topology Preserving Level Set Method for
        Geometric Deformable Models
        doi:
    .. [2] Lucas et al (2010). The Java Image Science Toolkit (JIST) for
        Rapid Prototyping and Publishing of Neuroimaging Software
        doi:
    """

    print("\nParcellation to Meshes")

    # first we need to know how many meshes to build
    
    # load the data
    p_img = load_volume(parcellation_image)
    p_data = p_img.get_fdata()
    hdr = p_img.header
    aff = p_img.affine
    resolution = [x.item() for x in hdr.get_zooms()]
    dimensions = p_data.shape

    # count the labels (incl. background)
    labels = numpy.unique(p_data)
    print("found labels: "+str(labels))

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, parcellation_image)

        mesh_files = [] 
        for num,label in enumerate(labels):
            # exclude background as first label
            if num>0:
                mesh_file = os.path.join(output_dir,
                        _fname_4saving(module=__name__,file_name=file_name,
                                       rootfile=parcellation_image,
                                       suffix='p2m-mesh'+str(num),ext="vtk"))
                mesh_files.append(mesh_file)

        if overwrite is False :
            missing = False
            for num,label in enumerate(labels):
                if num>0:
                    if not os.path.isfile(mesh_files[num-1]) :
                        missing = True

            if not missing:
                print("skip computation (use existing results)")
                output = {'result': mesh_files}
                return output

    # start virtual machine if not running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # build a simplified levelset for each structure
    meshes = []
    for num,label in enumerate(labels):
        
        if num>0:
            lvl_data = -1.0*(p_data==label) +1.0*(p_data!=label)
            
            # initiate class inside the loop, to avoid garbage collection issues with many labels (??)
            algorithm = nighresjava.SurfaceLevelsetToMesh()
        
            algorithm.setResolutions(resolution[0], resolution[1], resolution[2])
            algorithm.setDimensions(dimensions[0], dimensions[1], dimensions[2])

            algorithm.setLevelsetImage(nighresjava.JArray('float')(
                                    (lvl_data.flatten('F')).astype(float)))
    
            algorithm.setConnectivity(connectivity)
            algorithm.setZeroLevel(0.0)
            algorithm.setInclusive(True)
            algorithm.setSmoothing(smoothing)

            # execute class
            try:
                algorithm.execute()
    
            except:
                # if the Java module fails, reraise the error it throws
                print("\n The underlying Java code did not execute cleanly: ")
                print(sys.exc_info()[0])
                raise
                return
    
            # collect outputs
            npt = int(numpy.array(algorithm.getPointList(), dtype=numpy.float32).shape[0]/3)
            mesh_points = numpy.reshape(numpy.array(algorithm.getPointList(),
                                   dtype=numpy.float32), (npt,3), 'C')
    
            nfc = int(numpy.array(algorithm.getTriangleList(), dtype=numpy.int32).shape[0]/3)
            mesh_faces = numpy.reshape(numpy.array(algorithm.getTriangleList(),
                                   dtype=numpy.int32), (nfc,3), 'C')
    
            mesh_label = label*numpy.ones((npt,1))
    
            # create the mesh dictionary
            mesh = {"points": mesh_points, "faces": mesh_faces, "data": mesh_label}
    
            meshes.append(mesh)
        
    # if needed, spread values away from center
    if spacing>0:
        center = numpy.zeros((1,3))
        for num,label in enumerate(labels):
            if num>0:
                center = center + numpy.mean(meshes[num-1]['points'], axis=0)
        center = center/(len(labels)-1)
        
        for num,label in enumerate(labels):
            if num>0:
                mesh0 = numpy.mean(meshes[num-1]['points'], axis=0)
                meshes[num-1]['points'] = meshes[num-1]['points']-mesh0 + spacing*(mesh0-center) + center
        
    if save_data:
        for num,label in enumerate(labels):
            if num>0:
                save_mesh(mesh_files[num-1], meshes[num-1])
        return {'result': mesh_files}
    else:
        return {'result': meshes}
コード例 #18
0
ファイル: levelset_to_mesh.py プロジェクト: thm200103/nighres
def levelset_to_mesh(levelset_image,
                     connectivity="18/6",
                     level=0.0,
                     inclusive=True,
                     save_data=False,
                     overwrite=False,
                     output_dir=None,
                     file_name=None):
    """Levelset to mesh

    Creates a triangulated mesh from the distance to a levelset surface
    representation using a connectivity-consistent marching cube algorithm.

    Parameters
    ----------
    levelset_image: niimg
        Levelset image to be turned into a mesh
    connectivity: {"6/18","6/26","18/6","26/6"}, optional
        Choice of digital connectivity to build the mesh (default is 18/6)
    level: float, optional
        Value of the levelset function to use as isosurface (default is 0)
    inclusive: bool, optional
        Whether voxels at the exact 'level' value are inside the isosurface
        (default is True)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool, optional
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (mesh): Surface mesh dictionary of "points" and "faces"
          (_l2m-mesh)

    Notes
    ----------
    Ported from original Java module by Pierre-Louis Bazin. Original algorithm
    from [1]_ and adapted from [2]_.

    References
    ----------
    .. [1] Han et al (2003). A Topology Preserving Level Set Method for
        Geometric Deformable Models
        doi:
    .. [2] Lucas et al (2010). The Java Image Science Toolkit (JIST) for
        Rapid Prototyping and Publishing of Neuroimaging Software
        doi:
    """

    print("\nLevelset to Mesh")

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, levelset_image)

        mesh_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=levelset_image,
                           suffix='l2m-mesh',
                           ext="vtk"))

        if overwrite is False \
            and os.path.isfile(mesh_file) :

            print("skip computation (use existing results)")
            output = {'result': mesh_file}
            return output

    # start virtual machine if not running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # initiate class
    algorithm = nighresjava.SurfaceLevelsetToMesh()

    # load the data
    lvl_img = load_volume(levelset_image)
    lvl_data = lvl_img.get_data()
    hdr = lvl_img.header
    aff = lvl_img.affine
    resolution = [x.item() for x in hdr.get_zooms()]
    dimensions = lvl_data.shape

    algorithm.setResolutions(resolution[0], resolution[1], resolution[2])
    algorithm.setDimensions(dimensions[0], dimensions[1], dimensions[2])

    algorithm.setLevelsetImage(
        nighresjava.JArray('float')((lvl_data.flatten('F')).astype(float)))

    algorithm.setConnectivity(connectivity)
    algorithm.setZeroLevel(level)
    algorithm.setInclusive(inclusive)

    # execute class
    try:
        algorithm.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs
    npt = int(
        np.array(algorithm.getPointList(), dtype=np.float32).shape[0] / 3)
    mesh_points = np.reshape(
        np.array(algorithm.getPointList(), dtype=np.float32), (npt, 3), 'C')

    nfc = int(
        np.array(algorithm.getTriangleList(), dtype=np.int32).shape[0] / 3)
    mesh_faces = np.reshape(
        np.array(algorithm.getTriangleList(), dtype=np.int32), (nfc, 3), 'C')

    # create the mesh dictionary
    mesh = {"points": mesh_points, "faces": mesh_faces}

    if save_data:
        save_mesh_geometry(mesh_file, mesh)
        return {'result': mesh_file}
    else:
        return {'result': mesh}
コード例 #19
0
def lcpca_denoising(image_list,
                    phase_list=None,
                    ngb_size=4,
                    stdev_cutoff=1.05,
                    min_dimension=0,
                    max_dimension=-1,
                    unwrap=True,
                    rescale_phs=True,
                    process_2d=False,
                    use_rmt=False,
                    save_data=False,
                    overwrite=False,
                    output_dir=None,
                    file_names=None):
    """ LCPCA denoising

    Denoise multi-contrast data with a local complex-valued PCA-based method

    Parameters
    ----------
    image_list: [niimg]
        List of input images to denoise
    phase_list: [niimg], optional
        List of input phase to denoise (order must match that of image_list)
    ngb_size: int, optional
        Size of the local PCA neighborhood, to be increased with number of
        inputs (default is 4)
    stdev_cutoff: float, optional
        Factor of local noise level to remove PCA components. Higher
        values remove more components (default is 1.05)
    min_dimension: int, optional
        Minimum number of kept PCA components
        (default is 0)
    max_dimension: int, optional
        Maximum number of kept PCA components
        (default is -1 for all components)
    unwrap: bool, optional
        Whether to unwrap the phase data of keep it as is
        (default is True)
    rescale_phs: bool, optional
        Whether to rescale the phase data of keep it as is, assuming radians
        (default is True)
    process_2d: bool, optional
        Whether to denoise in 2D, for instance when acquiring a thin slab of 
        data (default is False)
    use_rmt: bool, optional
        Whether to use random matrix theory rather than noise fitting to
        estimate the noise threshold (default is False)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_names: [str], optional
        Desired base names for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * denoised ([niimg]): The list of denoised input images (_lcpca_den)
        * dimensions (niimg): Map of the estimated local dimensions (_lcpca_dim)
        * residuals (niimg): Estimated residuals between input and denoised images (_lcpca_err)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Algorithm adapted from [1]_
    with a different approach to set the adaptive noise threshold and additional
    processing to handle the phase data.

    References
    ----------
    .. [1] Manjon, Coupe, Concha, Buades, Collins, Robles (2013). Diffusion
        Weighted Image Denoising Using Overcomplete Local PCA
        doi:10.1371/journal.pone.0073021
    """

    print('\nLCPCA denoising')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image_list[0])

        den_files = []
        for idx, image in enumerate(image_list):
            if file_names is None: name = None
            else: name = file_names[idx]
            den_file = os.path.join(
                output_dir,
                _fname_4saving(module=__name__,
                               file_name=name,
                               rootfile=image,
                               suffix='lcpca-den'))
            den_files.append(den_file)

        if (phase_list != None):
            for idx, image in enumerate(phase_list):
                if file_names is None: name = None
                else: name = file_names[len(image_list) + idx]
                den_file = os.path.join(
                    output_dir,
                    _fname_4saving(module=__name__,
                                   file_name=name,
                                   rootfile=image,
                                   suffix='lcpca-den'))
                den_files.append(den_file)

        if file_names is None: name = None
        else: name = file_names[0]
        dim_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=name,
                           rootfile=image_list[0],
                           suffix='lcpca-dim'))

        err_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=name,
                           rootfile=image_list[0],
                           suffix='lcpca-res'))

        if overwrite is False \
            and os.path.isfile(dim_file) \
            and os.path.isfile(err_file) :
            # check that the denoised data is the same too
            missing = False
            for den_file in den_files:
                if not os.path.isfile(den_file):
                    missing = True
            if not missing:
                print("skip computation (use existing results)")
                denoised = []
                for den_file in den_files:
                    denoised.append(den_file)
                output = {
                    'denoised': denoised,
                    'dimensions': dim_file,
                    'residuals': err_file
                }

                return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create lcpca instance
    lcpca = nighresjava.LocalComplexPCADenoising()

    # load first image and use it to set dimensions and resolution
    img = load_volume(image_list[0])
    data = img.get_fdata()
    #data = data[0:10,0:10,0:10]
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape
    dim3D = (dimensions[0], dimensions[1], dimensions[2])

    # set lcpca parameters
    lcpca.setImageNumber(len(image_list))
    eigdim = len(image_list)
    if (phase_list != None):
        if len(dimensions) > 3:
            eigdim = 2 * eigdim * dimensions[3]
        else:
            eigdim = 2 * eigdim
        if (len(phase_list) != len(image_list)):
            print('\nmismatch of magnitude and phase images: abort')
            return

    if len(dimensions) > 3:
        lcpca.setDimensions(dimensions[0], dimensions[1], dimensions[2],
                            dimensions[3])
    else:
        lcpca.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    lcpca.setResolutions(resolution[0], resolution[1], resolution[2])

    # input images
    # important: set image number before adding images
    for idx, image in enumerate(image_list):
        #print('\nloading ('+str(idx)+'): '+image)
        data = load_volume(image).get_fdata()
        #data = data[0:10,0:10,0:10]
        lcpca.setMagnitudeImageAt(
            idx,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # input phase, if specified
    if (phase_list != None):
        for idx, image in enumerate(phase_list):
            #print('\nloading '+image)
            data = load_volume(image).get_fdata()
            #data = data[0:10,0:10,0:10]
            lcpca.setPhaseImageAt(
                idx,
                nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # set algorithm parameters
    lcpca.setPatchSize(ngb_size)
    lcpca.setStdevCutoff(stdev_cutoff)
    lcpca.setMinimumDimension(min_dimension)
    lcpca.setMaximumDimension(max_dimension)
    lcpca.setUnwrapPhase(unwrap)
    lcpca.setRescalePhase(rescale_phs)
    lcpca.setProcessSlabIn2D(process_2d)
    lcpca.setRandomMatrixTheory(use_rmt)

    # execute the algorithm
    try:
        lcpca.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    denoised_list = []
    for idx, image in enumerate(image_list):
        den_data = np.reshape(
            np.array(lcpca.getDenoisedMagnitudeImageAt(idx), dtype=np.float32),
            dimensions, 'F')
        header['cal_min'] = np.nanmin(den_data)
        header['cal_max'] = np.nanmax(den_data)
        denoised = nb.Nifti1Image(den_data, affine, header)
        denoised_list.append(denoised)

        if save_data:
            save_volume(den_files[idx], denoised)

    if (phase_list != None):
        for idx, image in enumerate(phase_list):
            den_data = np.reshape(
                np.array(lcpca.getDenoisedPhaseImageAt(idx), dtype=np.float32),
                dimensions, 'F')
            header['cal_min'] = np.nanmin(den_data)
            header['cal_max'] = np.nanmax(den_data)
            denoised = nb.Nifti1Image(den_data, affine, header)
            denoised_list.append(denoised)

            if save_data:
                save_volume(den_files[idx + len(image_list)], denoised)

    dim_data = np.reshape(
        np.array(lcpca.getLocalDimensionImage(), dtype=np.float32), dim3D, 'F')

    err_data = np.reshape(np.array(lcpca.getNoiseFitImage(), dtype=np.float32),
                          dim3D, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(dim_data)
    header['cal_max'] = np.nanmax(dim_data)
    dim = nb.Nifti1Image(dim_data, affine, header)

    header['cal_min'] = np.nanmin(err_data)
    header['cal_max'] = np.nanmax(err_data)
    err = nb.Nifti1Image(err_data, affine, header)

    if save_data:
        save_volume(dim_file, dim)
        save_volume(err_file, err)
        output = {
            'denoised': den_files,
            'dimensions': dim_file,
            'residuals': err_file
        }
    else:
        output = {
            'denoised': denoised_list,
            'dimensions': dim,
            'residuals': err
        }

    return output
コード例 #20
0
def levelset_fusion(levelset_images,
                    correct_topology=True,
                    topology_lut_dir=None,
                    max_distance=10.0,
                    smooth_curvature=0.1,
                    follow_stdev=False,
                    sharpen=0.0,
                    save_data=False,
                    overwrite=False,
                    output_dir=None,
                    file_name=None):
    """Levelset fusion

    Creates an average levelset surface representations from a collection of
    levelset surfaces, with same avearage volume and (optionally) spherical
    topology

    Parameters
    ----------
    levelset_images: niimg
        List of levelset images to combine.
    correct_topology: bool, optional
        Corrects the average shape to ensure correct topology (default is True)
    topology_lut_dir: str, optional
        Path to directory in which topology files are stored (default is stored
        in TOPOLOGY_LUT_DIR)
    max_distance: float, optional
        Maximum distance for levelset combination (default is 10.0 voxels)
    smooth_curvature: float, optional
        Curvature smoothing of the final average in [0,1] (default is 0)
    follow_stdev: bool, optional
        Grows preferrentially in regions of higher variance (default is False)
    sharpen: float, optional
        Sharpening of average by weighted average with a Laplacian filtered version [0,1] (default is 0)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool, optional
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): Levelset representation of combined surface (_lsf-avg)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin
    """

    print("\nLevelset Shape Fusion")

    # check topology_lut_dir and set default if not given
    topology_lut_dir = _check_topology_lut_dir(topology_lut_dir)

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, levelset_images[0])

        levelset_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=levelset_images[0],
                           suffix='lsf-avg'))
        print('output file: ' + levelset_file)
        if overwrite is False \
            and os.path.isfile(levelset_file) :

            print("skip computation (use existing results)")
            output = {'result': levelset_file}
            return output

    # start virtual machine if not running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # initiate class
    algorithm = nighresjava.LevelsetShapeFusion()
    #algorithm = nighresjava.ShapeLevelsetFusion()

    # load the data
    nsubjects = len(levelset_images)

    img = load_volume(levelset_images[0])
    hdr = img.header
    aff = img.affine
    resolution = [x.item() for x in hdr.get_zooms()]
    dimensions = img.get_fdata().shape

    algorithm.setNumberOfImages(nsubjects)
    algorithm.setResolutions(resolution[0], resolution[1], resolution[2])
    algorithm.setDimensions(dimensions[0], dimensions[1], dimensions[2])

    levelset_data = []
    for idx in range(len(levelset_images)):
        img = load_volume(levelset_images[idx])
        data = img.get_fdata()
        algorithm.setLevelsetImageAt(
            idx,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    algorithm.setCorrectSkeletonTopology(correct_topology)
    algorithm.setTopologyLUTdirectory(topology_lut_dir)

    algorithm.setLevelsetDistance(max_distance)

    algorithm.setCurvatureSmoothing(smooth_curvature)

    algorithm.setSlopeSharpening(sharpen)

    algorithm.setIncludeVariance(follow_stdev)

    # execute class
    try:
        algorithm.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs
    levelset_data = np.reshape(
        np.array(algorithm.getLevelsetAverage(), dtype=np.float32), dimensions,
        'F')

    hdr['cal_min'] = np.nanmin(levelset_data)
    hdr['cal_max'] = np.nanmax(levelset_data)
    levelset = nb.Nifti1Image(levelset_data, aff, hdr)

    if save_data:
        save_volume(levelset_file, levelset)
        return {'result': levelset_file}
    else:
        return {'result': levelset}
コード例 #21
0
def recursive_ridge_diffusion(input_image,
                              ridge_intensities,
                              ridge_filter,
                              surface_levelset=None,
                              orientation='undefined',
                              loc_prior=None,
                              min_scale=0,
                              max_scale=3,
                              diffusion_factor=1.0,
                              similarity_scale=0.1,
                              max_iter=100,
                              max_diff=1e-3,
                              save_data=False,
                              overwrite=False,
                              output_dir=None,
                              file_name=None):
    """ Recursive Ridge Diffusion

    Extracts planar of tubular structures across multiple scales, with an
    optional directional bias.


    Parameters
    ----------
    input_image: niimg
        Input image
    ridge_intensities: {'bright','dark','both'}
        Which intensities to consider for the filtering
    ridge_filter: {'2D','1D','0D'}
        Whether to filter for 2D ridges, 1D vessels, or 0D holes
    surface_levelset: niimg, optional
        Level set surface to restrict the orientation of the detected features
    orientation: {'undefined','parallel','orthogonal'}
        The orientation of features to keep with regard to the surface or its normal
    loc_prior: niimg, optional
        Location prior image to restrict the search for features
    min_scale: int
        Minimum scale (in voxels) to look for features (default is 0)
    max_scale: int
        Maximum scale (in voxels) to look for features (default is 3)
    diffusion_factor: float
        Scaling factor for the diffusion weighting in [0,1] (default is 1.0)
    similarity_scale: float
        Scaling of the similarity function as a factor of intensity range
    max_iter: int
        Maximum number of diffusion iterations
    max_diff: int
        Maximum difference to stop the diffusion
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * filter (niimg): raw filter response (_rrd-filter)
        * propagation (niimg): propagated probabilistic response after diffusion (_rrd-propag)
        * scale (niimg): scale of the detection filter  (_rrd-scale)
        * ridge_dir (niimg): estimated local ridge direction (_rrd-dir)
        * ridge_pv (niimg): ridge partial volume map, taking size into account (_rrd-pv)
        * ridge_size (niimg): estimated size of each detected component (rrd-size)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Extension of the recursive ridge
    filter in [1]_.

    References
    ----------
    .. [1] Bazin et al (2016), Vessel segmentation from quantitative
           susceptibility maps for local oxygenation venography, Proc ISBI.

    """

    print('\n Recursive Ridge Diffusion')

    # check atlas_file and set default if not given
    #atlas_file = _check_atlas_file(atlas_file)

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, input_image)

        filter_file = _fname_4saving(file_name=file_name,
                                     rootfile=input_image,
                                     suffix='rrd-filter')

        propagation_file = _fname_4saving(file_name=file_name,
                                          rootfile=input_image,
                                          suffix='rrd-propag')

        scale_file = _fname_4saving(file_name=file_name,
                                    rootfile=input_image,
                                    suffix='rrd-scale')

        ridge_direction_file = _fname_4saving(file_name=file_name,
                                              rootfile=input_image,
                                              suffix='rrd-dir')

        ridge_pv_file = _fname_4saving(file_name=file_name,
                                       rootfile=input_image,
                                       suffix='rrd-pv')

        ridge_size_file = _fname_4saving(file_name=file_name,
                                         rootfile=input_image,
                                         suffix='rrd-size')

        if overwrite is False \
            and os.path.isfile(filter_file) \
            and os.path.isfile(propagation_file) \
            and os.path.isfile(scale_file) \
            and os.path.isfile(ridge_direction_file) \
            and os.path.isfile(ridge_pv_file) \
            and os.path.isfile(ridge_size_file) :

            print("skip computation (use existing results)")
            output = {
                'filter': load_volume(filter_file),
                'propagation': load_volume(propagation_file),
                'scale': load_volume(scale_file),
                'ridge_dir': load_volume(ridge_direction_file),
                'ridge_pv': load_volume(ridge_pv_file),
                'ridge_size': load_volume(ridge_size_file)
            }
            return output

    # load input image and use it to set dimensions and resolution
    img = load_volume(input_image)
    data = img.get_data()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape
    if (len(dimensions) < 3): dimensions = (dimensions[0], dimensions[1], 1)
    if (len(resolution) < 3): resolution = [resolution[0], resolution[1], 1.0]

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create extraction instance
    if dimensions[2] is 1: rrd = nighresjava.FilterRecursiveRidgeDiffusion2D()
    else: rrd = nighresjava.FilterRecursiveRidgeDiffusion()

    # set parameters
    rrd.setRidgeIntensities(ridge_intensities)
    rrd.setRidgeFilter(ridge_filter)
    rrd.setOrientationToSurface(orientation)
    rrd.setMinimumScale(min_scale)
    rrd.setMaximumScale(max_scale)
    rrd.setDiffusionFactor(diffusion_factor)
    rrd.setSimilarityScale(similarity_scale)
    rrd.setPropagationModel("none")
    if max_iter > 0: rrd.setPropagationModel("diffusion")
    rrd.setMaxIterations(max_iter)
    rrd.setMaxDifference(max_diff)

    rrd.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    rrd.setResolutions(resolution[0], resolution[1], resolution[2])

    # input input_image
    rrd.setInputImage(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # input surface_levelset : dirty fix for the case where surface image not input
    try:
        data = load_volume(surface_levelset).get_data()
        rrd.setSurfaceLevelSet(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))
    except:
        print("no surface image")

    # input location prior image : loc_prior is optional
    try:
        data = load_volume(loc_prior).get_data()
        rrd.setLocationPrior(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))
    except:
        print("no location prior image")

    # execute Extraction
    try:
        rrd.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    filter_data = np.reshape(
        np.array(rrd.getFilterResponseImage(), dtype=np.float32), dimensions,
        'F')

    propagation_data = np.reshape(
        np.array(rrd.getPropagatedResponseImage(), dtype=np.float32),
        dimensions, 'F')

    scale_data = np.reshape(
        np.array(rrd.getDetectionScaleImage(), dtype=np.int32), dimensions,
        'F')

    ridge_direction_data = np.reshape(
        np.array(rrd.getRidgeDirectionImage(), dtype=np.float32),
        (dimensions[0], dimensions[1], dimensions[2], 3), 'F')

    ridge_pv_data = np.reshape(
        np.array(rrd.getRidgePartialVolumeImage(), dtype=np.float32),
        dimensions, 'F')

    ridge_size_data = np.reshape(
        np.array(rrd.getRidgeSizeImage(), dtype=np.float32), dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_max'] = np.nanmax(filter_data)
    filter_img = nb.Nifti1Image(filter_data, affine, header)

    header['cal_max'] = np.nanmax(propagation_data)
    propag_img = nb.Nifti1Image(propagation_data, affine, header)

    header['cal_max'] = np.nanmax(scale_data)
    scale_img = nb.Nifti1Image(scale_data, affine, header)

    header['cal_max'] = np.nanmax(ridge_direction_data)
    ridge_dir_img = nb.Nifti1Image(ridge_direction_data, affine, header)

    header['cal_max'] = np.nanmax(ridge_pv_data)
    ridge_pv_img = nb.Nifti1Image(ridge_pv_data, affine, header)

    header['cal_max'] = np.nanmax(ridge_size_data)
    ridge_size_img = nb.Nifti1Image(ridge_size_data, affine, header)

    if save_data:
        save_volume(os.path.join(output_dir, filter_file), filter_img)
        save_volume(os.path.join(output_dir, propagation_file), propag_img)
        save_volume(os.path.join(output_dir, scale_file), scale_img)
        save_volume(os.path.join(output_dir, ridge_direction_file),
                    ridge_dir_img)
        save_volume(os.path.join(output_dir, ridge_pv_file), ridge_pv_img)
        save_volume(os.path.join(output_dir, ridge_size_file), ridge_size_img)

    return {
        'filter': filter_img,
        'propagation': propag_img,
        'scale': scale_img,
        'ridge_dir': ridge_dir_img,
        'ridge_pv': ridge_pv_img,
        'ridge_size': ridge_size_img
    }
コード例 #22
0
def linear_fiber_interpolation(image,
                               references,
                               mapped_proba,
                               mapped_theta,
                               mapped_lambda,
                               mapped_dim=1,
                               weights=None,
                               patch=2,
                               search=3,
                               median=True,
                               save_data=False,
                               overwrite=False,
                               output_dir=None,
                               file_name=None):
    """ Linear fiber interpolation

    Uses a simple non-local means approach adapted from [1]_
    to interpolate extracted line information across slices

    Parameters
    ----------
    image: niimg
        Input 2D image
    references: [niimg]
        Reference 2D images to use for intensity mapping
    mapped_proba: [niimg]
        Corresponding mapped 3D images to use for line probabilites
    mapped_theta: [niimg]
        Corresponding mapped 3D images to use for line directions
    mapped_lambda: [niimg]
        Corresponding mapped 3D images to use for line lengths
    mapped_dim: int
        Thrid dimension of the mapped 3D images (default is 1)
    weights: [float], optional
        Weight factors for the 2D images (default is 1 for all)
    patch: int, optional 
        Maximum distance to define patch size (default is 2)
    search: int, optional 
        Maximum distance to define search window size (default is 3)
    median: bool
        Whether to use median instead of mean of the patches (default is True)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * proba (niimg): The probability mapped input
        * theta (niimg): The direction mapped input
        * lambda (niimg): The length mapped input

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.


    References
    ----------
    .. [1] P. Coupé, J.V. Manjón, V. Fonov, J. Pruessner, M. Robles, D.L. Collins,
       Patch-based segmentation using expert priors: Application to hippocampus 
       and ventricle msegmentation, NeuroImage, vol. 54, pp. 940--954, 2011.
    """

    print('\nLinear fiber interpolation')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image)

        proba_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image,
                           suffix='lfi-proba'))

        theta_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image,
                           suffix='lfi-theta'))

        lambda_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image,
                           suffix='lfi-lambda'))

        if overwrite is False \
            and os.path.isfile(proba_file) \
            and os.path.isfile(theta_file) \
            and os.path.isfile(lambda_file) :
            print("skip computation (use existing results)")
            output = {
                'proba': proba_file,
                'theta': theta_file,
                'lambda': lambda_file
            }
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    lfi = nighresjava.NonlocalLinearFiberInterpolation()

    # set parameters

    # load image and use it to set dimensions and resolution
    img = load_volume(image)
    data = img.get_fdata()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    lfi.setDimensions(dimensions[0], dimensions[1], 1)
    lfi.setLineNumber(mapped_dim)

    lfi.setInputImage(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    lfi.setReferenceNumber(len(references))

    for idx, ref in enumerate(references):
        data = load_volume(ref).get_fdata()
        lfi.setReferenceImageAt(
            idx,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

        data = load_volume(mapped_proba[idx]).get_fdata()
        lfi.setMappedProbaAt(
            idx,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

        data = load_volume(mapped_theta[idx]).get_fdata()
        lfi.setMappedThetaAt(
            idx,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

        data = load_volume(mapped_lambda[idx]).get_fdata()
        lfi.setMappedLambdaAt(
            idx,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

        if weights is not None:
            lfi.setWeightAt(idx, weights[idx])
        else:
            lfi.setWeightAt(idx, 1.0)

    # set algorithm parameters
    lfi.setPatchDistance(patch)
    lfi.setSearchDistance(search)
    lfi.setUseMedian(median)

    # execute the algorithm
    try:
        lfi.execute2D()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    dimensions = (dimensions[0], dimensions[1], mapped_dim)
    data = np.reshape(np.array(lfi.getMappedProba(), dtype=np.float32),
                      dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(data)
    header['cal_max'] = np.nanmax(data)
    result_proba = nb.Nifti1Image(data, affine, header)

    # reshape output to what nibabel likes
    dimensions = (dimensions[0], dimensions[1], mapped_dim)
    data = np.reshape(np.array(lfi.getMappedTheta(), dtype=np.float32),
                      dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(data)
    header['cal_max'] = np.nanmax(data)
    result_theta = nb.Nifti1Image(data, affine, header)

    # reshape output to what nibabel likes
    dimensions = (dimensions[0], dimensions[1], mapped_dim)
    data = np.reshape(np.array(lfi.getMappedLambda(), dtype=np.float32),
                      dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(data)
    header['cal_max'] = np.nanmax(data)
    result_lambda = nb.Nifti1Image(data, affine, header)

    if save_data:
        save_volume(proba_file, result_proba)
        save_volume(theta_file, result_theta)
        save_volume(lambda_file, result_lambda)
        return {
            'proba': proba_file,
            'theta': theta_file,
            'lambda': lambda_file
        }
    else:
        return {
            'proba': result_proba,
            'theta': result_theta,
            'lambda': result_lambda
        }
コード例 #23
0
def segmentation_statistics(segmentation,
                            intensity=None,
                            template=None,
                            statistics=None,
                            output_csv=None,
                            atlas=None,
                            skip_first=True,
                            ignore_zero=True,
                            save_data=False,
                            overwrite=False,
                            output_dir=None,
                            file_name=None):
    """ Segmentation Statistics

    Compute various statistics of image segmentations

    Parameters
    ----------
    segmentation: niimg
        Input segmentation image
    intensity: niimg, optional
        Input intensity image for intensity-based statistics
    template: niimg, optional
        Input template segmentation for comparisons
    statistics: [str]
        Statistics to compute. Available options include:
        "Voxels", "Volume", "Center_of_mass", "Mean_intensity",
        "Std_intensity", "Sum_intensity", "10_intensity","25_intensity",
        "50_intensity", "75_intensity","90_intensity", "Median_intensity",
        "IQR_intensity", "SNR_intensity","rSNR_intensity", "Volumes", 
        "Dice_overlap", "Jaccard_overlap", "Volume_difference", "False_positives"
        "False_negatives", "Dilated_Dice_overlap","Dilated_false_positive",
        "Dilated_false_negative", "Dilated_false_negative_volume",
        "Dilated_false_positive_volume", "Center_distance", "Detected_clusters",
        "False_detections", "Cluster_numbers", "Mean_cluster_sizes",
        "Cluster_maps", "Average_surface_distance",
        "Average_surface_difference", "Average_squared_surface_distance",
        "Hausdorff_distance"
    output_csv: str
        File name of the statistics file to generate or expand
    atlas: str, optional
        File name of an atlas file defining the segmentation labels
    skip_first: bool, optional
        Whether to skip the first segmentation label (usually representing the
        background, default is True)
    ignore_zero: bool, optional
        Whether to ignore zero intensity values in the intensity image
        (default is True)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool, optional
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * csv (str): The csv statistics file
        * map (niimg): Map of the estimated statistic, if relevant (stat-map)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    """

    print('\nSegmentation statistics')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, segmentation)

        map_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=segmentation,
                           suffix='stat-map'))

        csv_file = os.path.join(output_dir, output_csv)

        if overwrite is False \
            and os.path.isfile(csv_file) :
            # check that the denoised data is the same too
            print("append results to existing csv file")

        if overwrite is True:
            # delete current stats file to start from the beginning
            os.remove(csv_file)
    else:
        csv_file = output_csv

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    stats = nighresjava.StatisticsSegmentation()

    # load first image and use it to set dimensions and resolution
    img = load_volume(segmentation)
    data = img.get_fdata()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    if len(dimensions) > 2:
        stats.setDimensions(dimensions[0], dimensions[1], dimensions[2])
        stats.setResolutions(resolution[0], resolution[1], resolution[2])
    else:
        stats.setDimensions(dimensions[0], dimensions[1], 1)
        stats.setResolutions(resolution[0], resolution[1], 1.0)

    stats.setSegmentationImage(
        nighresjava.JArray('int')((data.flatten('F')).astype(int).tolist()))
    stats.setSegmentationName(
        _fname_4saving(module=__name__, rootfile=segmentation))

    # other input images, if any
    if intensity is not None:
        data = load_volume(intensity).get_fdata()
        stats.setIntensityImage(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))
        stats.setIntensityName(
            _fname_4saving(module=__name__, rootfile=intensity))

    if template is not None:
        data = load_volume(template).get_fdata()
        stats.setTemplateImage(
            nighresjava.JArray('int')(
                (data.flatten('F')).astype(int).tolist()))
        stats.setTemplateName(
            _fname_4saving(module=__name__, rootfile=template))

    # set algorithm parameters
    if atlas is not None:
        stats.setAtlasFile(atlas)

    stats.setSkipFirstLabel(skip_first)
    stats.setIgnoreZeroIntensities(ignore_zero)

    stats.setStatisticNumber(len(statistics))
    for idx, stat in enumerate(statistics):
        stats.setStatisticAt(idx, stat)

    stats.setSpreadsheetFile(csv_file)

    # execute the algorithm
    try:
        stats.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    output = False
    for st in statistics:
        if st == "Cluster_maps":
            output = True

    if (output):
        data = np.reshape(np.array(stats.getOutputImage(), dtype=np.int32),
                          dimensions, 'F')
        header['cal_min'] = np.nanmin(data)
        header['cal_max'] = np.nanmax(data)
        output = nb.Nifti1Image(data, affine, header)

        if save_data:
            save_volume(map_file, output)

    csv_file = stats.getOutputFile()

    if output:
        if save_data:
            return {'csv': csv_file, 'map': map_file}
        else:
            return {'csv': csv_file, 'map': output}
    else:
        return {'csv': csv_file}
コード例 #24
0
def stack_intensity_regularisation(image,
                                   cutoff=50,
                                   mask=None,
                                   save_data=False,
                                   overwrite=False,
                                   output_dir=None,
                                   file_name=None):
    """ Stack intensity regularisation

    Estimates an image-to-image linear intensity scaling for a stack of 2D images

    Parameters
    ----------
    image: niimg
        Input 2D images, stacked in the Z dimension
    cutoff: float, optional 
        Range of image differences to keep (default is middle 50%)
    mask: niimg
        Input mask or probability image of the data to use (optional)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): The intensity regularised input

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.

    """

    print('\nStack Intensity Regularisation')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image)

        regularised_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image,
                           suffix='sir-img'))

        if overwrite is False \
            and os.path.isfile(regularised_file) :
            print("skip computation (use existing results)")
            output = {'result': regularised_file}
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    sir = nighresjava.StackIntensityRegularisation()

    # set parameters

    # load image and use it to set dimensions and resolution
    img = load_volume(image)
    data = img.get_fdata()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    sir.setDimensions(dimensions[0], dimensions[1], dimensions[2])

    sir.setInputImage(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    if mask is not None:
        sir.setForegroundImage(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # set algorithm parameters
    sir.setVariationRatio(float(cutoff))

    # execute the algorithm
    try:
        sir.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    regularised_data = np.reshape(
        np.array(sir.getRegularisedImage(), dtype=np.float32), dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(regularised_data)
    header['cal_max'] = np.nanmax(regularised_data)
    regularised = nb.Nifti1Image(regularised_data, affine, header)

    if save_data:
        save_volume(regularised_file, regularised)
        return {'result': regularised_file}
    else:
        return {'result': regularised}
コード例 #25
0
def mp2rageme_pd_mapping(first_inversion,
                         second_inversion,
                         t1map,
                         r2smap,
                         echo_times,
                         inversion_times,
                         flip_angles,
                         inversion_TR,
                         excitation_TR,
                         N_excitations,
                         efficiency=0.96,
                         b1map=None,
                         s0img=None,
                         save_data=False,
                         overwrite=False,
                         output_dir=None,
                         file_name=None):
    """ MP2RAGEME PD mapping

    Estimate PD maps from MP2RAGEME data, combining T1 and R2* estimates
    with the MPRAGE model of _[1].

    Parameters
    ----------
    first_inversion: [niimg]
        List of {magnitude, phase} images for the first inversion
    second_inversion: [niimg]
        List of {magnitude, phase} images for the second inversion
    t1map: niimg
        Quantitative T1 map image, in milliseconds
    r2smap: niimg
        Quantitative R2* map image, in kHz
    echo_times: [float]
        List of {te1, te2, te3, te4, te5} echo times, in seconds
    inversion_times: [float]
        List of {first, second} inversion times, in seconds
    flip_angles: [float]
        List of {first, second} flip angles, in degrees
    inversion_TR: float
        Inversion repetition time, in seconds
    excitation_TR: [float]
        List of {first,second} repetition times,in seconds
    N_excitations: int
        Number of excitations
    efficiency: float
        Inversion efficiency (default is 0.96)
    correct_B1: bool
        Whether to correct for B1 inhomogeneities (default is False)
    b1map: niimg
        Computed B1 map (optional)
    s0map: niimg
        Computed S0 map (optional)
    scale_phase: bool
        Whether to rescale the phase image in [0,2PI] or to assume it is 
        already in radians
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * pd1 (niimg): Map of estimated proton density from inv1 (_qpd-inv1)
        * pd2 (niimg): Map of estimated proton density from inv2 (_qpd-inv2)
        * pd (niimg):  Map of estimated proton density average (_qpd-avg)
        
    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    
    References
    ----------
    .. [1] Marques, Kober, Krueger, van der Zwaag, Van de Moortele, Gruetter (2010)
        MP2RAGE, a self bias-field corrected sequence for improved segmentation 
        and T1-mapping at high field. doi: 10.1016/j.neuroimage.2009.10.002.
    """

    print('\nPD Mapping')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, first_inversion[0])

        pd1_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=first_inversion[0],
                           suffix='qpd-inv1'))

        pd2_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=first_inversion[0],
                           suffix='qpd-inv2'))

        pd_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=first_inversion[0],
                           suffix='qpd-avg'))

        if overwrite is False \
            and os.path.isfile(pd1_file) \
            and os.path.isfile(pd2_file) \
            and os.path.isfile(pd_file) :
            output = {'pd1': pd1_file, 'pd2': pd2_file, 'pd': pd_file}
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    qpdmap = nighresjava.IntensityMp2ragemePDmapping()

    # set algorithm parameters
    qpdmap.setFirstEchoTime(echo_times[0])
    qpdmap.setFirstInversionTime(inversion_times[0])
    qpdmap.setSecondInversionTime(inversion_times[1])
    qpdmap.setFirstFlipAngle(flip_angles[0])
    qpdmap.setSecondFlipAngle(flip_angles[1])
    qpdmap.setInversionRepetitionTime(inversion_TR)
    qpdmap.setFirstExcitationRepetitionTime(excitation_TR[0])
    qpdmap.setSecondExcitationRepetitionTime(excitation_TR[1])
    qpdmap.setNumberExcitations(N_excitations)
    qpdmap.setInversionEfficiency(efficiency)
    qpdmap.setCorrectB1inhomogeneities(b1map != None)

    # load first image and use it to set dimensions and resolution
    img = load_volume(first_inversion[0])
    data = img.get_data()
    #data = data[0:10,0:10,0:10]
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    qpdmap.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    qpdmap.setResolutions(resolution[0], resolution[1], resolution[2])

    # input images
    qpdmap.setFirstInversionMagnitude(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    data = load_volume(first_inversion[1]).get_data()
    qpdmap.setFirstInversionPhase(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    data = load_volume(second_inversion[0]).get_data()
    qpdmap.setSecondInversionMagnitude(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    data = load_volume(second_inversion[1]).get_data()
    qpdmap.setSecondInversionPhase(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    data = load_volume(t1map).get_data()
    qpdmap.setT1mapImage(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    data = load_volume(r2smap).get_data()
    qpdmap.setR2smapImage(
        nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    if (s0img != None):
        data = load_volume(s0img).get_data()
        qpdmap.setS0Image(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    if (b1map != None):
        data = load_volume(b1map).get_data()
        qpdmap.setB1mapImage(
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

    # execute the algorithm
    try:
        qpdmap.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    pd1_data = np.reshape(
        np.array(qpdmap.getProtonDensityImage1(), dtype=np.float32),
        dimensions, 'F')

    pd2_data = np.reshape(
        np.array(qpdmap.getProtonDensityImage2(), dtype=np.float32),
        dimensions, 'F')

    pd_data = np.reshape(
        np.array(qpdmap.getProtonDensityImage(), dtype=np.float32), dimensions,
        'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(pd1_data)
    header['cal_max'] = np.nanmax(pd1_data)
    pd1 = nb.Nifti1Image(pd1_data, affine, header)

    header['cal_min'] = np.nanmin(pd2_data)
    header['cal_max'] = np.nanmax(pd2_data)
    pd2 = nb.Nifti1Image(pd2_data, affine, header)

    header['cal_min'] = np.nanmin(pd_data)
    header['cal_max'] = np.nanmax(pd_data)
    pd = nb.Nifti1Image(pd_data, affine, header)

    if save_data:
        save_volume(pd1_file, pd1)
        save_volume(pd2_file, pd2)
        save_volume(pd_file, pd)
        return {'pd1': pd1_file, 'pd2': pd2_file, 'pd': pd_file}
    else:
        return {'pd1': pd1, 'pd2': pd2, 'pd': pd}
コード例 #26
0
def total_variation_filtering(image, mask=None, lambda_scale=0.05,
                      tau_step=0.125,max_dist=1e-4,max_iter=500,
                      save_data=False, overwrite=False, output_dir=None,
                      file_name=None):
    """ Total Variation Filtering

    Total variation filtering.

    Parameters
    ----------
    image: niimg
        Input image to filter
    mask: niimg, optional
        Data mask for processing
    lambda_scale: float, optional
        Relative intensity scale for total variation smoothing (default is 0.5)
    tau_step: float, optional
        Internal step parameter (default is 0.125)
    max_dist: float, optional
        Maximum distance for convergence (default is 1e-4)
    max_iter: int, optional
        Maximum number of iterations (default is 500)
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * filtered (niimg): The filtered image (_tv-img)
        * residual (niimg): The image residuals (_tv-res)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin. Algorithm adapted from [1]_

    References
    ----------
    .. [1] Chambolle (2004). An Algorithm for Total Variation Minimization and
        Applications. doi:10.1023/B:JMIV.0000011325.36760.1e
    """

    print('\nTotal variation filtering')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image)

        out_file = os.path.join(output_dir,
                        _fname_4saving(module=__name__,file_name=file_name,
                                   rootfile=image,
                                   suffix='tv-img'))

        res_file = os.path.join(output_dir,
                        _fname_4saving(module=__name__,file_name=file_name,
                                   rootfile=image,
                                   suffix='tv-res'))

        if overwrite is False \
            and os.path.isfile(out_file) and os.path.isfile(res_file) :
                print("skip computation (use existing results)")
                output = {'filtered': out_file,
                          'residual': res_file}
                return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create instance
    algo = nighresjava.TotalVariationFiltering()

    # set parameters

    # load image and use it to set dimensions and resolution
    img = load_volume(image)
    data = img.get_data()
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    algo.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    algo.setResolutions(resolution[0], resolution[1], resolution[2])

    algo.setImage(nighresjava.JArray('float')(
                                    (data.flatten('F')).astype(float)))


    if mask is not None:
        algo.setMaskImage(idx, nighresjava.JArray('int')(
                (load_volume(mask).get_data().flatten('F')).astype(int).tolist()))

    # set algorithm parameters
    algo.setLambdaScale(lambda_scale)
    algo.setTauStep(tau_step)
    algo.setMaxDist(max_dist)
    algo.setMaxIter(max_iter)

    # execute the algorithm
    try:
        algo.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    filtered_data = np.reshape(np.array(algo.getFilteredImage(),
                                    dtype=np.float32), dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(filtered_data)
    header['cal_max'] = np.nanmax(filtered_data)
    out = nb.Nifti1Image(filtered_data, affine, header)

    # reshape output to what nibabel likes
    residual_data = np.reshape(np.array(algo.getResidualImage(),
                                    dtype=np.float32), dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(residual_data)
    header['cal_max'] = np.nanmax(residual_data)
    res = nb.Nifti1Image(residual_data, affine, header)

    if save_data:
        save_volume(out_file, out)
        save_volume(res_file, res)

        return {'filtered': out_file, 'residual': res_file}
    else:
        return {'filtered': out, 'residual': res}
コード例 #27
0
def flash_t2s_fitting(image_list,
                      te_list,
                      save_data=False,
                      overwrite=False,
                      output_dir=None,
                      file_name=None):
    """ FLASH T2* fitting

    Estimate T2*/R2* by linear least squares fitting in log space.

    Parameters
    ----------
    image_list: [niimg]
        List of input images to fit the T2* curve
    te_list: [float]
        List of input echo times (TE)
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool, optional
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * t2s (niimg): Map of estimated T2* times (_qt2fit-t2s)
        * r2s (niimg): Map of estimated R2* relaxation rate (_qt2fit-r2s)
        * s0 (niimg): Estimated PD weighted image at TE=0 (_qt2fit-s0)
        * residuals (niimg): Estimated residuals between input and estimated echoes (_qt2fit-err)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    """

    print('\nT2* Fitting')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, image_list[0])

        t2s_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image_list[0],
                           suffix='qt2fit-t2s'))

        r2s_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image_list[0],
                           suffix='qt2fit-r2s'))

        s0_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image_list[0],
                           suffix='qt2fit-s0'))

        err_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=image_list[0],
                           suffix='qt2fit-err'))

        if overwrite is False \
            and os.path.isfile(t2s_file) \
            and os.path.isfile(r2s_file) \
            and os.path.isfile(s0_file) \
            and os.path.isfile(err_file) :
            output = {
                't2s': t2s_file,
                'r2s': r2s_file,
                's0': s0_file,
                'residuals': err_file
            }
            return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    qt2fit = nighresjava.IntensityFlashT2sFitting()

    # set algorithm parameters
    qt2fit.setNumberOfEchoes(len(image_list))

    # load first image and use it to set dimensions and resolution
    img = load_volume(image_list[0])
    data = img.get_data()
    #data = data[0:10,0:10,0:10]
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    qt2fit.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    qt2fit.setResolutions(resolution[0], resolution[1], resolution[2])

    # input images
    # important: set image number before adding images
    for idx, image in enumerate(image_list):
        #print('\nloading ('+str(idx)+'): '+image)
        data = load_volume(image).get_data()
        #data = data[0:10,0:10,0:10]
        qt2fit.setEchoImageAt(
            idx,
            nighresjava.JArray('float')((data.flatten('F')).astype(float)))

        qt2fit.setEchoTimeAt(idx, te_list[idx])

    # execute the algorithm
    try:
        qt2fit.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    t2s_data = np.reshape(np.array(qt2fit.getT2sImage(), dtype=np.float32),
                          dimensions, 'F')

    r2s_data = np.reshape(np.array(qt2fit.getR2sImage(), dtype=np.float32),
                          dimensions, 'F')

    s0_data = np.reshape(np.array(qt2fit.getS0Image(), dtype=np.float32),
                         dimensions, 'F')

    err_data = np.reshape(
        np.array(qt2fit.getResidualImage(), dtype=np.float32), dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(t2s_data)
    header['cal_max'] = np.nanmax(t2s_data)
    t2s = nb.Nifti1Image(t2s_data, affine, header)

    header['cal_min'] = np.nanmin(r2s_data)
    header['cal_max'] = np.nanmax(r2s_data)
    r2s = nb.Nifti1Image(r2s_data, affine, header)

    header['cal_min'] = np.nanmin(s0_data)
    header['cal_max'] = np.nanmax(s0_data)
    s0 = nb.Nifti1Image(s0_data, affine, header)

    header['cal_min'] = np.nanmin(err_data)
    header['cal_max'] = np.nanmax(err_data)
    err = nb.Nifti1Image(err_data, affine, header)

    if save_data:
        save_volume(t2s_file, t2s)
        save_volume(r2s_file, r2s)
        save_volume(s0_file, s0)
        save_volume(err_file, err)

        return {
            't2s': t2s_file,
            'r2s': r2s_file,
            's0': s0_file,
            'residuals': err_file
        }
    else:
        return {'t2s': t2s, 'r2s': r2s, 's0': s0, 'residuals': err}
コード例 #28
0
ファイル: Simple_Skeleton.py プロジェクト: JuliaHuck/nighres
def Simple_Skeleton(input_image,
		   shape_image_type = 'signed_distance',
                   boundary_threshold = 0.0,
                   skeleton_threshold = 2.0,
		   Topology_LUT_directory = None,
                   save_data=False, 
                   overwrite=False, 
                   output_dir=None,
                   file_name=None):

    """ Simple Skeleton
    
    Create a skeleton for a levelset surface or a probability map (loosely adapted from Bouix et al., 2006)


    Parameters
    ----------
    input_image: niimg
        Image containing structure-of-interest
    shape_image_type: str
        shape of the input image: either 'signed_distance' or 'probability_map'.
    boundary_threshold: float
	Boundary threshold (>0: inside, <0: outside)
    skeleton_threshold: float
	Skeleton threshold (>0: inside, <0: outside)
    Topology_LUT_directory:str
         Directory of LUT topology
    save_data: bool, optional
        Save output data to file (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
   Medial_Surface_Image
   Medial_Curve_Image

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    """

    if save_data:
        output_dir = _output_dir_4saving(output_dir, input_image)

        MedialSurface_file = _fname_4saving(file_name=file_name,
                                  rootfile=input_image,
                                  suffix='medial', )

        Medial_Curve_file = _fname_4saving(file_name=file_name,
                                  rootfile=input_image,
                                  suffix='skel')     

        if overwrite is False \
            and os.path.isfile(MedialSurface_file) \
            and os.path.isfile(Medial_Curve_file) :
                output = {'medial': load_volume(MedialSurface_file),
                          'skel': load_volume(Medial_Curve_file)}
                return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    skeleton = nighresjava.ShapeSimpleSkeleton()

    # set parameters
    skeleton.setBoundaryThreshold(boundary_threshold)
    skeleton.setSkeletonThreshold(skeleton_threshold)
    skeleton.setTopologyLUTdirectory(Topology_LUT_directory)
    skeleton.setShapeImageType(shape_image_type)


    # load images and set dimensions and resolution
    input_image = load_volume(input_image)
    data = input_image.get_data()
    affine = input_image.get_affine()
    header = input_image.get_header()
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = input_image.shape


    skeleton.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    skeleton.setResolutions(resolution[0], resolution[1], resolution[2])

    data = load_volume(input_image).get_data()
    skeleton.setShapeImage(nighresjava.JArray('float')(
                               (data.flatten('F')).astype(float)))

    # execute
    try:
        skeleton.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # Collect output
    medialImage_data = np.reshape(np.array(
                                    skeleton.getMedialSurfaceImage(),
                                    dtype=np.int8), dimensions, 'F')
    skelImage_data = np.reshape(np.array(
                                    skeleton.getMedialCurveImage(),
                                    dtype=np.int8), dimensions, 'F')


    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
 #   d_head['data_type'] = np.array(8).astype('int8') #convert the header as well
    header['cal_min'] = np.nanmin(medialImage_data)
    header['cal_max'] = np.nanmax(medialImage_data)
    medialImage = nb.Nifti1Image(medialImage_data, affine, header)

    header['cal_min'] = np.nanmin(skelImage_data)
    header['cal_max'] = np.nanmax(skelImage_data)
    skelImage = nb.Nifti1Image(skelImage_data, affine, header)

    if save_data:
        save_volume(os.path.join(output_dir, MedialSurface_file), medialImage)
        save_volume(os.path.join(output_dir, Medial_Curve_file), skelImage)

    return {'medialImage': medialImage, 'skelImage': skelImage}
コード例 #29
0
def probability_to_levelset(probability_image,
                            mask_image=None,
                            save_data=False,
                            overwrite=False,
                            output_dir=None,
                            file_name=None):
    """Levelset from probability map

    Creates a levelset surface representations from a probabilistic map
    or a mask. The levelset indicates each voxel's distance to the closest
    boundary. It takes negative values inside and positive values outside
    of the object.

    Parameters
    ----------
    probability_image: niimg
        Probability image to be turned into levelset. Values should be in
        [0, 1], either a binary mask or defining the boundary at 0.5.
    mask_image: niimg, optional
        Mask image defining the region in which to compute the levelset. Values
        equal to zero are set to maximum distance.
    save_data: bool, optional
        Save output data to file (default is False)
    overwrite: bool, optional
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * result (niimg): Levelset representation of surface (_p2l-surf)

    Notes
    ----------
    Original Java module by Pierre-Louis Bazin
    """

    print("\nProbability to Levelset")

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, probability_image)

        levelset_file = os.path.join(
            output_dir,
            _fname_4saving(module=__name__,
                           file_name=file_name,
                           rootfile=probability_image,
                           suffix='p2l-surf'))

        if overwrite is False \
            and os.path.isfile(levelset_file) :

            print("skip computation (use existing results)")
            output = {'result': levelset_file}
            return output

    # start virtual machine if not running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass

    # initiate class
    prob2level = nighresjava.SurfaceProbabilityToLevelset()

    # load the data
    prob_img = load_volume(probability_image)
    prob_data = prob_img.get_fdata()
    hdr = prob_img.header
    aff = prob_img.affine
    resolution = [x.item() for x in hdr.get_zooms()]
    dimensions = prob_data.shape

    # set parameters from input data
    prob2level.setProbabilityImage(
        nighresjava.JArray('float')((prob_data.flatten('F')).astype(float)))

    if (mask_image is not None):
        mask_data = load_volume(mask_image).get_fdata()
        prob2level.setMaskImage(
            nighresjava.JArray('int')(
                (mask_data.flatten('F')).astype(int).tolist()))

    if len(dimensions) > 2:
        prob2level.setResolutions(resolution[0], resolution[1], resolution[2])
        prob2level.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    else:
        prob2level.setResolutions(resolution[0], resolution[1], 1.0)
        prob2level.setDimensions(dimensions[0], dimensions[1], 1)

    # execute class
    try:
        prob2level.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # collect outputs
    levelset_data = np.reshape(
        np.array(prob2level.getLevelSetImage(), dtype=np.float32), dimensions,
        'F')

    hdr['cal_max'] = np.nanmax(levelset_data)
    levelset = nb.Nifti1Image(levelset_data, aff, hdr)

    if save_data:
        save_volume(levelset_file, levelset)
        return {'result': levelset_file}
    else:
        return {'result': levelset}
コード例 #30
0
def mp2rage_t1_from_uni(uniform_image, 
                      inversion_times, flip_angles, inversion_TR,
                      excitation_TR, N_excitations, efficiency=0.96,
                      correct_B1=False, B1_map=None, B1_scale=1.0,
                      scale_phase=True,
                      save_data=False, overwrite=False, output_dir=None,
                      file_name=None):
    """ MP2RAGE uniform image to T1 mapping

    Estimate T1/R1 by a look-up table method adapted from [1]_

    Parameters
    ----------
    uniform_image: niimg
        Uniform image computed from first and second inversion
    inversion_times: [float]
        List of {first, second} inversion times, in seconds
    flip_angles: [float]
        List of {first, second} flip angles, in degrees
    inversion_TR: float
        Inversion repetition time, in seconds
    excitation_TR: [float]
        List of {first,second} repetition times,in seconds
    N_excitations: int
        Number of excitations
    efficiency: float
        Inversion efficiency (default is 0.96)
    correct_B1: bool
        Whether to correct for B1 inhomogeneities (default is False)
    B1_map: niimg
        Computed B1 map
    B1_scale: float
        B1 map scaling factor (default is 1.0)
    scale_phase: bool
        Whether to rescale the phase image in [0,2PI] or to assume it is 
        already in radians
    save_data: bool
        Save output data to file (default is False)
    overwrite: bool
        Overwrite existing results (default is False)
    output_dir: str, optional
        Path to desired output directory, will be created if it doesn't exist
    file_name: str, optional
        Desired base name for output files with file extension
        (suffixes will be added)

    Returns
    ----------
    dict
        Dictionary collecting outputs under the following keys
        (suffix of output files in brackets)

        * t1 (niimg): Map of estimated T1 times in seconds (_qt1map-t1)
        * r1 (niimg): Map of estimated R1 relaxation rate in hertz (_qt1map-r1)
        
    Notes
    ----------
    Original Java module by Pierre-Louis Bazin.
    
    References
    ----------
    .. [1] Marques, Kober, Krueger, van der Zwaag, Van de Moortele, Gruetter (2010)
        MP2RAGE, a self bias-field corrected sequence for improved segmentation 
        and T1-mapping at high field. doi: 10.1016/j.neuroimage.2009.10.002.
    """

    print('\nT1 Mapping')

    # make sure that saving related parameters are correct
    if save_data:
        output_dir = _output_dir_4saving(output_dir, uniform_image)

        t1_file = os.path.join(output_dir, 
                        _fname_4saving(module=__name__,file_name=file_name,
                                   rootfile=uniform_image,
                                   suffix='qt1map-t1'))

        r1_file = os.path.join(output_dir, 
                        _fname_4saving(module=__name__,file_name=file_name,
                                   rootfile=uniform_image,
                                   suffix='qt1map-r1'))

        if overwrite is False \
            and os.path.isfile(t1_file) \
            and os.path.isfile(r1_file) :
                output = {'t1': t1_file,
                          'r1': r1_file}
                return output

    # start virtual machine, if not already running
    try:
        mem = _check_available_memory()
        nighresjava.initVM(initialheap=mem['init'], maxheap=mem['max'])
    except ValueError:
        pass
    # create algorithm instance
    qt1map = nighresjava.IntensityMp2rageT1Fitting()

    # set algorithm parameters
    qt1map.setFirstInversionTime(inversion_times[0])
    qt1map.setSecondInversionTime(inversion_times[1])
    qt1map.setFirstFlipAngle(flip_angles[0])
    qt1map.setSecondFlipAngle(flip_angles[1])
    qt1map.setInversionRepetitionTime(inversion_TR)
    qt1map.setFirstExcitationRepetitionTime(excitation_TR[0])
    qt1map.setSecondExcitationRepetitionTime(excitation_TR[1])
    qt1map.setNumberExcitations(N_excitations)
    qt1map.setInversionEfficiency(efficiency)
    qt1map.setCorrectB1inhomogeneities(correct_B1)
     
    # load first image and use it to set dimensions and resolution
    img = load_volume(uniform_image)
    data = img.get_fdata()
    #data = data[0:10,0:10,0:10]
    affine = img.affine
    header = img.header
    resolution = [x.item() for x in header.get_zooms()]
    dimensions = data.shape

    qt1map.setDimensions(dimensions[0], dimensions[1], dimensions[2])
    qt1map.setResolutions(resolution[0], resolution[1], resolution[2])

    # input images
    qt1map.setUniformImage(nighresjava.JArray('float')(
                                    (data.flatten('F')).astype(float)))
     
    if (correct_B1):
        data = load_volume(B1_map).get_fdata()
        qt1map.setB1mapImage(nighresjava.JArray('float')(
                                    (data.flatten('F')).astype(float)))
        qt1map.setB1mapScaling(B1_scale)
 
    # execute the algorithm
    try:
        qt1map.execute()

    except:
        # if the Java module fails, reraise the error it throws
        print("\n The underlying Java code did not execute cleanly: ")
        print(sys.exc_info()[0])
        raise
        return

    # reshape output to what nibabel likes
    t1_data = np.reshape(np.array(qt1map.getQuantitativeT1mapImage(),
                                    dtype=np.float32), dimensions, 'F')

    r1_data = np.reshape(np.array(qt1map.getQuantitativeR1mapImage(),
                                    dtype=np.float32), dimensions, 'F')

    # adapt header max for each image so that correct max is displayed
    # and create nifiti objects
    header['cal_min'] = np.nanmin(t1_data)
    header['cal_max'] = np.nanmax(t1_data)
    t1 = nb.Nifti1Image(t1_data, affine, header)

    header['cal_min'] = np.nanmin(r1_data)
    header['cal_max'] = np.nanmax(r1_data)
    r1 = nb.Nifti1Image(r1_data, affine, header)

    if save_data:
        save_volume(t1_file, t1)
        save_volume(r1_file, r1)
        return {'t1': t1_file, 'r1': r1_file}
    else:
        return {'t1': t1, 'r1': r1}