Exemple #1
0
def ThresholdImage(volume, output_file='', threshlo=1, threshhi=10000):
    """
    Use the ThresholdImage function in ANTs to threshold image volume.

    Usage: ThresholdImage ImageDimension ImageIn.ext outImage.ext
           threshlo threshhi <insideValue> <outsideValue>

    Parameters
    ----------
    volume : string
        nibabel-readable image volume
    output_file : string
        nibabel-readable image volume
    threshlo : integer
        lower threshold
    threshhi : integer
        upper threshold

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> import os
    >>> from mindboggle.thirdparty.ants import ThresholdImage
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> volume = fetch_data(urls['T1_001'], '', '.nii.gz')
    >>> os.rename(volume, volume + '.nii.gz')
    >>> volume += '.nii.gz'
    >>> output_file = ''
    >>> threshlo = 500
    >>> threshhi = 10000
    >>> output_file = ThresholdImage(volume, output_file, threshlo, threshhi) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'threshold_' + os.path.basename(volume))
    cmd = [
        'ThresholdImage', '3', volume, output_file,
        str(threshlo),
        str(threshhi)
    ]
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError("ThresholdImage did not create " + output_file + ".")

    return output_file
Exemple #2
0
def ThresholdImage(volume, output_file='', threshlo=1, threshhi=10000):
    """
    Use the ThresholdImage function in ANTs to threshold image volume.

    Usage: ThresholdImage ImageDimension ImageIn.ext outImage.ext
           threshlo threshhi <insideValue> <outsideValue>

    Parameters
    ----------
    volume : string
        nibabel-readable image volume
    output_file : string
        nibabel-readable image volume
    threshlo : integer
        lower threshold
    threshhi : integer
        upper threshold

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> import os
    >>> from mindboggle.thirdparty.ants import ThresholdImage
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> volume = fetch_data(urls['T1_001'])
    >>> os.rename(volume, volume + '.nii.gz')
    >>> volume += '.nii.gz'
    >>> output_file = ''
    >>> threshlo = 500
    >>> threshhi = 10000
    >>> output_file = ThresholdImage(volume, output_file, threshlo, threshhi) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'threshold_' + os.path.basename(volume))
    cmd = ['ThresholdImage', '3', volume, output_file,
           str(threshlo), str(threshhi)]
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError("ThresholdImage did not create " + output_file + ".")

    return output_file
Exemple #3
0
def ThresholdImage(volume, output_file='', threshlo=1, threshhi=10000):
    """
    Use the ThresholdImage function in ANTs to threshold image volume::

    Usage: ThresholdImage ImageDimension ImageIn.ext outImage.ext
           threshlo threshhi <insideValue> <outsideValue>

    Parameters
    ----------
    volume : string
        nibabel-readable image volume
    output_file : string
        nibabel-readable image volume
    threshlo : integer
        lower threshold
    threshhi : integer
        upper threshold

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> import os
    >>> from mindboggle.thirdparty.ants import ThresholdImage
    >>> from mindboggle.mio.plots import plot_volumes
    >>> path = os.path.join(os.environ['MINDBOGGLE_DATA'])
    >>> volume = os.path.join(path, 'arno', 'mri', 't1weighted.nii.gz')
    >>> output_file = ''
    >>> threshlo = 500
    >>> threshhi = 10000
    >>> output_file = ThresholdImage(volume, output_file, threshlo, threshhi)
    >>> # View
    >>> plot_volumes(output_file)

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'threshold_' + os.path.basename(volume))

    cmd = 'ThresholdImage 3 {0} {1} {2} {3}'.format(volume, output_file,
                                                    threshlo, threshhi)
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise (IOError("ThresholdImage did not create " + output_file + "."))

    return output_file
Exemple #4
0
def ThresholdImage(volume, output_file='', threshlo=1, threshhi=10000):
    """
    Use the ThresholdImage function in ANTs to threshold image volume::

    Usage: ThresholdImage ImageDimension ImageIn.ext outImage.ext
           threshlo threshhi <insideValue> <outsideValue>

    Parameters
    ----------
    volume : string
        nibabel-readable image volume
    output_file : string
        nibabel-readable image volume
    threshlo : integer
        lower threshold
    threshhi : integer
        upper threshold

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> import os
    >>> from mindboggle.thirdparty.ants import ThresholdImage
    >>> from mindboggle.mio.plots import plot_volumes
    >>> path = os.path.join(os.environ['MINDBOGGLE_DATA'])
    >>> volume = os.path.join(path, 'arno', 'mri', 't1weighted.nii.gz')
    >>> output_file = ''
    >>> threshlo = 500
    >>> threshhi = 10000
    >>> output_file = ThresholdImage(volume, output_file, threshlo, threshhi)
    >>> # View
    >>> plot_volumes(output_file)

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'threshold_' + os.path.basename(volume))

    cmd = 'ThresholdImage 3 {0} {1} {2} {3}'.format(volume, output_file,
                                                    threshlo, threshhi)
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise(IOError("ThresholdImage did not create " + output_file + "."))

    return output_file
Exemple #5
0
def plot_volumes(volume_files, command='fslview'):
    """
    Use fslview to visualize image volume data.

    Parameters
    ----------
    volume_files : list of strings
        names of image volume files
    command : string
        plotting software command

    Examples
    --------
    >>> import os
    >>> from mindboggle.mio.plots import plot_volumes
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> label_file1 = fetch_data(urls['freesurfer_labels'], '', '.vtk')
    >>> label_file2 = fetch_data(urls['freesurfer_labels'], '', '.vtk')
    >>> volume_files = [label_file1, label_file2]
    >>> command = 'fslview'
    >>> command = '/Applications/ITK-SNAP.app/Contents/MacOS/InsightSNAP'
    >>> plot_volumes(volume_files, command=command) # doctest: +SKIP

    """
    from mindboggle.guts.utilities import execute

    if isinstance(volume_files, str):
        volume_files = [volume_files]
    elif not isinstance(volume_files, list):
        raise IOError('plot_volumes() requires volume_files to be a list '
                      'or string.')

    if not isinstance(command, str):
        raise IOError('plot_volumes() requires command to be a string.')
    else:
        command = [command]

    command.extend(volume_files)
    command.extend('&')
    execute(command, 'os')
Exemple #6
0
def plot_volumes(volume_files, command='fslview'):
    """
    Use fslview to visualize image volume data.

    Parameters
    ----------
    volume_files : list of strings
        names of image volume files
    command : string
        plotting software command

    Examples
    --------
    >>> import os
    >>> from mindboggle.mio.plots import plot_volumes
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> label_file1 = fetch_data(urls['freesurfer_labels'], '', '.vtk')
    >>> label_file2 = fetch_data(urls['freesurfer_labels'], '', '.vtk')
    >>> volume_files = [label_file1, label_file2]
    >>> command = 'fslview'
    >>> command = '/Applications/ITK-SNAP.app/Contents/MacOS/InsightSNAP'
    >>> plot_volumes(volume_files, command=command) # doctest: +SKIP

    """
    from mindboggle.guts.utilities import execute

    if isinstance(volume_files, str):
        volume_files = [volume_files]
    elif not isinstance(volume_files, list):
        raise IOError('plot_volumes() requires volume_files to be a list '
                      'or string.')

    if not isinstance(command, str):
        raise IOError('plot_volumes() requires command to be a string.')
    else:
        command = [command]

    command.extend(volume_files)
    command.extend('&')
    execute(command, 'os')
Exemple #7
0
def plot_volumes(volume_files, command='fslview'):
    """
    Use fslview to visualize image volume data.

    Parameters
    ----------
    volume_files : list of strings
        names of image volume files
    command : string
        plotting software command

    Examples
    --------
    >>> import os
    >>> from mindboggle.mio.plots import plot_volumes
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> volume_file1 = os.path.join(path, 'Twins-2-1', 'mri', 't1weighted.nii.gz')
    >>> volume_file2 = os.path.join(path, 'Twins-2-1', 'mri', 't1weighted_brain.nii.gz')
    >>> volume_files = [volume_file1, volume_file2]
    >>> command = 'fslview'
    >>> command = '/Applications/ITK-SNAP.app/Contents/MacOS/InsightSNAP'
    >>> plot_volumes(volume_files, command=command)

    """
    from mindboggle.guts.utilities import execute

    if isinstance(volume_files, str):
        volume_files = [volume_files]
    elif not isinstance(volume_files, list):
        raise(IOError('plot_volumes() requires volume_files to be a list or string.'))

    if not isinstance(command, str):
        raise(IOError('plot_volumes() requires command to be a string.'))
    else:
        command = [command]

    command.extend(volume_files)
    command.extend('&')
    execute(command, 'os')
Exemple #8
0
def ResampleImageBySpacing(volume,
                           output_file='',
                           outxspc=1,
                           outyspc=1,
                           outzspc=1,
                           dosmooth=0,
                           addvox=0,
                           nninterp=1):
    """
    Use the ResampleImageBySpacing function in ANTs to resample image volume.

    Usage: ResampleImageBySpacing ImageDimension ImageIn.ext outImage.ex
           outxspc outyspc <outzspc> <dosmooth?> <addvox> <nninterp?>

    Parameters
    ----------
    volume : string
        nibabel-readable image volume
    output_file : string
        nibabel-readable image volume
    outxspc : integer
        output x-spacing
    outyspc : integer
        output y-spacing
    outzspc : integer
        output z-spacing
    dosmooth : bool
        smooth?
    addvox : integer
        pad each dimension by addvox
    nninterp : bool
        nearest-neighbor interpolation?

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> # Resample image so that 1mm voxels are 0.5mm voxels:
    >>> import os
    >>> from mindboggle.thirdparty.ants import ResampleImageBySpacing
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> volume = fetch_data(urls['T1_001'], '', '.nii.gz')
    >>> os.rename(volume, volume + '.nii.gz')
    >>> volume += '.nii.gz'
    >>> output_file = ''
    >>> outxspc = 1/2.0
    >>> outyspc = 1/2.0
    >>> outzspc = 1/2.0
    >>> dosmooth = 0
    >>> addvox = 0
    >>> nninterp = 1
    >>> output_file = ResampleImageBySpacing(volume, output_file, outxspc,
    ...     outxspc, outzspc, dosmooth, addvox, nninterp) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'resampled_' + os.path.basename(volume))
    cmd = [
        'ResampleImageBySpacing', '3', volume, output_file,
        str(outxspc),
        str(outyspc),
        str(outzspc)
    ]
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError(
            "ResampleImageBySpacing did not create {0).".format(output_file))

    return output_file
Exemple #9
0
def PropagateLabelsThroughMask(mask,
                               labels,
                               mask_index=None,
                               output_file='',
                               binarize=True,
                               stopvalue=''):
    """
    Use ANTs to fill a binary volume mask with initial labels.

    This program uses ThresholdImage and the ImageMath
    PropagateLabelsThroughMask functions in ANTs.

    ThresholdImage ImageDimension ImageIn.ext outImage.ext
        threshlo threshhi <insideValue> <outsideValue>

    PropagateLabelsThroughMask: Final output is the propagated label image.
        ImageMath ImageDimension Out.ext PropagateLabelsThroughMask
        speed/binaryimagemask.nii.gz initiallabelimage.nii.gz ...

    Parameters
    ----------
    mask : string
        nibabel-readable image volume
    labels : string
        nibabel-readable image volume with integer labels
    mask_index : integer (optional)
        mask with just voxels having this value
    output_file : string (optional)
        nibabel-readable labeled image volume
    binarize : bool (optional)
        binarize mask?
    stopvalue : integer (optional)
        stopping value

    Returns
    -------
    output_file : string
        name of labeled output nibabel-readable image volume

    Examples
    --------
    >>> # Propagate FreeSurfer labels through brain mask:
    >>> import os
    >>> from mindboggle.thirdparty.ants import PropagateLabelsThroughMask
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> labels = fetch_data(urls['freesurfer_labels'], '', '.nii.gz')
    >>> mask = fetch_data(urls['ants_mask'], '', '.nii.gz')
    >>> mask_index = None
    >>> output_file = ''
    >>> binarize = True
    >>> stopvalue = None
    >>> output_file = PropagateLabelsThroughMask(mask, labels, mask_index,
    ...     output_file, binarize, stopvalue) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        #output_file = os.path.join(os.getcwd(),
        #                           'PropagateLabelsThroughMask.nii.gz')
        output_file = os.path.join(
            os.getcwd(),
            os.path.basename(labels) + '_through_' + os.path.basename(mask))

    print('mask: {0}, labels: {1}'.format(mask, labels))

    # Binarize image volume:
    if binarize:
        temp_file = os.path.join(os.getcwd(),
                                 'PropagateLabelsThroughMask.nii.gz')
        cmd = ['ThresholdImage', '3', mask, temp_file, '0 1 0 1']
        execute(cmd, 'os')
        mask = temp_file

    # Mask with just voxels having mask_index value:
    if mask_index:
        mask2 = os.path.join(os.getcwd(), 'temp.nii.gz')

        cmd = [
            'ThresholdImage', '3', mask, mask2,
            str(mask_index),
            str(mask_index)
        ]
        execute(cmd, 'os')
    else:
        mask2 = mask

    # Propagate labels:

    cmd = [
        'ImageMath', '3', output_file, 'PropagateLabelsThroughMask', mask2,
        labels
    ]
    if stopvalue:
        cmd.extend(str(stopvalue))
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError("ImageMath did not create " + output_file + ".")

    return output_file
Exemple #10
0
def antsApplyTransformsToPoints(points, transform_files, inverse_booleans=[0]):
    """
    Run ANTs antsApplyTransformsToPoints function to transform points.
    (Creates pre- and post-transformed .csv points files for ANTs.)

    Parameters
    ----------
    points : list of lists of three integers
        point coordinate data
    transform_files : list
        transform file names
    inverse_booleans : list
        for each transform, one to apply inverse of transform (otherwise zero)

    Returns
    -------
    transformed_points : list of lists of three integers
        transformed point coordinate data

    Examples
    --------
    >>> import numpy as np
    >>> from mindboggle.thirdparty.ants import antsApplyTransformsToPoints
    >>> from mindboggle.mio.vtks import read_points
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> xfm1 = fetch_data(urls['ants_affine_template2subject'], '', '.mat')
    >>> xfm2 = fetch_data(urls['ants_warp_template2subject'], '', '.nii.gz')
    >>> xfm3 = fetch_data(urls['OASIS-30_Atropos_template_to_MNI152_affine'], '', '.txt')
    >>> transform_files = [xfm1, xfm2, xfm3]
    >>> vtk_file = fetch_data(urls['left_pial'], '', '.vtk')
    >>> points = read_points(vtk_file)
    >>> inverse_booleans = [0,0,1]
    >>> transformed_points = antsApplyTransformsToPoints(points,
    ...     transform_files, inverse_booleans) # doctest: +SKIP
    >>> print(np.array_str(np.array(transformed_points[0:5]),
    ...       precision=5, suppress_small=True)) # doctest: +SKIP
    [[-11.23189 -46.78223 -39.88869]
     [-11.71384 -46.87075 -40.13328]
     [-12.56237 -46.99126 -40.04564]
     [ -9.66693 -46.0446  -41.36334]
     [-10.67998 -46.45458 -40.7572 ]]

    """
    import os
    from io import open

    from mindboggle.guts.utilities import execute

    # ------------------------------------------------------------------------
    # Write points (x,y,z,1) to a .csv file:
    # ------------------------------------------------------------------------
    points_file = os.path.join(os.getcwd(), 'points.csv')
    fid = open(points_file, 'w')
    fid.write('x,y,z,t\n')
    fid.close()
    fid = open(points_file, 'a')
    for point in points:
        string_of_zeros = (4 - len(point)) * ',0'
        fid.write(','.join([str(x) for x in point]) + string_of_zeros + '\n')
    fid.close()

    # ------------------------------------------------------------------------
    # Apply transforms to points in .csv file:
    # ------------------------------------------------------------------------
    transformed_points_file = os.path.join(os.getcwd(),
                                           'transformed_points.csv')
    transform_string = ''
    for ixfm, transform_file in enumerate(transform_files):
        transform_string += " --t [{0},{1}]".\
            format(transform_file, str(inverse_booleans[ixfm]))
    cmd = [
        'antsApplyTransformsToPoints', '-d', '3', '-i', points_file, '-o',
        transformed_points_file, transform_string
    ]
    try:
        execute(cmd, 'os')
    except:
        raise Exception("Cannot find antsApplyTransformsToPoints command.")

    if not os.path.exists(transformed_points_file):
        raise IOError("antsApplyTransformsToPoints did not create {0}.".format(
            transformed_points_file))

    # ------------------------------------------------------------------------
    # Return transformed points:
    # ------------------------------------------------------------------------
    fid = open(transformed_points_file, 'r')
    lines = fid.readlines()
    fid.close()
    transformed_points = []
    for iline, line in enumerate(lines):
        if iline > 0:
            point_xyz1 = [float(x) for x in line.split(',')]
            transformed_points.append(point_xyz1[0:3])

    return transformed_points
Exemple #11
0
def PropagateLabelsThroughMask(mask,
                               labels,
                               mask_index=None,
                               output_file='',
                               binarize=True,
                               stopvalue=''):
    """
    Use ANTs to fill a binary volume mask with initial labels.

    This program uses ThresholdImage and the ImageMath
    PropagateLabelsThroughMask functions in ANTs.

    ThresholdImage ImageDimension ImageIn.ext outImage.ext
        threshlo threshhi <insideValue> <outsideValue>

    PropagateLabelsThroughMask: Final output is the propagated label image.
        ImageMath ImageDimension Out.ext PropagateLabelsThroughMask
        speed/binaryimagemask.nii.gz initiallabelimage.nii.gz ...

    Parameters
    ----------
    mask : string
        nibabel-readable image volume
    labels : string
        nibabel-readable image volume with integer labels
    mask_index : integer (optional)
        mask with just voxels having this value
    output_file : string
        nibabel-readable labeled image volume
    binarize : Boolean
        binarize mask?
    stopvalue : integer
        stopping value

    Returns
    -------
    output_file : string
        name of labeled output nibabel-readable image volume

    Examples
    --------
    >>> import os
    >>> from mindboggle.thirdparty.ants import PropagateLabelsThroughMask
    >>> from mindboggle.mio.plots import plot_volumes
    >>> path = os.path.join(os.environ['MINDBOGGLE_DATA'])
    >>> labels = os.path.join(path, 'arno', 'labels', 'labels.DKT25.manual.nii.gz')
    >>> mask = os.path.join(path, 'arno', 'mri', 't1weighted_brain.nii.gz')
    >>> mask_index = None
    >>> output_file = ''
    >>> binarize = True
    >>> stopvalue = None
    >>> output_file = PropagateLabelsThroughMask(mask, labels, mask_index, output_file, binarize, stopvalue)
    >>> # View
    >>> plot_volumes(output_file)

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        #output_file = os.path.join(os.getcwd(),
        #                           'PropagateLabelsThroughMask.nii.gz')
        output_file = os.path.join(
            os.getcwd(),
            os.path.basename(labels) + '_through_' + os.path.basename(mask))

    print('mask: {0}, labels: {1}'.format(mask, labels))

    # Binarize image volume:
    if binarize:
        temp_file = os.path.join(os.getcwd(),
                                 'PropagateLabelsThroughMask.nii.gz')
        cmd = ['ThresholdImage', '3', mask, temp_file, '0 1 0 1']
        execute(cmd, 'os')
        mask = temp_file

    # Mask with just voxels having mask_index value:
    if mask_index:
        mask2 = os.path.join(os.getcwd(), 'temp.nii.gz')
        cmd = 'ThresholdImage 3 {0} {1} {2} {3} 1 0'.format(
            mask, mask2, mask_index, mask_index)
        execute(cmd)
    else:
        mask2 = mask

    # Propagate labels:
    cmd = [
        'ImageMath', '3', output_file, 'PropagateLabelsThroughMask', mask2,
        labels
    ]
    if stopvalue:
        cmd.extend(stopvalue)
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise (IOError("ImageMath did not create " + output_file + "."))

    return output_file
Exemple #12
0
def ImageMath(volume1, volume2, operator='m', output_file=''):
    """
    Use the ImageMath function in ANTs to perform operation on two volumes::

        m         : Multiply ---  use vm for vector multiply
        +         : Add ---  use v+ for vector add
        -         : Subtract ---  use v- for vector subtract
        /         : Divide
        ^         : Power
        exp       : Take exponent exp(imagevalue*value)
        addtozero : add image-b to image-a only over points where image-a has zero values
        overadd   : replace image-a pixel with image-b pixel if image-b pixel is non-zero
        abs       : absolute value
        total     : Sums up values in an image or in image1*image2 (img2 is the probability mask)
        mean      :  Average of values in an image or in image1*image2 (img2 is the probability mask)
        vtotal    : Sums up volumetrically weighted values in an image or in image1*image2 (img2 is the probability mask)
        Decision  : Computes result=1./(1.+exp(-1.0*( pix1-0.25)/pix2))
        Neg       : Produce image negative


    Parameters
    ----------
    volume1 : string
        nibabel-readable image volume
    volume2 : string
        nibabel-readable image volume
    operator : string
        ImageMath string corresponding to mathematical operator
    output_file : string
        nibabel-readable image volume

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> # Mask head with brain mask:
    >>> import os
    >>> from mindboggle.thirdparty.ants import ImageMath
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> volume1 = fetch_data(urls['T1_001'], '', '.nii.gz')
    >>> volume2 = fetch_data(urls['ants_mask'], '', '.nii.gz')
    >>> operator = 'm'
    >>> output_file = ''
    >>> output_file = ImageMath(volume1, volume2, operator, output_file) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(
            os.getcwd(),
            os.path.basename(volume1) + '_' + os.path.basename(volume2))
    cmd = ['ImageMath', '3', output_file, operator, volume1, volume2]
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError("ImageMath did not create " + output_file + ".")

    return output_file
Exemple #13
0
def ResampleImageBySpacing(volume, output_file='', outxspc=1, outyspc=1,
                           outzspc=1, dosmooth=0, addvox=0, nninterp=1):
    """
    Use the ResampleImageBySpacing function in ANTs to resample image volume.

    Usage: ResampleImageBySpacing ImageDimension ImageIn.ext outImage.ex
           outxspc outyspc <outzspc> <dosmooth?> <addvox> <nninterp?>

    Parameters
    ----------
    volume : string
        nibabel-readable image volume
    output_file : string
        nibabel-readable image volume
    outxspc : integer
        output x-spacing
    outyspc : integer
        output y-spacing
    outzspc : integer
        output z-spacing
    dosmooth : bool
        smooth?
    addvox : integer
        pad each dimension by addvox
    nninterp : bool
        nearest-neighbor interpolation?

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> # Resample image so that 1mm voxels are 0.5mm voxels:
    >>> import os
    >>> from mindboggle.thirdparty.ants import ResampleImageBySpacing
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> volume = fetch_data(urls['T1_001'])
    >>> os.rename(volume, volume + '.nii.gz')
    >>> volume += '.nii.gz'
    >>> output_file = ''
    >>> outxspc = 1/2.0
    >>> outyspc = 1/2.0
    >>> outzspc = 1/2.0
    >>> dosmooth = 0
    >>> addvox = 0
    >>> nninterp = 1
    >>> output_file = ResampleImageBySpacing(volume, output_file, outxspc,
    ...     outxspc, outzspc, dosmooth, addvox, nninterp) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'resampled_' + os.path.basename(volume))
    cmd = ['ResampleImageBySpacing', '3', volume, output_file,
           str(outxspc), str(outyspc), str(outzspc)]
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError("ResampleImageBySpacing did not create {0).".
                      format(output_file))

    return output_file
Exemple #14
0
def plot_mask_surface(vtk_file, mask_file='', nonmask_value=-1,
                      masked_output='', remove_nonmask=False,
                      program='vtkviewer',
                      use_colormap=False, colormap_file=''):
    """
    Use vtkviewer or mayavi2 to visualize VTK surface mesh data.

    If a mask_file is provided, a temporary masked file is saved,
    and it is this file that is viewed.

    If using vtkviewer, can optionally provide colormap file
    or set $COLORMAP environment variable.

    Parameters
    ----------
    vtk_file : string
        name of VTK surface mesh file
    mask_file : string
        name of VTK surface mesh file to mask vtk_file vertices
    nonmask_value : integer
        nonmask (usually background) value
    masked_output : string
        temporary masked output file name
    remove_nonmask : Boolean
        remove vertices that are not in mask? (otherwise assign nonmask_value)
    program : string {'vtkviewer', 'mayavi2'}
        program to visualize VTK file
    use_colormap : Boolean
        use Paraview-style XML colormap file set by $COLORMAP env variable?
    colormap_file : string
        use colormap in given file if use_colormap==True?  if empty and
        use_colormap==True, use file set by $COLORMAP environment variable

    Examples
    --------
    >>> import os
    >>> from mindboggle.mio.plots import plot_mask_surface
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> vtk_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT31.manual.vtk')
    >>> mask_file = os.path.join(path, 'test_one_label.vtk')
    >>> nonmask_value = 0 #-1
    >>> masked_output = ''
    >>> remove_nonmask = True
    >>> program = 'vtkviewer'
    >>> use_colormap = True
    >>> colormap_file = '' #'/software/surface_cpp_tools/colormap.xml'
    >>> plot_mask_surface(vtk_file, mask_file, nonmask_value, masked_output, remove_nonmask, program, use_colormap, colormap_file)

    """
    import os
    import numpy as np

    from mindboggle.guts.mesh import remove_faces, reindex_faces_points
    from mindboggle.guts.utilities import execute
    from mindboggle.mio.plots import plot_surfaces
    from mindboggle.mio.vtks import read_scalars, rewrite_scalars, \
                                        read_vtk, write_vtk

    #-------------------------------------------------------------------------
    # Filter mesh with non-background values from a second (same-size) mesh:
    #-------------------------------------------------------------------------
    if mask_file:
        mask, name = read_scalars(mask_file, True, True)
        if not masked_output:
            masked_output = os.path.join(os.getcwd(), 'temp.vtk')
        file_to_plot = masked_output

        #---------------------------------------------------------------------
        # Remove nonmask-valued vertices:
        #---------------------------------------------------------------------
        if remove_nonmask:
            #-----------------------------------------------------------------
            # Load VTK files:
            #-----------------------------------------------------------------
            points, indices, lines, faces, scalars, scalar_names, npoints, \
                input_vtk = read_vtk(vtk_file, True, True)
            #-----------------------------------------------------------------
            # Find mask indices, remove nonmask faces, and reindex:
            #-----------------------------------------------------------------
            Imask = [i for i,x in enumerate(mask) if x != nonmask_value]
            mask_faces = remove_faces(faces, Imask)
            mask_faces, points, \
            original_indices = reindex_faces_points(mask_faces, points)
            #-----------------------------------------------------------------
            # Write VTK file with scalar values:
            #-----------------------------------------------------------------
            if np.ndim(scalars) == 1:
                scalar_type = type(scalars[0]).__name__
            elif np.ndim(scalars) == 2:
                scalar_type = type(scalars[0][0]).__name__
            else:
                print("Undefined scalar type!")
            write_vtk(file_to_plot, points, [], [], mask_faces,
                      scalars[original_indices].tolist(), scalar_names,
                      scalar_type=scalar_type)
        else:
            scalars, name = read_scalars(vtk_file, True, True)
            scalars[mask == nonmask_value] = nonmask_value
            rewrite_scalars(vtk_file, file_to_plot, scalars)
    else:
        file_to_plot = vtk_file

    #-------------------------------------------------------------------------
    # Display with vtkviewer.py:
    #-------------------------------------------------------------------------
    if program == 'vtkviewer':
        plot_surfaces(file_to_plot, use_colormap=use_colormap,
                      colormap_file=colormap_file)
    #-------------------------------------------------------------------------
    # Display with mayavi2:
    #-------------------------------------------------------------------------
    elif program == 'mayavi2':
        cmd = ["mayavi2", "-d", file_to_plot, "-m", "Surface", "&"]
        execute(cmd, 'os')
Exemple #15
0
def thickinthehead(segmented_file,
                   labeled_file,
                   cortex_value=2,
                   noncortex_value=3,
                   labels=[],
                   names=[],
                   resize=True,
                   propagate=True,
                   output_dir='',
                   save_table=False,
                   output_table=''):
    """
    Compute a simple thickness measure for each labeled cortex region volume.

    Note::

      - Cortex, noncortex, & label files are from the same coregistered brain.
      - Calls ANTs functions: ImageMath, Threshold, ResampleImageBySpacing
      - There may be slight discrepancies between volumes computed by
        thickinthehead() and volumes computed by volume_for_each_label();
        in 31 of 600+ ADNI 1.5T images, some volume_for_each_label() volumes
        were slightly larger (in the third decimal place), presumably due to
        label propagation through the cortex in thickinthehead().
        This is more pronounced in ANTs vs. FreeSurfer-labeled volumes.

    Example preprocessing steps ::

      1. Run Freesurfer and antsCorticalThickness.sh on T1-weighted image.
      2. Convert FreeSurfer volume labels (e.g., wmparc.mgz or aparc+aseg.mgz)
         to cortex (2) and noncortex (3) segments using relabel_volume()
         function [refer to LABELS.rst or FreeSurferColorLUT labels file].
      3. Convert ANTs Atropos-segmented volume (tmpBrainSegmentation.nii.gz)
         to cortex and noncortex segments, by converting 1-labels to 0 and
         4-labels to 3 with the relabel_volume() function
         (the latter is to include deep-gray matter with noncortical tissues).
      4. Combine FreeSurfer and ANTs segmentation volumes to obtain a single
         cortex (2) and noncortex (3) segmentation file using the function
         combine_2labels_in_2volumes(). This function takes the union of
         cortex voxels from the segmentations, the union of the noncortex
         voxels from the segmentations, and overwrites intersecting cortex
         and noncortex voxels with noncortex (3) labels.
         ANTs tends to include more cortical gray matter at the periphery of
         the brain than Freesurfer, and FreeSurfer tends to include more white
         matter that extends deep into gyral folds than ANTs, so the above
         attempts to remedy their differences by overlaying ANTs cortical gray
         with FreeSurfer white matter.
      5. Optional, see Step 2 below:
         Fill segmented cortex with cortex labels and noncortex with
         noncortex labels using the PropagateLabelsThroughMask() function
         (which calls ImageMath ... PropagateLabelsThroughMask in ANTs).
         The labels can be initialized using FreeSurfer (e.g. wmparc.mgz)
         or ANTs (by applying the nonlinear inverse transform generated by
         antsCorticalThickness.sh to labels in the Atropos template space).
         [Note: Any further labeling steps may be applied, such as
         overwriting cerebrum with intersecting cerebellum labels.]

    Steps ::

        1. Extract noncortex and cortex.
        2. Either mask labels with cortex or fill cortex with labels.
        3. Resample cortex and noncortex files from 1x1x1 to 0.5x0.5x0.5
           to better represent the contours of the boundaries of the cortex.
        4. Extract outer and inner boundary voxels of the cortex,
           by eroding 1 (resampled) voxel for cortex voxels (2) bordering
           the outside of the brain (0) and bordering noncortex (3).
        5. Estimate middle cortical surface area by the average volume
           of the outer and inner boundary voxels of the cortex.
        6. Compute the volume of a labeled region of cortex.
        7. Estimate the thickness of the labeled cortical region as the
           volume of the labeled region (#6) divided by the surface area (#5).

    Parameters
    ----------
    segmented_file : string
        image volume with cortex and noncortex (and any other) labels
    labeled_file : string
        corresponding image volume with index labels
    cortex_value : integer
        cortex label value in segmented_file
    noncortex_value : integer
        noncortex label value in segmented_file
    labels : list of integers
        label indices
    names : list of strings
        label names
    resize : Boolean
        resize (2x) segmented_file for more accurate thickness estimates?
    propagate : Boolean
        propagate labels through cortex?
    output_dir : string
        output directory
    save_table : Boolean
        save output table file with label volumes and thickness values?
    output_table : string
        name of output table file with label volumes and thickness values

    Returns
    -------
    label_volume_thickness : list of lists of integers and floats
        label indices, volumes, and thickness values (default -1)
    output_table : string
        name of output table file with label volumes and thickness values

    Examples
    --------
    >>> from mindboggle.shapes.volume_shapes import thickinthehead
    >>> segmented_file = '/Users/arno/Data/antsCorticalThickness/OASIS-TRT-20-1/antsBrainSegmentation.nii.gz'
    >>> labeled_file = '/appsdir/freesurfer/subjects/OASIS-TRT-20-1/mri/labels.DKT31.manual.nii.gz'
    >>> cortex_value = 2
    >>> noncortex_value = 3
    >>> #labels = [2]
    >>> labels = range(1002,1036) + range(2002,2036)
    >>> labels.remove(1004)
    >>> labels.remove(2004)
    >>> labels.remove(1032)
    >>> labels.remove(2032)
    >>> labels.remove(1033)
    >>> labels.remove(2033)
    >>> names = []
    >>> resize = True
    >>> propagate = False
    >>> output_dir = ''
    >>> save_table = True
    >>> output_table = ''
    >>> label_volume_thickness, output_table = thickinthehead(segmented_file, labeled_file, cortex_value, noncortex_value, labels, names, resize, propagate, output_dir, save_table, output_table)

    """
    import os
    import numpy as np
    import nibabel as nb

    from mindboggle.guts.utilities import execute

    #-------------------------------------------------------------------------
    # Output files:
    #-------------------------------------------------------------------------
    if output_dir:
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
    else:
        output_dir = os.getcwd()
    cortex = os.path.join(output_dir, 'cortex.nii.gz')
    noncortex = os.path.join(output_dir, 'noncortex.nii.gz')
    temp = os.path.join(output_dir, 'temp.nii.gz')
    inner_edge = os.path.join(output_dir, 'cortex_inner_edge.nii.gz')
    use_outer_edge = True
    if use_outer_edge:
        outer_edge = os.path.join(output_dir, 'cortex_outer_edge.nii.gz')

    if save_table:
        if output_table:
            output_table = os.path.join(os.getcwd(), output_table)
        else:
            output_table = os.path.join(os.getcwd(),
                                        'thickinthehead_for_each_label.csv')
        fid = open(output_table, 'w')
        if names:
            fid.write("name, ID, thickness (thickinthehead)\n")
        else:
            fid.write("ID, thickness (thickinthehead)\n")
    else:
        output_table = ''

    #-------------------------------------------------------------------------
    # Extract noncortex and cortex:
    #-------------------------------------------------------------------------
    cmd = [
        'ThresholdImage 3', segmented_file, noncortex,
        str(noncortex_value),
        str(noncortex_value), '1 0'
    ]
    execute(cmd)
    cmd = [
        'ThresholdImage 3', segmented_file, cortex,
        str(cortex_value),
        str(cortex_value), '1 0'
    ]
    execute(cmd)

    #-------------------------------------------------------------------------
    # Either mask labels with cortex or fill cortex with labels:
    #-------------------------------------------------------------------------
    if propagate:
        cmd = [
            'ImageMath', '3', cortex, 'PropagateLabelsThroughMask', cortex,
            labeled_file
        ]
        execute(cmd)
    else:
        cmd = ['ImageMath 3', cortex, 'm', cortex, labeled_file]
        execute(cmd)

    #-------------------------------------------------------------------------
    # Load data and dimensions:
    #-------------------------------------------------------------------------
    if resize:
        rescale = 2.0
    else:
        rescale = 1.0
    compute_real_volume = True
    if compute_real_volume:
        img = nb.load(cortex)
        hdr = img.get_header()
        vv_orig = np.prod(hdr.get_zooms())
        vv = np.prod([x / rescale for x in hdr.get_zooms()])
        cortex_data = img.get_data().ravel()
    else:
        vv = 1 / rescale
        cortex_data = nb.load(cortex).get_data().ravel()

    #-------------------------------------------------------------------------
    # Resample cortex and noncortex files from 1x1x1 to 0.5x0.5x0.5
    # to better represent the contours of the boundaries of the cortex:
    #-------------------------------------------------------------------------
    if resize:
        dims = ' '.join([str(1 / rescale), str(1 / rescale), str(1 / rescale)])
        cmd = ['ResampleImageBySpacing 3', cortex, cortex, dims, '0 0 1']
        execute(cmd)
        cmd = ['ResampleImageBySpacing 3', noncortex, noncortex, dims, '0 0 1']
        execute(cmd)

    #-------------------------------------------------------------------------
    # Extract outer and inner boundary voxels of the cortex,
    # by eroding 1 (resampled) voxel for cortex voxels (2) bordering
    # the outside of the brain (0) and bordering noncortex (3):
    #-------------------------------------------------------------------------
    cmd = ['ImageMath 3', inner_edge, 'MD', noncortex, '1']
    execute(cmd)
    cmd = ['ImageMath 3', inner_edge, 'm', cortex, inner_edge]
    execute(cmd)
    if use_outer_edge:
        cmd = ['ThresholdImage 3', cortex, outer_edge, '1 10000 1 0']
        execute(cmd)
        cmd = ['ImageMath 3', outer_edge, 'ME', outer_edge, '1']
        execute(cmd)
        cmd = ['ThresholdImage 3', outer_edge, outer_edge, '1 1 0 1']
        execute(cmd)
        cmd = ['ImageMath 3', outer_edge, 'm', cortex, outer_edge]
        execute(cmd)
        cmd = ['ThresholdImage 3', inner_edge, temp, '1 10000 1 0']
        execute(cmd)
        cmd = ['ThresholdImage 3', temp, temp, '1 1 0 1']
        execute(cmd)
        cmd = ['ImageMath 3', outer_edge, 'm', temp, outer_edge]
        execute(cmd)

    #-------------------------------------------------------------------------
    # Load data:
    #-------------------------------------------------------------------------
    inner_edge_data = nb.load(inner_edge).get_data().ravel()
    if use_outer_edge:
        outer_edge_data = nb.load(outer_edge).get_data().ravel()

    #-------------------------------------------------------------------------
    # Loop through labels:
    #-------------------------------------------------------------------------
    if not labels:
        labeled_data = nb.load(labeled_file).get_data().ravel()
        labels = np.unique(labeled_data)
    labels = [int(x) for x in labels]
    label_volume_thickness = -1 * np.ones((len(labels), 3))
    label_volume_thickness[:, 0] = labels
    for ilabel, label in enumerate(labels):
        if names:
            name = names[ilabel]

        #---------------------------------------------------------------------
        # Compute thickness as a ratio of label volume and edge volume:
        #   - Estimate middle cortical surface area by the average volume
        #     of the outer and inner boundary voxels of the cortex.
        #   - Compute the volume of a labeled region of cortex.
        #   - Estimate the thickness of the labeled cortical region as the
        #     volume of the labeled region divided by the surface area.
        #---------------------------------------------------------------------
        label_cortex_volume = vv_orig * len(np.where(cortex_data == label)[0])
        label_inner_edge_volume = vv * len(
            np.where(inner_edge_data == label)[0])
        if label_inner_edge_volume:
            if use_outer_edge:
                label_outer_edge_volume = \
                    vv * len(np.where(outer_edge_data==label)[0])
                label_area = (label_inner_edge_volume +
                              label_outer_edge_volume) / 2.0
            else:
                label_area = label_inner_edge_volume
            thickness = label_cortex_volume / label_area
            label_volume_thickness[ilabel, 1] = label_cortex_volume
            label_volume_thickness[ilabel, 2] = thickness

            #print('label {0} volume: cortex={1:2.2f}, inner={2:2.2f}, '
            #      'outer={3:2.2f}, area51={4:2.2f}, thickness={5:2.2f}mm'.
            #      format(name, label, label_cortex_volume, label_inner_edge_volume,
            #      label_outer_edge_volume, label_area, thickness))
            if names:
                print('{0} ({1}) thickness={2:2.2f}mm'.format(
                    name, label, thickness))
            else:
                print('{0}, thickness={1:2.2f}mm'.format(label, thickness))

            if save_table:
                if names:
                    fid.write('{0}, {1}, {2:2.3f}\n'.format(
                        name, label, thickness))
                else:
                    fid.write('{0}, {1:2.3f}\n'.format(label, thickness))

    label_volume_thickness = label_volume_thickness.transpose().tolist()

    return label_volume_thickness, output_table
def thickinthehead(segmented_file, labeled_file,
                   cortex_value=2, noncortex_value=3, labels=[], names=[],
                   propagate=False, output_dir='', save_table=False,
                   output_table='', verbose=False):
    """
    Compute a simple thickness measure for each labeled cortex region volume.

    Since Mindboggle accepts FreeSurfer data as input, we include FreeSurfer
    cortical thickness estimates with Mindboggle’s shape measures.
    However, surface mesh reconstruction from MRI data does not always
    produce favorable results. For example, we found that at least a quarter
    of the over one hundred EMBARC brain images we processed through
    FreeSurfer clipped ventral cortical regions, resulting in bad surface
    patches in those regions. For comparison, we built this function called
    thickinthehead which computes a simple thickness measure for each
    cortical region using a segmentation volume rather than surfaces.

    We have revised this algorithm from the original published version.
    We removed upsampling to reduce memory issues for large image volumes,
    and replaced the estimated volume of middle cortical layer
    with an estimate of its surface area. We made these revisions to be less
    susceptible to deviations in voxel size from isometric 1mm^3 voxels
    for which thickinthehead was originally built.

    Steps ::

        1. Extract noncortex and cortex into separate files.
        2. Either mask labels with cortex or fill cortex with labels.
        3. Extract outer and inner boundary voxels of the cortex,
           by morphologically eroding the cortex (=2) by one voxel bordering
           the outside of the brain (=0) and bordering the inside of the brain
           (non-cortex=3).
        4. Estimate middle cortical layer's surface area by the average
           surface area of the outer and inner boundary voxels of the cortex,
           where surface area is roughly estimated as the average face area
           of a voxel times the number of voxels.
        5. Compute the volume of a labeled region of cortex.
        6. Estimate the thickness of the labeled cortical region as the
           volume of the labeled region (#5) divided by the
           estimate of the middle cortical surface area of that region (#4).

    Note::

      - Cortex, noncortex, & label files are from the same coregistered brain.
      - Calls ANTs functions: ImageMath and Threshold
      - There may be slight discrepancies between volumes computed by
        thickinthehead() and volumes computed by volume_per_label();
        in 31 of 600+ ADNI 1.5T images, some volume_per_label() volumes
        were slightly larger (in the third decimal place), presumably due to
        label propagation through the cortex in thickinthehead().
        This is more pronounced in ANTs vs. FreeSurfer-labeled volumes.

    Parameters
    ----------
    segmented_file : string
        image volume with cortex and noncortex (and any other) labels
    labeled_file : string
        corresponding image volume with index labels
    cortex_value : integer
        cortex label value in segmented_file
    noncortex_value : integer
        noncortex label value in segmented_file
    labels : list of integers
        label indices
    names : list of strings
        label names
    propagate : bool
        propagate labels through cortex (or mask labels with cortex)?
    output_dir : string
        output directory
    save_table : bool
        save output table file with label volumes and thickness values?
    output_table : string
        name of output table file with label volumes and thickness values
    verbose : bool
        print statements?

    Returns
    -------
    label_volume_thickness : list of lists of integers and floats
        label indices, volumes, and thickness values (default -1)
    output_table : string
        name of output table file with label volumes and thickness values

    Examples
    --------
    >>> # Example simply using ants segmentation and labels vs. hybrid segmentation:
    >>> import os
    >>> import numpy as np
    >>> from mindboggle.shapes.volume_shapes import thickinthehead
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> segmented_file = fetch_data(urls['ants_segmentation'], '', '.nii.gz')
    >>> labeled_file = fetch_data(urls['ants_labels'], '', '.nii.gz')
    >>> cortex_value = 2
    >>> noncortex_value = 3
    >>> #labels = [2]
    >>> labels = list(range(1002,1036)) + list(range(2002,2036))
    >>> labels.remove(1004)
    >>> labels.remove(2004)
    >>> labels.remove(1032)
    >>> labels.remove(2032)
    >>> labels.remove(1033)
    >>> labels.remove(2033)
    >>> names = []
    >>> propagate = False
    >>> output_dir = ''
    >>> save_table = True
    >>> output_table = ''
    >>> verbose = False

    Skip online test because it requires installation of ANTs:

    >>> label_volume_thickness, output_table = thickinthehead(segmented_file,
    ...     labeled_file, cortex_value, noncortex_value, labels, names,
    ...     propagate, output_dir, save_table, output_table, verbose) # doctest: +SKIP
    >>> [np.int("{0:.{1}f}".format(x, 5)) label_volume_thickness[0][0:10]] # doctest: +SKIP
    >>> [np.float("{0:.{1}f}".format(x, 5)) for x in label_volume_thickness[1][0:5]] # doctest: +SKIP
    >>> [np.float("{0:.{1}f}".format(x, 5)) for x in label_volume_thickness[2][0:5]] # doctest: +SKIP

    """
    import os
    import numpy as np
    import nibabel as nb
    from io import open

    from mindboggle.guts.utilities import execute

    # ------------------------------------------------------------------------
    # Output files:
    # ------------------------------------------------------------------------
    if output_dir:
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
    else:
        output_dir = os.getcwd()
    cortex = os.path.join(output_dir, 'cortex.nii.gz')
    noncortex = os.path.join(output_dir, 'noncortex.nii.gz')
    temp = os.path.join(output_dir, 'temp.nii.gz')
    inner_edge = os.path.join(output_dir, 'cortex_inner_edge.nii.gz')
    use_outer_edge = True
    if use_outer_edge:
        outer_edge = os.path.join(output_dir, 'cortex_outer_edge.nii.gz')

    if save_table:
        if output_table:
            output_table = os.path.join(os.getcwd(), output_table)
        else:
            output_table = os.path.join(os.getcwd(),
                                        'thickinthehead_for_each_label.csv')
        fid = open(output_table, 'w')
        if names:
            fid.write("name, ID, thickness (thickinthehead)\n")
        else:
            fid.write("ID, thickness (thickinthehead)\n")
    else:
        output_table = ''

    # ------------------------------------------------------------------------
    # Extract noncortex and cortex:
    # ------------------------------------------------------------------------
    cmd = ['ThresholdImage', '3', segmented_file, noncortex,
           str(noncortex_value), str(noncortex_value), '1 0']
    execute(cmd, 'os')
    cmd = ['ThresholdImage', '3', segmented_file, cortex,
           str(cortex_value), str(cortex_value), '1 0']
    execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Either mask labels with cortex or fill cortex with labels:
    # ------------------------------------------------------------------------
    if propagate:
        cmd = ['ImageMath', '3', cortex, 'PropagateLabelsThroughMask',
               cortex, labeled_file]
        execute(cmd, 'os')
    else:
        cmd = ['ImageMath', '3', cortex, 'm', cortex, labeled_file]
        execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Load data and dimensions:
    # ------------------------------------------------------------------------
    img = nb.load(cortex)
    cortex_data = img.get_data().ravel()
    voxsize = img.header.get_zooms()
    voxvol = np.prod(voxsize)
    voxarea = (voxsize[0] * voxsize[1] + \
               voxsize[0] * voxsize[2] + \
               voxsize[1] * voxsize[2]) / 3

    # ------------------------------------------------------------------------
    # Extract outer and inner boundary voxels of the cortex,
    # by eroding 1 voxel for cortex voxels (=2) bordering
    # the outside of the brain (=0) and bordering noncortex (=3):
    # ------------------------------------------------------------------------
    cmd = ['ImageMath', '3', inner_edge, 'MD', noncortex, '1']
    execute(cmd, 'os')
    cmd = ['ImageMath', '3', inner_edge, 'm', cortex, inner_edge]
    execute(cmd, 'os')
    if use_outer_edge:
        cmd = ['ThresholdImage', '3', cortex, outer_edge, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = ['ImageMath', '3', outer_edge, 'ME', outer_edge, '1']
        execute(cmd, 'os')
        cmd = ['ThresholdImage', '3', outer_edge, outer_edge, '1 1 0 1']
        execute(cmd, 'os')
        cmd = ['ImageMath', '3', outer_edge, 'm', cortex, outer_edge]
        execute(cmd, 'os')
        cmd = ['ThresholdImage', '3', inner_edge, temp, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = ['ThresholdImage', '3', temp, temp, '1 1 0 1']
        execute(cmd, 'os')
        cmd = ['ImageMath', '3', outer_edge, 'm', temp, outer_edge]
        execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Load data:
    # ------------------------------------------------------------------------
    inner_edge_data = nb.load(inner_edge).get_data().ravel()
    if use_outer_edge:
        outer_edge_data = nb.load(outer_edge).get_data().ravel()

    # ------------------------------------------------------------------------
    # Loop through labels:
    # ------------------------------------------------------------------------
    if not labels:
        labeled_data = nb.load(labeled_file).get_data().ravel()
        labels = np.unique(labeled_data)
    labels = [int(x) for x in labels]
    label_volume_thickness = -1 * np.ones((len(labels), 3))
    label_volume_thickness[:, 0] = labels
    for ilabel, label in enumerate(labels):
        if names:
            name = names[ilabel]

        # --------------------------------------------------------------------
        # Compute thickness as a ratio of label volume and layer surface area:
        #   - Estimate middle cortical surface area by the average area
        #     of the outer and inner boundary voxels of the cortex.
        #   - Surface area is roughly estimated as the average face area
        #     of a voxel times the number of voxels.
        #   - Compute the volume of a labeled region of cortex.
        #   - Estimate the thickness of the labeled cortical region as the
        #     volume of the labeled region divided by the middle surface area.
        # --------------------------------------------------------------------
        label_cortex_volume = voxvol * len(np.where(cortex_data==label)[0])
        label_inner_edge_area = voxarea * \
                                  len(np.where(inner_edge_data==label)[0])
        if label_inner_edge_area:
            if use_outer_edge:
                label_outer_edge_area = \
                    voxarea * len(np.where(outer_edge_data==label)[0])
                label_area = (label_inner_edge_area +
                              label_outer_edge_area) / 2.0
            else:
                label_area = label_inner_edge_area
            thickness = label_cortex_volume / label_area
            label_volume_thickness[ilabel, 1] = label_cortex_volume
            label_volume_thickness[ilabel, 2] = thickness

            if save_table:
                if names:
                    if verbose:
                        print('{0} ({1}) thickinthehead thickness = '
                              '{2:2.2f}mm'.format(name, label, thickness))
                    fid.write('{0}, {1}, {2:2.3f}\n'.format(name, label,
                                                            thickness))
                else:
                    if verbose:
                        print('{0} thickinthehead thickness = {1:2.2f}mm'.
                              format(label, thickness))
                    fid.write('{0}, {1:2.3f}\n'.format(label, thickness))

    label_volume_thickness = label_volume_thickness.transpose().tolist()

    return label_volume_thickness, output_table
Exemple #17
0
def ImageMath(volume1, volume2, operator='m', output_file=''):
    """
    Use the ImageMath function in ANTs to perform operation on two volumes::

        m         : Multiply ---  use vm for vector multiply
        +         : Add ---  use v+ for vector add
        -         : Subtract ---  use v- for vector subtract
        /         : Divide
        ^         : Power
        exp       : Take exponent exp(imagevalue*value)
        addtozero : add image-b to image-a only over points where image-a has zero values
        overadd   : replace image-a pixel with image-b pixel if image-b pixel is non-zero
        abs       : absolute value
        total     : Sums up values in an image or in image1*image2 (img2 is the probability mask)
        mean      :  Average of values in an image or in image1*image2 (img2 is the probability mask)
        vtotal    : Sums up volumetrically weighted values in an image or in image1*image2 (img2 is the probability mask)
        Decision  : Computes result=1./(1.+exp(-1.0*( pix1-0.25)/pix2))
        Neg       : Produce image negative


    Parameters
    ----------
    volume1 : string
        nibabel-readable image volume
    volume2 : string
        nibabel-readable image volume
    operator : string
        ImageMath string corresponding to mathematical operator
    output_file : string
        nibabel-readable image volume

    Returns
    -------
    output_file : string
        name of output nibabel-readable image volume

    Examples
    --------
    >>> # Mask head with brain mask:
    >>> import os
    >>> from mindboggle.thirdparty.ants import ImageMath
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> volume1 = fetch_data(urls['T1_001'])
    >>> volume2 = fetch_data(urls['ants_mask'])
    >>> operator = 'm'
    >>> output_file = ''
    >>> output_file = ImageMath(volume1, volume2, operator, output_file) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   os.path.basename(volume1) + '_' +
                                   os.path.basename(volume2))
    cmd = ['ImageMath', '3', output_file, operator, volume1, volume2]
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError("ImageMath did not create " + output_file + ".")

    return output_file
Exemple #18
0
def antsApplyTransformsToPoints(points, transform_files, inverse_booleans=[0]):
    """
    Run ANTs antsApplyTransformsToPoints function to transform points.
    (Creates pre- and post-transformed .csv points files for ANTs.)

    Parameters
    ----------
    points : list of lists of three integers
        point coordinate data
    transform_files : list
        transform file names
    inverse_booleans : list
        for each transform, one to apply inverse of transform (otherwise zero)

    Returns
    -------
    transformed_points : list of lists of three integers
        transformed point coordinate data

    Examples
    --------
    >>> from mindboggle.thirdparty.ants import antsApplyTransformsToPoints
    >>> from mindboggle.mio.vtks import read_vtk
    >>> transform_files = ['/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsTemplateToSubject1GenericAffine.mat','/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsTemplateToSubject0Warp.nii.gz','/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsSubjectToTemplate0GenericAffine.mat','/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsSubjectToTemplate1Warp.nii.gz']
    >>> transform_files = [transform_files[0],transform_files[1],'/Users/arno/Data/mindboggle_cache/f36e3d5d99f7c4a9bb70e2494ed7340b/OASIS-30_Atropos_template_to_MNI152_affine.txt']
    >>> vtk_file = '/Users/arno/mindboggle_working/Twins-2-1/Mindboggle/_hemi_lh/Surface_to_vtk/lh.pial.vtk'
    >>> points, indices, lines, faces, scalars, scalar_names, npoints, input_vtk = read_vtk(vtk_file)
    >>> inverse_booleans = [0,0,1]
    >>> transformed_points = antsApplyTransformsToPoints(points, transform_files, inverse_booleans)

    """
    import os

    from mindboggle.guts.utilities import execute

    #-------------------------------------------------------------------------
    # Write points (x,y,z,1) to a .csv file:
    #-------------------------------------------------------------------------
    points_file = os.path.join(os.getcwd(), 'points.csv')
    fid = open(points_file, 'wa')
    fid.write('x,y,z,t\n')
    for point in points:
        string_of_zeros = (4 - len(point)) * ',0'
        fid.write(','.join([str(x) for x in point]) + string_of_zeros + '\n')
    fid.close()

    #-------------------------------------------------------------------------
    # Apply transforms to points in .csv file:
    #-------------------------------------------------------------------------
    transformed_points_file = os.path.join(os.getcwd(),
                                           'transformed_points.csv')
    transform_string = ''
    for ixfm, transform_file in enumerate(transform_files):
        transform_string += " --t [{0},{1}]".\
            format(transform_file, str(inverse_booleans[ixfm]))
    cmd = ['antsApplyTransformsToPoints', '-d', '3', '-i', points_file,
           '-o', transformed_points_file, transform_string]
    execute(cmd, 'os')
    if not os.path.exists(transformed_points_file):
        str1 = "antsApplyTransformsToPoints did not create "
        raise(IOError(str1 + transformed_points_file + "."))

    #-------------------------------------------------------------------------
    # Return transformed points:
    #-------------------------------------------------------------------------
    fid = open(transformed_points_file, 'r')
    lines = fid.readlines()
    fid.close()
    transformed_points = []
    for iline, line in enumerate(lines):
        if iline > 0:
            point_xyz1 = [float(x) for x in line.split(',')]
            transformed_points.append(point_xyz1[0:3])


    return transformed_points
Exemple #19
0
def PropagateLabelsThroughMask(mask, labels, mask_index=None,
                               output_file='', binarize=True, stopvalue=''):
    """
    Use ANTs to fill a binary volume mask with initial labels.

    This program uses ThresholdImage and the ImageMath
    PropagateLabelsThroughMask functions in ANTs.

    ThresholdImage ImageDimension ImageIn.ext outImage.ext
        threshlo threshhi <insideValue> <outsideValue>

    PropagateLabelsThroughMask: Final output is the propagated label image.
        ImageMath ImageDimension Out.ext PropagateLabelsThroughMask
        speed/binaryimagemask.nii.gz initiallabelimage.nii.gz ...

    Parameters
    ----------
    mask : string
        nibabel-readable image volume
    labels : string
        nibabel-readable image volume with integer labels
    mask_index : integer (optional)
        mask with just voxels having this value
    output_file : string
        nibabel-readable labeled image volume
    binarize : Boolean
        binarize mask?
    stopvalue : integer
        stopping value

    Returns
    -------
    output_file : string
        name of labeled output nibabel-readable image volume

    Examples
    --------
    >>> import os
    >>> from mindboggle.thirdparty.ants import PropagateLabelsThroughMask
    >>> from mindboggle.mio.plots import plot_volumes
    >>> path = os.path.join(os.environ['MINDBOGGLE_DATA'])
    >>> labels = os.path.join(path, 'arno', 'labels', 'labels.DKT25.manual.nii.gz')
    >>> mask = os.path.join(path, 'arno', 'mri', 't1weighted_brain.nii.gz')
    >>> mask_index = None
    >>> output_file = ''
    >>> binarize = True
    >>> stopvalue = None
    >>> output_file = PropagateLabelsThroughMask(mask, labels, mask_index, output_file, binarize, stopvalue)
    >>> # View
    >>> plot_volumes(output_file)

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        #output_file = os.path.join(os.getcwd(),
        #                           'PropagateLabelsThroughMask.nii.gz')
        output_file = os.path.join(os.getcwd(),
                                   os.path.basename(labels) + '_through_' +
                                   os.path.basename(mask))

    print('mask: {0}, labels: {1}'.format(mask, labels))

    # Binarize image volume:
    if binarize:
        temp_file = os.path.join(os.getcwd(),
                                 'PropagateLabelsThroughMask.nii.gz')
        cmd = ['ThresholdImage', '3', mask, temp_file, '0 1 0 1']
        execute(cmd, 'os')
        mask = temp_file

    # Mask with just voxels having mask_index value:
    if mask_index:
        mask2 = os.path.join(os.getcwd(), 'temp.nii.gz')
        cmd = 'ThresholdImage 3 {0} {1} {2} {3} 1 0'.format(mask, mask2,
               mask_index, mask_index)
        execute(cmd)
    else:
        mask2 = mask

    # Propagate labels:
    cmd = ['ImageMath', '3', output_file, 'PropagateLabelsThroughMask',
            mask2, labels]
    if stopvalue:
        cmd.extend(stopvalue)
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise(IOError("ImageMath did not create " + output_file + "."))

    return output_file
Exemple #20
0
def thickinthehead(segmented_file,
                   labeled_file,
                   cortex_value=2,
                   noncortex_value=3,
                   labels=[],
                   names=[],
                   resize=True,
                   propagate=True,
                   output_dir='',
                   save_table=False,
                   output_table='',
                   verbose=False):
    """
    Compute a simple thickness measure for each labeled cortex region volume.

    Since Mindboggle accepts FreeSurfer data as input, we include FreeSurfer
    cortical thickness estimates with Mindboggle’s shape measures.
    However, surface mesh reconstruction from MRI data does not always
    produce favorable results. For example, we found that at least a quarter
    of the over one hundred EMBARC brain images we processed through
    FreeSurfer clipped ventral cortical regions, resulting in bad surface
    patches in those regions. For comparison, we built a function called
    thickinthehead which computes a simple thickness measure for each
    cortical region using the hybrid segmentation volume rather than surfaces.

    The thickinthehead function first saves a brain volume that has been
    segmented into cortex and non-cortex voxels into separate binary files,
    then resamples these cortex and non-cortex files from, for example,
    1mm^3 to 0.5mm^3 voxel dimensions to better represent the contours
    of the cortex, then extracts outer and inner boundary voxels of the cortex
    by morphologically eroding the cortex by one (resampled) voxel bordering
    the outside of the brain and bordering the inside of the brain
    (non-cortex). Then it estimates the middle cortical surface area by the
    average volume of the outer and inner boundary voxels of the cortex.
    Finally, it estimates the thickness of a labeled cortical region as the
    volume of the labeled region divided by the surface area of that region.

    We compared thickinthehead and FreeSurfer cortical thickness estimates
    for 16 cortical regions in 40 EMBARC control subjects (unpublished
    results) with published estimates based on manual delineations of MR
    images (Kabani, 2001). Forty percent of FreeSurfer estimates for the 640
    labels were in the range of the published values, whereas almost ninety
    percent of thickinthehead’s estimates were within range. ANTs values
    deviated further from the published estimates and were less reliable
    (greater inter-subject ranges) than the FreeSurfer or thickinthehead
    values.

    Note::

      - Cortex, noncortex, & label files are from the same coregistered brain.
      - Calls ANTs functions: ImageMath, Threshold, ResampleImageBySpacing
      - There may be slight discrepancies between volumes computed by
        thickinthehead() and volumes computed by volume_per_label();
        in 31 of 600+ ADNI 1.5T images, some volume_per_label() volumes
        were slightly larger (in the third decimal place), presumably due to
        label propagation through the cortex in thickinthehead().
        This is more pronounced in ANTs vs. FreeSurfer-labeled volumes.

    Example preprocessing steps ::

      1. Run Freesurfer and antsCorticalThickness.sh on T1-weighted image.
      2. Convert FreeSurfer volume labels (e.g., wmparc.mgz or aparc+aseg.mgz)
         to cortex (2) and noncortex (3) segments using relabel_volume()
         function [refer to labels.rst or FreeSurferColorLUT labels file].
      3. Convert ANTs Atropos-segmented volume (tmpBrainSegmentation.nii.gz)
         to cortex and noncortex segments, by converting 1-labels to 0 and
         4-labels to 3 with the relabel_volume() function
         (the latter is to include deep-gray matter with noncortical tissues).
      4. Combine FreeSurfer and ANTs segmentation volumes to obtain a single
         cortex (2) and noncortex (3) segmentation file using the function
         combine_2labels_in_2volumes(). This function takes the union of
         cortex voxels from the segmentations, the union of the noncortex
         voxels from the segmentations, and overwrites intersecting cortex
         and noncortex voxels with noncortex (3) labels.
         ANTs tends to include more cortical gray matter at the periphery of
         the brain than Freesurfer, and FreeSurfer tends to include more white
         matter that extends deep into gyral folds than ANTs, so the above
         attempts to remedy their differences by overlaying ANTs cortical gray
         with FreeSurfer white matter.
      5. Optional, see Step 2 below:
         Fill segmented cortex with cortex labels and noncortex with
         noncortex labels using the PropagateLabelsThroughMask() function
         (which calls ImageMath ... PropagateLabelsThroughMask in ANTs).
         The labels can be initialized using FreeSurfer (e.g. wmparc.mgz)
         or ANTs (by applying the nonlinear inverse transform generated by
         antsCorticalThickness.sh to labels in the Atropos template space).
         [Note: Any further labeling steps may be applied, such as
         overwriting cerebrum with intersecting cerebellum labels.]

    Steps ::

        1. Extract noncortex and cortex.
        2. Either mask labels with cortex or fill cortex with labels.
        3. Resample cortex and noncortex files from 1x1x1 to 0.5x0.5x0.5
           to better represent the contours of the boundaries of the cortex.
        4. Extract outer and inner boundary voxels of the cortex,
           by eroding 1 (resampled) voxel for cortex voxels (2) bordering
           the outside of the brain (0) and bordering noncortex (3).
        5. Estimate middle cortical surface area by the average volume
           of the outer and inner boundary voxels of the cortex.
        6. Compute the volume of a labeled region of cortex.
        7. Estimate the thickness of the labeled cortical region as the
           volume of the labeled region (#6) divided by the surface area (#5).

    Parameters
    ----------
    segmented_file : string
        image volume with cortex and noncortex (and any other) labels
    labeled_file : string
        corresponding image volume with index labels
    cortex_value : integer
        cortex label value in segmented_file
    noncortex_value : integer
        noncortex label value in segmented_file
    labels : list of integers
        label indices
    names : list of strings
        label names
    resize : bool
        resize (2x) segmented_file for more accurate thickness estimates?
    propagate : bool
        propagate labels through cortex?
    output_dir : string
        output directory
    save_table : bool
        save output table file with label volumes and thickness values?
    output_table : string
        name of output table file with label volumes and thickness values
    verbose : bool
        print statements?

    Returns
    -------
    label_volume_thickness : list of lists of integers and floats
        label indices, volumes, and thickness values (default -1)
    output_table : string
        name of output table file with label volumes and thickness values

    Examples
    --------
    >>> # Example simply using ants segmentation and labels:
    >>> import os
    >>> import numpy as np
    >>> from mindboggle.shapes.volume_shapes import thickinthehead
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> segmented_file = fetch_data(urls['ants_segmentation'], '', '.nii.gz')
    >>> labeled_file = fetch_data(urls['ants_labels'], '', '.nii.gz')
    >>> cortex_value = 2
    >>> noncortex_value = 3
    >>> #labels = [2]
    >>> labels = list(range(1002,1036)) + list(range(2002,2036))
    >>> labels.remove(1004)
    >>> labels.remove(2004)
    >>> labels.remove(1032)
    >>> labels.remove(2032)
    >>> labels.remove(1033)
    >>> labels.remove(2033)
    >>> names = []
    >>> resize = True
    >>> propagate = False
    >>> output_dir = ''
    >>> save_table = True
    >>> output_table = ''
    >>> verbose = False

    Skip online test because it requires installation of ANTs:

    >>> label_volume_thickness, output_table = thickinthehead(segmented_file,
    ...     labeled_file, cortex_value, noncortex_value, labels, names,
    ...     resize, propagate, output_dir, save_table, output_table, verbose) # doctest: +SKIP
    >>> [np.int("{0:.{1}f}".format(x, 5)) label_volume_thickness[0][0:10]] # doctest: +SKIP
    [1002, 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011 1012]
    >>> [np.float("{0:.{1}f}".format(x, 5)) for x in label_volume_thickness[1][0:5]] # doctest: +SKIP
    [3136.99383, 7206.98582, 3257.99359, 1950.99616, 12458.97549]
    >>> [np.float("{0:.{1}f}".format(x, 5)) for x in label_volume_thickness[2][0:5]] # doctest: +SKIP
    [3.8639, 3.69637, 2.56334, 4.09336, 4.52592]

    """
    import os
    import numpy as np
    import nibabel as nb
    from io import open

    from mindboggle.guts.utilities import execute

    # ------------------------------------------------------------------------
    # Output files:
    # ------------------------------------------------------------------------
    if output_dir:
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
    else:
        output_dir = os.getcwd()
    cortex = os.path.join(output_dir, 'cortex.nii.gz')
    noncortex = os.path.join(output_dir, 'noncortex.nii.gz')
    temp = os.path.join(output_dir, 'temp.nii.gz')
    inner_edge = os.path.join(output_dir, 'cortex_inner_edge.nii.gz')
    use_outer_edge = True
    if use_outer_edge:
        outer_edge = os.path.join(output_dir, 'cortex_outer_edge.nii.gz')

    if save_table:
        if output_table:
            output_table = os.path.join(os.getcwd(), output_table)
        else:
            output_table = os.path.join(os.getcwd(),
                                        'thickinthehead_for_each_label.csv')
        fid = open(output_table, 'w')
        if names:
            fid.write("name, ID, thickness (thickinthehead)\n")
        else:
            fid.write("ID, thickness (thickinthehead)\n")
    else:
        output_table = ''

    # ------------------------------------------------------------------------
    # ants command paths:
    # ------------------------------------------------------------------------
    ants_thresh = 'ThresholdImage'
    ants_math = 'ImageMath'
    ants_resample = 'ResampleImageBySpacing'

    # ------------------------------------------------------------------------
    # Extract noncortex and cortex:
    # ------------------------------------------------------------------------
    cmd = [
        ants_thresh, '3', segmented_file, noncortex,
        str(noncortex_value),
        str(noncortex_value), '1 0'
    ]
    execute(cmd, 'os')
    cmd = [
        ants_thresh, '3', segmented_file, cortex,
        str(cortex_value),
        str(cortex_value), '1 0'
    ]
    execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Either mask labels with cortex or fill cortex with labels:
    # ------------------------------------------------------------------------
    if propagate:
        cmd = [
            ants_math, '3', cortex, 'PropagateLabelsThroughMask', cortex,
            labeled_file
        ]
        execute(cmd, 'os')
    else:
        cmd = [ants_math, '3', cortex, 'm', cortex, labeled_file]
        execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Load data and dimensions:
    # ------------------------------------------------------------------------
    if resize:
        rescale = 2.0
    else:
        rescale = 1.0
    compute_real_volume = True
    if compute_real_volume:
        img = nb.load(cortex)
        hdr = img.get_header()
        vv_orig = np.prod(hdr.get_zooms())
        vv = np.prod([x / rescale for x in hdr.get_zooms()])
        cortex_data = img.get_data().ravel()
    else:
        vv = 1 / rescale
        cortex_data = nb.load(cortex).get_data().ravel()

    # ------------------------------------------------------------------------
    # Resample cortex and noncortex files from 1x1x1 to 0.5x0.5x0.5
    # to better represent the contours of the boundaries of the cortex:
    # ------------------------------------------------------------------------
    if resize:
        dims = ' '.join([str(1 / rescale), str(1 / rescale), str(1 / rescale)])
        cmd = [ants_resample, '3', cortex, cortex, dims, '0 0 1']
        execute(cmd, 'os')
        cmd = [ants_resample, '3', noncortex, noncortex, dims, '0 0 1']
        execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Extract outer and inner boundary voxels of the cortex,
    # by eroding 1 (resampled) voxel for cortex voxels (2) bordering
    # the outside of the brain (0) and bordering noncortex (3):
    # ------------------------------------------------------------------------
    cmd = [ants_math, '3', inner_edge, 'MD', noncortex, '1']
    execute(cmd, 'os')
    cmd = [ants_math, '3', inner_edge, 'm', cortex, inner_edge]
    execute(cmd, 'os')
    if use_outer_edge:
        cmd = [ants_thresh, '3', cortex, outer_edge, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = [ants_math, '3', outer_edge, 'ME', outer_edge, '1']
        execute(cmd, 'os')
        cmd = [ants_thresh, '3', outer_edge, outer_edge, '1 1 0 1']
        execute(cmd, 'os')
        cmd = [ants_math, '3', outer_edge, 'm', cortex, outer_edge]
        execute(cmd, 'os')
        cmd = [ants_thresh, '3', inner_edge, temp, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = [ants_thresh, '3', temp, temp, '1 1 0 1']
        execute(cmd, 'os')
        cmd = [ants_math, '3', outer_edge, 'm', temp, outer_edge]
        execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Load data:
    # ------------------------------------------------------------------------
    inner_edge_data = nb.load(inner_edge).get_data().ravel()
    if use_outer_edge:
        outer_edge_data = nb.load(outer_edge).get_data().ravel()

    # ------------------------------------------------------------------------
    # Loop through labels:
    # ------------------------------------------------------------------------
    if not labels:
        labeled_data = nb.load(labeled_file).get_data().ravel()
        labels = np.unique(labeled_data)
    labels = [int(x) for x in labels]
    label_volume_thickness = -1 * np.ones((len(labels), 3))
    label_volume_thickness[:, 0] = labels
    for ilabel, label in enumerate(labels):
        if names:
            name = names[ilabel]

        # --------------------------------------------------------------------
        # Compute thickness as a ratio of label volume and edge volume:
        #   - Estimate middle cortical surface area by the average volume
        #     of the outer and inner boundary voxels of the cortex.
        #   - Compute the volume of a labeled region of cortex.
        #   - Estimate the thickness of the labeled cortical region as the
        #     volume of the labeled region divided by the surface area.
        # --------------------------------------------------------------------
        label_cortex_volume = vv_orig * len(np.where(cortex_data == label)[0])
        label_inner_edge_volume = vv * len(
            np.where(inner_edge_data == label)[0])
        if label_inner_edge_volume:
            if use_outer_edge:
                label_outer_edge_volume = \
                    vv * len(np.where(outer_edge_data==label)[0])
                label_area = (label_inner_edge_volume +
                              label_outer_edge_volume) / 2.0
            else:
                label_area = label_inner_edge_volume
            thickness = label_cortex_volume / label_area
            label_volume_thickness[ilabel, 1] = label_cortex_volume
            label_volume_thickness[ilabel, 2] = thickness

            if save_table:
                if names:
                    if verbose:
                        print('{0} ({1}) thickinthehead thickness = '
                              '{2:2.2f}mm'.format(name, label, thickness))
                    fid.write('{0}, {1}, {2:2.3f}\n'.format(
                        name, label, thickness))
                else:
                    if verbose:
                        print(
                            '{0} thickinthehead thickness = {1:2.2f}mm'.format(
                                label, thickness))
                    fid.write('{0}, {1:2.3f}\n'.format(label, thickness))

    label_volume_thickness = label_volume_thickness.transpose().tolist()

    return label_volume_thickness, output_table
Exemple #21
0
def plot_mask_surface(vtk_file,
                      mask_file='',
                      nonmask_value=-1,
                      masked_output='',
                      remove_nonmask=False,
                      program='vtkviewer',
                      use_colormap=False,
                      colormap_file='',
                      background_value=-1):
    """
    Use vtkviewer or mayavi2 to visualize VTK surface mesh data.

    If a mask_file is provided, a temporary masked file is saved,
    and it is this file that is viewed.

    If using vtkviewer, optionally provide colormap file
    or set $COLORMAP environment variable.

    Parameters
    ----------
    vtk_file : string
        name of VTK surface mesh file
    mask_file : string
        name of VTK surface mesh file to mask vtk_file vertices
    nonmask_value : integer
        nonmask (usually background) value
    masked_output : string
        temporary masked output file name
    remove_nonmask : bool
        remove vertices that are not in mask? (otherwise assign nonmask_value)
    program : string {'vtkviewer', 'mayavi2'}
        program to visualize VTK file
    use_colormap : bool
        use Paraview-style XML colormap file set by $COLORMAP env variable?
    colormap_file : string
        use colormap in given file if use_colormap==True?  if empty and
        use_colormap==True, use file set by $COLORMAP environment variable
    background_value : integer or float
        background value

    Examples
    --------
    >>> import os
    >>> from mindboggle.mio.plots import plot_mask_surface
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> vtk_file = fetch_data(urls['freesurfer_labels'], '', '.vtk')
    >>> os.rename(vtk_file, vtk_file + '.nii.gz')
    >>> vtk_file = vtk_file + '.nii.gz'
    >>> mask_file = ''
    >>> nonmask_value = 0 #-1
    >>> masked_output = ''
    >>> remove_nonmask = True
    >>> program = 'vtkviewer'
    >>> use_colormap = True
    >>> colormap_file = ''
    >>> background_value = -1
    >>> plot_mask_surface(vtk_file, mask_file, nonmask_value, masked_output,
    ...     remove_nonmask, program, use_colormap, colormap_file,
    ...     background_value) # doctest: +SKIP

    """
    import os
    import numpy as np

    from mindboggle.guts.mesh import keep_faces, reindex_faces_points
    from mindboggle.guts.utilities import execute
    from mindboggle.mio.plots import plot_surfaces
    from mindboggle.mio.vtks import read_scalars, rewrite_scalars, \
                                        read_vtk, write_vtk

    # ------------------------------------------------------------------------
    # Filter mesh with non-background values from a second (same-size) mesh:
    # ------------------------------------------------------------------------
    if mask_file:
        mask, name = read_scalars(mask_file, True, True)
        if not masked_output:
            masked_output = os.path.join(os.getcwd(), 'temp.vtk')
        file_to_plot = masked_output

        # --------------------------------------------------------------------
        # Remove nonmask-valued vertices:
        # --------------------------------------------------------------------
        if remove_nonmask:
            # ----------------------------------------------------------------
            # Load VTK files:
            # ----------------------------------------------------------------
            points, indices, lines, faces, scalars, scalar_names, npoints, \
                input_vtk = read_vtk(vtk_file, True, True)
            # ----------------------------------------------------------------
            # Find mask indices, remove nonmask faces, and reindex:
            # ----------------------------------------------------------------
            Imask = [i for i, x in enumerate(mask) if x != nonmask_value]
            mask_faces = keep_faces(faces, Imask)
            mask_faces, points, \
            original_indices = reindex_faces_points(mask_faces, points)
            # ----------------------------------------------------------------
            # Write VTK file with scalar values:
            # ----------------------------------------------------------------
            if np.ndim(scalars) == 1:
                scalar_type = type(scalars[0]).__name__
            elif np.ndim(scalars) == 2:
                scalar_type = type(scalars[0][0]).__name__
            else:
                print("Undefined scalar type!")
            write_vtk(file_to_plot,
                      points, [], [],
                      mask_faces,
                      scalars[original_indices].tolist(),
                      scalar_names,
                      scalar_type=scalar_type)
        else:
            scalars, name = read_scalars(vtk_file, True, True)
            scalars[mask == nonmask_value] = nonmask_value
            rewrite_scalars(vtk_file, file_to_plot, scalars, ['scalars'], [],
                            background_value)
    else:
        file_to_plot = vtk_file

    # ------------------------------------------------------------------------
    # Display with vtkviewer.py:
    # ------------------------------------------------------------------------
    if program == 'vtkviewer':
        plot_surfaces(file_to_plot,
                      use_colormap=use_colormap,
                      colormap_file=colormap_file)
    # ------------------------------------------------------------------------
    # Display with mayavi2:
    # ------------------------------------------------------------------------
    elif program == 'mayavi2':
        cmd = ["mayavi2", "-d", file_to_plot, "-m", "Surface", "&"]
        execute(cmd, 'os')
Exemple #22
0
def antsApplyTransformsToPoints(points, transform_files, inverse_booleans=[0]):
    """
    Run ANTs antsApplyTransformsToPoints function to transform points.
    (Creates pre- and post-transformed .csv points files for ANTs.)

    Parameters
    ----------
    points : list of lists of three integers
        point coordinate data
    transform_files : list
        transform file names
    inverse_booleans : list
        for each transform, one to apply inverse of transform (otherwise zero)

    Returns
    -------
    transformed_points : list of lists of three integers
        transformed point coordinate data

    Examples
    --------
    >>> from mindboggle.thirdparty.ants import antsApplyTransformsToPoints
    >>> from mindboggle.mio.vtks import read_vtk
    >>> transform_files = ['/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsTemplateToSubject1GenericAffine.mat','/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsTemplateToSubject0Warp.nii.gz','/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsSubjectToTemplate0GenericAffine.mat','/Users/arno/Data/antsCorticalThickness/Twins-2-1/antsSubjectToTemplate1Warp.nii.gz']
    >>> transform_files = [transform_files[0],transform_files[1],'/Users/arno/Data/mindboggle_cache/f36e3d5d99f7c4a9bb70e2494ed7340b/OASIS-30_Atropos_template_to_MNI152_affine.txt']
    >>> vtk_file = '/Users/arno/mindboggle_working/Twins-2-1/Mindboggle/_hemi_lh/Surface_to_vtk/lh.pial.vtk'
    >>> faces, lines, indices, points, npoints, scalars, name, foo1 = read_vtk(vtk_file)
    >>> inverse_booleans = [0,0,1]
    >>> transformed_points = antsApplyTransformsToPoints(points, transform_files, inverse_booleans)

    """
    import os

    from mindboggle.guts.utilities import execute

    #-------------------------------------------------------------------------
    # Write points (x,y,z,1) to a .csv file:
    #-------------------------------------------------------------------------
    points_file = os.path.join(os.getcwd(), 'points.csv')
    fid = open(points_file, 'wa')
    fid.write('x,y,z,t\n')
    for point in points:
        string_of_zeros = (4 - len(point)) * ',0'
        fid.write(','.join([str(x) for x in point]) + string_of_zeros + '\n')
    fid.close()

    #-------------------------------------------------------------------------
    # Apply transforms to points in .csv file:
    #-------------------------------------------------------------------------
    transformed_points_file = os.path.join(os.getcwd(),
                                           'transformed_points.csv')
    transform_string = ''
    for ixfm, transform_file in enumerate(transform_files):
        transform_string += " --t [{0},{1}]".\
            format(transform_file, str(inverse_booleans[ixfm]))
    cmd = [
        'antsApplyTransformsToPoints', '-d', '3', '-i', points_file, '-o',
        transformed_points_file, transform_string
    ]
    execute(cmd, 'os')
    if not os.path.exists(transformed_points_file):
        str1 = "antsApplyTransformsToPoints did not create "
        raise (IOError(str1 + transformed_points_file + "."))

    #-------------------------------------------------------------------------
    # Return transformed points:
    #-------------------------------------------------------------------------
    fid = open(transformed_points_file, 'r')
    lines = fid.readlines()
    fid.close()
    transformed_points = []
    for iline, line in enumerate(lines):
        if iline > 0:
            point_xyz1 = [float(x) for x in line.split(',')]
            transformed_points.append(point_xyz1[0:3])

    return transformed_points
def thickinthehead(segmented_file, labeled_file, cortex_value=2,
                   noncortex_value=3, labels=[], names=[], resize=True,
                   propagate=True, output_dir='', save_table=False,
                   output_table='', ants_path='', verbose=False):
    """
    Compute a simple thickness measure for each labeled cortex region volume.

    Note::

      - Cortex, noncortex, & label files are from the same coregistered brain.
      - Calls ANTs functions: ImageMath, Threshold, ResampleImageBySpacing
      - There may be slight discrepancies between volumes computed by
        thickinthehead() and volumes computed by volume_for_each_label();
        in 31 of 600+ ADNI 1.5T images, some volume_for_each_label() volumes
        were slightly larger (in the third decimal place), presumably due to
        label propagation through the cortex in thickinthehead().
        This is more pronounced in ANTs vs. FreeSurfer-labeled volumes.

    Example preprocessing steps ::

      1. Run Freesurfer and antsCorticalThickness.sh on T1-weighted image.
      2. Convert FreeSurfer volume labels (e.g., wmparc.mgz or aparc+aseg.mgz)
         to cortex (2) and noncortex (3) segments using relabel_volume()
         function [refer to LABELS.rst or FreeSurferColorLUT labels file].
      3. Convert ANTs Atropos-segmented volume (tmpBrainSegmentation.nii.gz)
         to cortex and noncortex segments, by converting 1-labels to 0 and
         4-labels to 3 with the relabel_volume() function
         (the latter is to include deep-gray matter with noncortical tissues).
      4. Combine FreeSurfer and ANTs segmentation volumes to obtain a single
         cortex (2) and noncortex (3) segmentation file using the function
         combine_2labels_in_2volumes(). This function takes the union of
         cortex voxels from the segmentations, the union of the noncortex
         voxels from the segmentations, and overwrites intersecting cortex
         and noncortex voxels with noncortex (3) labels.
         ANTs tends to include more cortical gray matter at the periphery of
         the brain than Freesurfer, and FreeSurfer tends to include more white
         matter that extends deep into gyral folds than ANTs, so the above
         attempts to remedy their differences by overlaying ANTs cortical gray
         with FreeSurfer white matter.
      5. Optional, see Step 2 below:
         Fill segmented cortex with cortex labels and noncortex with
         noncortex labels using the PropagateLabelsThroughMask() function
         (which calls ImageMath ... PropagateLabelsThroughMask in ANTs).
         The labels can be initialized using FreeSurfer (e.g. wmparc.mgz)
         or ANTs (by applying the nonlinear inverse transform generated by
         antsCorticalThickness.sh to labels in the Atropos template space).
         [Note: Any further labeling steps may be applied, such as
         overwriting cerebrum with intersecting cerebellum labels.]

    Steps ::

        1. Extract noncortex and cortex.
        2. Either mask labels with cortex or fill cortex with labels.
        3. Resample cortex and noncortex files from 1x1x1 to 0.5x0.5x0.5
           to better represent the contours of the boundaries of the cortex.
        4. Extract outer and inner boundary voxels of the cortex,
           by eroding 1 (resampled) voxel for cortex voxels (2) bordering
           the outside of the brain (0) and bordering noncortex (3).
        5. Estimate middle cortical surface area by the average volume
           of the outer and inner boundary voxels of the cortex.
        6. Compute the volume of a labeled region of cortex.
        7. Estimate the thickness of the labeled cortical region as the
           volume of the labeled region (#6) divided by the surface area (#5).

    Parameters
    ----------
    segmented_file : string
        image volume with cortex and noncortex (and any other) labels
    labeled_file : string
        corresponding image volume with index labels
    cortex_value : integer
        cortex label value in segmented_file
    noncortex_value : integer
        noncortex label value in segmented_file
    labels : list of integers
        label indices
    names : list of strings
        label names
    resize : bool
        resize (2x) segmented_file for more accurate thickness estimates?
    propagate : bool
        propagate labels through cortex?
    output_dir : string
        output directory
    save_table : bool
        save output table file with label volumes and thickness values?
    output_table : string
        name of output table file with label volumes and thickness values
    verbose : bool
        print statements?

    Returns
    -------
    label_volume_thickness : list of lists of integers and floats
        label indices, volumes, and thickness values (default -1)
    output_table : string
        name of output table file with label volumes and thickness values

    Examples
    --------
    >>> # Example simply using ants segmentation and labels:
    >>> import os
    >>> import numpy as np
    >>> from mindboggle.shapes.volume_shapes import thickinthehead
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> segmented_file = fetch_data(urls['ants_segmentation'])
    >>> labeled_file = fetch_data(urls['ants_labels'])
    >>> cortex_value = 2
    >>> noncortex_value = 3
    >>> #labels = [2]
    >>> labels = list(range(1002,1036)) + list(range(2002,2036))
    >>> labels.remove(1004)
    >>> labels.remove(2004)
    >>> labels.remove(1032)
    >>> labels.remove(2032)
    >>> labels.remove(1033)
    >>> labels.remove(2033)
    >>> names = []
    >>> resize = True
    >>> propagate = False
    >>> output_dir = ''
    >>> save_table = True
    >>> output_table = ''
    >>> verbose = False
    >>> label_volume_thickness, output_table = thickinthehead(segmented_file,
    ...     labeled_file, cortex_value, noncortex_value, labels, names,
    ...     resize, propagate, output_dir, save_table, output_table, verbose)
    >>> print(np.array_str(np.array(label_volume_thickness[0][0:10]),
    ...       precision=5, suppress_small=True))
    [ 1002.  1003.  1005.  1006.  1007.  1008.  1009.  1010.  1011.  1012.]
    >>> print(np.array_str(np.array(label_volume_thickness[1][0:5]),
    ...       precision=5, suppress_small=True))
    [  3136.99383   7206.98582   3257.99359   1950.99616  12458.97549]
    >>> print(np.array_str(np.array(label_volume_thickness[2][0:5]),
    ...       precision=5, suppress_small=True))
    [ 3.8639   3.69637  2.56334  4.09336  4.52592]

    """
    import os
    import numpy as np
    import nibabel as nb
    from io import open

    from mindboggle.guts.utilities import execute

    #-------------------------------------------------------------------------
    # Output files:
    #-------------------------------------------------------------------------
    if output_dir:
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
    else:
        output_dir = os.getcwd()
    cortex = os.path.join(output_dir, 'cortex.nii.gz')
    noncortex = os.path.join(output_dir, 'noncortex.nii.gz')
    temp = os.path.join(output_dir, 'temp.nii.gz')
    inner_edge = os.path.join(output_dir, 'cortex_inner_edge.nii.gz')
    use_outer_edge = True
    if use_outer_edge:
        outer_edge = os.path.join(output_dir, 'cortex_outer_edge.nii.gz')

    if save_table:
        if output_table:
            output_table = os.path.join(os.getcwd(), output_table)
        else:
            output_table = os.path.join(os.getcwd(),
                                        'thickinthehead_for_each_label.csv')
        fid = open(output_table, 'w')
        if names:
            fid.write("name, ID, thickness (thickinthehead)\n")
        else:
            fid.write("ID, thickness (thickinthehead)\n")
    else:
        output_table = ''

    #-------------------------------------------------------------------------
    # ants command paths:
    #-------------------------------------------------------------------------
    ants_thresh = 'ThresholdImage'
    ants_math = 'ImageMath'
    ants_resample = 'ResampleImageBySpacing'

    #-------------------------------------------------------------------------
    # Extract noncortex and cortex:
    #-------------------------------------------------------------------------
    cmd = [ants_thresh, '3', segmented_file, noncortex,
           str(noncortex_value), str(noncortex_value), '1 0']
    execute(cmd, 'os')
    cmd = [ants_thresh, '3', segmented_file, cortex,
           str(cortex_value), str(cortex_value), '1 0']
    execute(cmd, 'os')

    #-------------------------------------------------------------------------
    # Either mask labels with cortex or fill cortex with labels:
    #-------------------------------------------------------------------------
    if propagate:
        cmd = [ants_math, '3', cortex, 'PropagateLabelsThroughMask',
               cortex, labeled_file]
        execute(cmd, 'os')
    else:
        cmd = [ants_math, '3', cortex, 'm', cortex, labeled_file]
        execute(cmd, 'os')

    #-------------------------------------------------------------------------
    # Load data and dimensions:
    #-------------------------------------------------------------------------
    if resize:
        rescale = 2.0
    else:
        rescale = 1.0
    compute_real_volume = True
    if compute_real_volume:
        img = nb.load(cortex)
        hdr = img.get_header()
        vv_orig = np.prod(hdr.get_zooms())
        vv = np.prod([x/rescale for x in hdr.get_zooms()])
        cortex_data = img.get_data().ravel()
    else:
        vv = 1/rescale
        cortex_data = nb.load(cortex).get_data().ravel()

    #-------------------------------------------------------------------------
    # Resample cortex and noncortex files from 1x1x1 to 0.5x0.5x0.5
    # to better represent the contours of the boundaries of the cortex:
    #-------------------------------------------------------------------------
    if resize:
        dims = ' '.join([str(1/rescale), str(1/rescale), str(1/rescale)])
        cmd = [ants_resample, '3', cortex, cortex, dims, '0 0 1']
        execute(cmd, 'os')
        cmd = [ants_resample, '3', noncortex, noncortex, dims, '0 0 1']
        execute(cmd, 'os')

    #-------------------------------------------------------------------------
    # Extract outer and inner boundary voxels of the cortex,
    # by eroding 1 (resampled) voxel for cortex voxels (2) bordering
    # the outside of the brain (0) and bordering noncortex (3):
    #-------------------------------------------------------------------------
    cmd = [ants_math, '3', inner_edge, 'MD', noncortex, '1']
    execute(cmd, 'os')
    cmd = [ants_math, '3', inner_edge, 'm', cortex, inner_edge]
    execute(cmd, 'os')
    if use_outer_edge:
        cmd = [ants_thresh, '3', cortex, outer_edge, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = [ants_math, '3', outer_edge, 'ME', outer_edge, '1']
        execute(cmd, 'os')
        cmd = [ants_thresh, '3', outer_edge, outer_edge, '1 1 0 1']
        execute(cmd, 'os')
        cmd = [ants_math, '3', outer_edge, 'm', cortex, outer_edge]
        execute(cmd, 'os')
        cmd = [ants_thresh, '3', inner_edge, temp, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = [ants_thresh, '3', temp, temp, '1 1 0 1']
        execute(cmd, 'os')
        cmd = [ants_math, '3', outer_edge, 'm', temp, outer_edge]
        execute(cmd, 'os')

    #-------------------------------------------------------------------------
    # Load data:
    #-------------------------------------------------------------------------
    inner_edge_data = nb.load(inner_edge).get_data().ravel()
    if use_outer_edge:
        outer_edge_data = nb.load(outer_edge).get_data().ravel()

    #-------------------------------------------------------------------------
    # Loop through labels:
    #-------------------------------------------------------------------------
    if not labels:
        labeled_data = nb.load(labeled_file).get_data().ravel()
        labels = np.unique(labeled_data)
    labels = [int(x) for x in labels]
    label_volume_thickness = -1 * np.ones((len(labels), 3))
    label_volume_thickness[:, 0] = labels
    for ilabel, label in enumerate(labels):
        if names:
            name = names[ilabel]

        #---------------------------------------------------------------------
        # Compute thickness as a ratio of label volume and edge volume:
        #   - Estimate middle cortical surface area by the average volume
        #     of the outer and inner boundary voxels of the cortex.
        #   - Compute the volume of a labeled region of cortex.
        #   - Estimate the thickness of the labeled cortical region as the
        #     volume of the labeled region divided by the surface area.
        #---------------------------------------------------------------------
        label_cortex_volume = vv_orig * len(np.where(cortex_data==label)[0])
        label_inner_edge_volume = vv * len(np.where(inner_edge_data==label)[0])
        if label_inner_edge_volume:
            if use_outer_edge:
                label_outer_edge_volume = \
                    vv * len(np.where(outer_edge_data==label)[0])
                label_area = (label_inner_edge_volume +
                              label_outer_edge_volume) / 2.0
            else:
                label_area = label_inner_edge_volume
            thickness = label_cortex_volume / label_area
            label_volume_thickness[ilabel, 1] = label_cortex_volume
            label_volume_thickness[ilabel, 2] = thickness

            if save_table:
                if names:
                    if verbose:
                        print('{0} ({1}) thickinthehead thickness = '
                              '{2:2.2f}mm'.format(name, label, thickness))
                    fid.write('{0}, {1}, {2:2.3f}\n'.format(name, label,
                                                            thickness))
                else:
                    if verbose:
                        print('{0} thickinthehead thickness = {1:2.2f}mm'.
                              format(label, thickness))
                    fid.write('{0}, {1:2.3f}\n'.format(label, thickness))

    label_volume_thickness = label_volume_thickness.transpose().tolist()

    return label_volume_thickness, output_table
Exemple #24
0
def antsApplyTransformsToPoints(points, transform_files,
                                inverse_booleans=[0]):
    """
    Run ANTs antsApplyTransformsToPoints function to transform points.
    (Creates pre- and post-transformed .csv points files for ANTs.)

    Parameters
    ----------
    points : list of lists of three integers
        point coordinate data
    transform_files : list
        transform file names
    inverse_booleans : list
        for each transform, one to apply inverse of transform (otherwise zero)

    Returns
    -------
    transformed_points : list of lists of three integers
        transformed point coordinate data

    Examples
    --------
    >>> import os
    >>> import numpy as np
    >>> from mindboggle.thirdparty.ants import antsApplyTransformsToPoints
    >>> from mindboggle.mio.vtks import read_points
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> xfm1 = fetch_data(urls['ants_affine_template2subject'])
    >>> xfm2 = fetch_data(urls['ants_warp_template2subject'])
    >>> xfm3 = fetch_data(urls['OASIS-30_Atropos_template_to_MNI152_affine'])
    >>> transform_files = [xfm1, xfm2, xfm3]
    >>> vtk_file = fetch_data(urls['left_pial'])
    >>> points  = read_points(vtk_file)
    >>> inverse_booleans = [0,0,1]
    >>> transformed_points = antsApplyTransformsToPoints(points,
    ...     transform_files, inverse_booleans) # doctest: +SKIP
    >>> print(np.array_str(np.array(transformed_points[0:5]),
    ...       precision=5, suppress_small=True)) # doctest: +SKIP
    [[-11.23189 -46.78223 -39.88869]
     [-11.71384 -46.87075 -40.13328]
     [-12.56237 -46.99126 -40.04564]
     [ -9.66693 -46.0446  -41.36334]
     [-10.67998 -46.45458 -40.7572 ]]

    """
    import os
    from io import open

    from mindboggle.guts.utilities import execute

    #-------------------------------------------------------------------------
    # Write points (x,y,z,1) to a .csv file:
    #-------------------------------------------------------------------------
    points_file = os.path.join(os.getcwd(), 'points.csv')
    fid = open(points_file, 'wa')
    fid.write('x,y,z,t\n')
    for point in points:
        string_of_zeros = (4 - len(point)) * ',0'
        fid.write(','.join([str(x) for x in point]) + string_of_zeros + '\n')
    fid.close()

    #-------------------------------------------------------------------------
    # Apply transforms to points in .csv file:
    #-------------------------------------------------------------------------
    transformed_points_file = os.path.join(os.getcwd(),
                                           'transformed_points.csv')
    transform_string = ''
    for ixfm, transform_file in enumerate(transform_files):
        transform_string += " --t [{0},{1}]".\
            format(transform_file, str(inverse_booleans[ixfm]))
    cmd = ['antsApplyTransformsToPoints', '-d', '3', '-i', points_file,
           '-o', transformed_points_file, transform_string]
    try:
        execute(cmd, 'os')
    except:
        raise Exception("Cannot find antsApplyTransformsToPoints command.")

    if not os.path.exists(transformed_points_file):
        raise IOError("antsApplyTransformsToPoints did not create {0}.".
                      format(transformed_points_file))

    #-------------------------------------------------------------------------
    # Return transformed points:
    #-------------------------------------------------------------------------
    fid = open(transformed_points_file, 'rb')
    lines = fid.readlines()
    fid.close()
    transformed_points = []
    for iline, line in enumerate(lines):
        if iline > 0:
            point_xyz1 = [float(x) for x in line.split(',')]
            transformed_points.append(point_xyz1[0:3])

    return transformed_points
Exemple #25
0
def thickinthehead(segmented_file, labeled_file,
                   cortex_value=2, noncortex_value=3, labels=[], names=[],
                   propagate=False, output_dir='', save_table=False,
                   output_table='', verbose=False):
    """
    Compute a simple thickness measure for each labeled cortex region volume.

    Since Mindboggle accepts FreeSurfer data as input, we include FreeSurfer
    cortical thickness estimates with Mindboggle’s shape measures.
    However, surface mesh reconstruction from MRI data does not always
    produce favorable results. For example, we found that at least a quarter
    of the over one hundred EMBARC brain images we processed through
    FreeSurfer clipped ventral cortical regions, resulting in bad surface
    patches in those regions. For comparison, we built this function called
    thickinthehead which computes a simple thickness measure for each
    cortical region using a segmentation volume rather than surfaces.

    We have revised this algorithm from the original published version.
    We removed upsampling to reduce memory issues for large image volumes,
    and replaced the estimated volume of middle cortical layer
    with an estimate of its surface area. We made these revisions to be less
    susceptible to deviations in voxel size from isometric 1mm^3 voxels
    for which thickinthehead was originally built.

    Steps ::

        1. Extract noncortex and cortex into separate files.
        2. Either mask labels with cortex or fill cortex with labels.
        3. Extract outer and inner boundary voxels of the cortex,
           by morphologically eroding the cortex (=2) by one voxel bordering
           the outside of the brain (=0) and bordering the inside of the brain
           (non-cortex=3).
        4. Estimate middle cortical layer's surface area by the average
           surface area of the outer and inner boundary voxels of the cortex,
           where surface area is roughly estimated as the average face area
           of a voxel times the number of voxels.
        5. Compute the volume of a labeled region of cortex.
        6. Estimate the thickness of the labeled cortical region as the
           volume of the labeled region (#5) divided by the
           estimate of the middle cortical surface area of that region (#4).

    Note::

      - Cortex, noncortex, & label files are from the same coregistered brain.
      - Calls ANTs functions: ImageMath and Threshold
      - There may be slight discrepancies between volumes computed by
        thickinthehead() and volumes computed by volume_per_label();
        in 31 of 600+ ADNI 1.5T images, some volume_per_label() volumes
        were slightly larger (in the third decimal place), presumably due to
        label propagation through the cortex in thickinthehead().
        This is more pronounced in ANTs vs. FreeSurfer-labeled volumes.

    Parameters
    ----------
    segmented_file : string
        image volume with cortex and noncortex (and any other) labels
    labeled_file : string
        corresponding image volume with index labels
    cortex_value : integer
        cortex label value in segmented_file
    noncortex_value : integer
        noncortex label value in segmented_file
    labels : list of integers
        label indices
    names : list of strings
        label names
    propagate : bool
        propagate labels through cortex (or mask labels with cortex)?
    output_dir : string
        output directory
    save_table : bool
        save output table file with label volumes and thickness values?
    output_table : string
        name of output table file with label volumes and thickness values
    verbose : bool
        print statements?

    Returns
    -------
    label_volume_thickness : list of lists of integers and floats
        label indices, volumes, and thickness values (default -1)
    output_table : string
        name of output table file with label volumes and thickness values

    Examples
    --------
    >>> # Example simply using ants segmentation and labels vs. hybrid segmentation:
    >>> import os
    >>> import numpy as np
    >>> from mindboggle.shapes.volume_shapes import thickinthehead
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> segmented_file = fetch_data(urls['ants_segmentation'], '', '.nii.gz')
    >>> labeled_file = fetch_data(urls['ants_labels'], '', '.nii.gz')
    >>> cortex_value = 2
    >>> noncortex_value = 3
    >>> #labels = [2]
    >>> labels = list(range(1002,1036)) + list(range(2002,2036))
    >>> labels.remove(1004)
    >>> labels.remove(2004)
    >>> labels.remove(1032)
    >>> labels.remove(2032)
    >>> labels.remove(1033)
    >>> labels.remove(2033)
    >>> names = []
    >>> propagate = False
    >>> output_dir = ''
    >>> save_table = True
    >>> output_table = ''
    >>> verbose = False

    Skip online test because it requires installation of ANTs:

    >>> label_volume_thickness, output_table = thickinthehead(segmented_file,
    ...     labeled_file, cortex_value, noncortex_value, labels, names,
    ...     propagate, output_dir, save_table, output_table, verbose) # doctest: +SKIP
    >>> [np.int("{0:.{1}f}".format(x, 5)) label_volume_thickness[0][0:10]] # doctest: +SKIP
    >>> [np.float("{0:.{1}f}".format(x, 5)) for x in label_volume_thickness[1][0:5]] # doctest: +SKIP
    >>> [np.float("{0:.{1}f}".format(x, 5)) for x in label_volume_thickness[2][0:5]] # doctest: +SKIP

    """
    import os
    import numpy as np
    import nibabel as nb
    from io import open

    from mindboggle.guts.utilities import execute

    # ------------------------------------------------------------------------
    # Output files:
    # ------------------------------------------------------------------------
    if output_dir:
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
    else:
        output_dir = os.getcwd()
    cortex = os.path.join(output_dir, 'cortex.nii.gz')
    noncortex = os.path.join(output_dir, 'noncortex.nii.gz')
    temp = os.path.join(output_dir, 'temp.nii.gz')
    inner_edge = os.path.join(output_dir, 'cortex_inner_edge.nii.gz')
    use_outer_edge = True
    if use_outer_edge:
        outer_edge = os.path.join(output_dir, 'cortex_outer_edge.nii.gz')

    if save_table:
        if output_table:
            output_table = os.path.join(os.getcwd(), output_table)
        else:
            output_table = os.path.join(os.getcwd(),
                                        'thickinthehead_for_each_label.csv')
        fid = open(output_table, 'w', encoding='utf-8')
        if names:
            fid.write("name, ID, thickness (thickinthehead)\n")
        else:
            fid.write("ID, thickness (thickinthehead)\n")
    else:
        output_table = ''

    # ------------------------------------------------------------------------
    # Extract noncortex and cortex:
    # ------------------------------------------------------------------------
    cmd = ['ThresholdImage', '3', segmented_file, noncortex,
           str(noncortex_value), str(noncortex_value), '1 0']
    execute(cmd, 'os')
    cmd = ['ThresholdImage', '3', segmented_file, cortex,
           str(cortex_value), str(cortex_value), '1 0']
    execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Either mask labels with cortex or fill cortex with labels:
    # ------------------------------------------------------------------------
    if propagate:
        cmd = ['ImageMath', '3', cortex, 'PropagateLabelsThroughMask',
               cortex, labeled_file]
        execute(cmd, 'os')
    else:
        cmd = ['ImageMath', '3', cortex, 'm', cortex, labeled_file]
        execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Load data and dimensions:
    # ------------------------------------------------------------------------
    img = nb.load(cortex)
    cortex_data = img.get_data().ravel()
    voxsize = img.header.get_zooms()
    voxvol = np.prod(voxsize)
    voxarea = (voxsize[0] * voxsize[1] + \
               voxsize[0] * voxsize[2] + \
               voxsize[1] * voxsize[2]) / 3

    # ------------------------------------------------------------------------
    # Extract outer and inner boundary voxels of the cortex,
    # by eroding 1 voxel for cortex voxels (=2) bordering
    # the outside of the brain (=0) and bordering noncortex (=3):
    # ------------------------------------------------------------------------
    cmd = ['ImageMath', '3', inner_edge, 'MD', noncortex, '1']
    execute(cmd, 'os')
    cmd = ['ImageMath', '3', inner_edge, 'm', cortex, inner_edge]
    execute(cmd, 'os')
    if use_outer_edge:
        cmd = ['ThresholdImage', '3', cortex, outer_edge, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = ['ImageMath', '3', outer_edge, 'ME', outer_edge, '1']
        execute(cmd, 'os')
        cmd = ['ThresholdImage', '3', outer_edge, outer_edge, '1 1 0 1']
        execute(cmd, 'os')
        cmd = ['ImageMath', '3', outer_edge, 'm', cortex, outer_edge]
        execute(cmd, 'os')
        cmd = ['ThresholdImage', '3', inner_edge, temp, '1 10000 1 0']
        execute(cmd, 'os')
        cmd = ['ThresholdImage', '3', temp, temp, '1 1 0 1']
        execute(cmd, 'os')
        cmd = ['ImageMath', '3', outer_edge, 'm', temp, outer_edge]
        execute(cmd, 'os')

    # ------------------------------------------------------------------------
    # Load data:
    # ------------------------------------------------------------------------
    inner_edge_data = nb.load(inner_edge).get_data().ravel()
    if use_outer_edge:
        outer_edge_data = nb.load(outer_edge).get_data().ravel()

    # ------------------------------------------------------------------------
    # Loop through labels:
    # ------------------------------------------------------------------------
    if not labels:
        labeled_data = nb.load(labeled_file).get_data().ravel()
        labels = np.unique(labeled_data)
    labels = [int(x) for x in labels]
    label_volume_thickness = -1 * np.ones((len(labels), 3))
    label_volume_thickness[:, 0] = labels
    for ilabel, label in enumerate(labels):
        if names:
            name = names[ilabel]

        # --------------------------------------------------------------------
        # Compute thickness as a ratio of label volume and layer surface area:
        #   - Estimate middle cortical surface area by the average area
        #     of the outer and inner boundary voxels of the cortex.
        #   - Surface area is roughly estimated as the average face area
        #     of a voxel times the number of voxels.
        #   - Compute the volume of a labeled region of cortex.
        #   - Estimate the thickness of the labeled cortical region as the
        #     volume of the labeled region divided by the middle surface area.
        # --------------------------------------------------------------------
        label_cortex_volume = voxvol * len(np.where(cortex_data==label)[0])
        label_inner_edge_area = voxarea * \
                                  len(np.where(inner_edge_data==label)[0])
        if label_inner_edge_area:
            if use_outer_edge:
                label_outer_edge_area = \
                    voxarea * len(np.where(outer_edge_data==label)[0])
                label_area = (label_inner_edge_area +
                              label_outer_edge_area) / 2.0
            else:
                label_area = label_inner_edge_area
            thickness = label_cortex_volume / label_area
            label_volume_thickness[ilabel, 1] = label_cortex_volume
            label_volume_thickness[ilabel, 2] = thickness

            if save_table:
                if names:
                    if verbose:
                        print('{0} ({1}) thickinthehead thickness = '
                              '{2:2.2f}mm'.format(name, label, thickness))
                    fid.write('{0}, {1}, {2:2.3f}\n'.format(name, label,
                                                            thickness))
                else:
                    if verbose:
                        print('{0} thickinthehead thickness = {1:2.2f}mm'.
                              format(label, thickness))
                    fid.write('{0}, {1:2.3f}\n'.format(label, thickness))

    label_volume_thickness = label_volume_thickness.transpose().tolist()

    return label_volume_thickness, output_table
Exemple #26
0
def PropagateLabelsThroughMask(mask, labels, mask_index=None, output_file='',
                               binarize=True, stopvalue=''):
    """
    Use ANTs to fill a binary volume mask with initial labels.

    This program uses ThresholdImage and the ImageMath
    PropagateLabelsThroughMask functions in ANTs.

    ThresholdImage ImageDimension ImageIn.ext outImage.ext
        threshlo threshhi <insideValue> <outsideValue>

    PropagateLabelsThroughMask: Final output is the propagated label image.
        ImageMath ImageDimension Out.ext PropagateLabelsThroughMask
        speed/binaryimagemask.nii.gz initiallabelimage.nii.gz ...

    Parameters
    ----------
    mask : string
        nibabel-readable image volume
    labels : string
        nibabel-readable image volume with integer labels
    mask_index : integer (optional)
        mask with just voxels having this value
    output_file : string (optional)
        nibabel-readable labeled image volume
    binarize : bool (optional)
        binarize mask?
    stopvalue : integer (optional)
        stopping value

    Returns
    -------
    output_file : string
        name of labeled output nibabel-readable image volume

    Examples
    --------
    >>> # Propagate FreeSurfer labels through brain mask:
    >>> import os
    >>> from mindboggle.thirdparty.ants import PropagateLabelsThroughMask
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> labels = fetch_data(urls['freesurfer_labels'])
    >>> mask = fetch_data(urls['ants_mask'])
    >>> mask_index = None
    >>> output_file = ''
    >>> binarize = True
    >>> stopvalue = None
    >>> output_file = PropagateLabelsThroughMask(mask, labels, mask_index,
    ...     output_file, binarize, stopvalue) # doctest: +SKIP

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_volumes
    >>> plot_volumes(output_file) # doctest: +SKIP

    """
    import os
    from mindboggle.guts.utilities import execute

    if not output_file:
        #output_file = os.path.join(os.getcwd(),
        #                           'PropagateLabelsThroughMask.nii.gz')
        output_file = os.path.join(os.getcwd(),
                                   os.path.basename(labels) + '_through_' +
                                   os.path.basename(mask))

    print('mask: {0}, labels: {1}'.format(mask, labels))

    # Binarize image volume:
    if binarize:
        temp_file = os.path.join(os.getcwd(),
                                 'PropagateLabelsThroughMask.nii.gz')
        cmd = ['ThresholdImage', '3', mask, temp_file, '0 1 0 1']
        execute(cmd, 'os')
        mask = temp_file

    # Mask with just voxels having mask_index value:
    if mask_index:
        mask2 = os.path.join(os.getcwd(), 'temp.nii.gz')

        cmd = ['ThresholdImage', '3', mask, mask2,
               str(mask_index), str(mask_index)]
        execute(cmd, 'os')
    else:
        mask2 = mask

    # Propagate labels:

    cmd = ['ImageMath', '3', output_file, 'PropagateLabelsThroughMask',
           mask2, labels]
    if stopvalue:
        cmd.extend(str(stopvalue))
    execute(cmd, 'os')
    if not os.path.exists(output_file):
        raise IOError("ImageMath did not create " + output_file + ".")

    return output_file