Beispiel #1
0
def streamlines_in_mask(sft, target_mask, all_in=False):
    """
    Parameters
    ----------
    sft : StatefulTractogram
        StatefulTractogram containing the streamlines to segment.
    target_mask : numpy.ndarray
        Binary mask in which the streamlines should pass.
    Returns
    -------
    ids : list
        Ids of the streamlines passing through the mask.
    """
    sft.to_vox()
    sft.to_corner()
    # Copy-Paste from Dipy to get indices
    if all_in:
        target_mask = np.array(target_mask, dtype=bool, copy=True)
        target_mask = np.invert(target_mask)
        tractogram_mask = compute_tract_counts_map(sft.streamlines,
                                                   target_mask.shape)
        tractogram_mask[tractogram_mask > 0] = 1
        tmp_mask = tractogram_mask.astype(np.uint8) * target_mask.astype(
            np.uint8)
        streamlines_case = _streamlines_in_mask(list(sft.streamlines),
                                                tmp_mask, np.eye(3), [0, 0, 0])

        return np.where(streamlines_case == [0, 1][False])[0].tolist()
    else:
        target_mask = np.array(target_mask, dtype=np.uint8, copy=True)
        streamlines_case = _streamlines_in_mask(list(sft.streamlines),
                                                target_mask, np.eye(3),
                                                [0, 0, 0])
        return np.where(streamlines_case == [0, 1][True])[0].tolist()
Beispiel #2
0
def target_line_based(streamlines, affine, target_mask, include=True):
    """Filter streamlines based on whether or not they pass through a ROI,
    using a line-based algorithm. Mostly used as a replacement of `target`
    for compressed streamlines.

    This function never returns single-point streamlines, whatever the
    value of `include`.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines. Each streamline should be a (N, 3) array,
        where N is the length of the streamline.
    affine : array (4, 4)
        The mapping between voxel indices and the point space for seeds.
        The voxel_to_rasmm matrix, typically from a NIFTI file.
    target_mask : array-like
        A mask used as a target. Non-zero values are considered to be within
        the target region.
    include : bool, default True
        If True, streamlines passing through `target_mask` are kept. If False,
        the streamlines not passing through `target_mask` are kept.

    Returns
    -------
    streamlines : generator
        A sequence of streamlines that pass through `target_mask`.

    References
    ----------
    [Bresenham5] Bresenham, Jack Elton. "Algorithm for computer control of a
                 digital plotter", IBM Systems Journal, vol 4, no. 1, 1965.
    [Houde15] Houde et al. How to avoid biased streamlines-based metrics for
              streamlines with variable step sizes, ISMRM 2015.

    See Also
    --------
    dipy.tracking.utils.density_map
    dipy.tracking.streamline.compress_streamlines

    """
    target_mask = np.array(target_mask, dtype=np.uint8, copy=True)
    lin_T, offset = _mapping_to_voxel(affine)
    streamline_index = _streamlines_in_mask(streamlines, target_mask, lin_T,
                                            offset)
    yield
    # End of initialization

    for idx in np.where(streamline_index == [0, 1][include])[0]:
        yield streamlines[idx]
Beispiel #3
0
def target_line_based(streamlines, target_mask, affine=None, include=True):
    # Copy-Paste from Dipy to get indices
    target_mask = np.array(target_mask, dtype=np.uint8, copy=True)
    lin_T, offset = _mapping_to_voxel(affine)

    streamline_index = _streamlines_in_mask(
        streamlines, target_mask, lin_T, offset)

    target_indices = []
    target_streamlines = []
    for idx in np.where(streamline_index == [0, 1][include])[0]:
        target_indices.append(idx)
        target_streamlines.append(streamlines[idx])

    return target_streamlines, target_indices
Beispiel #4
0
def target_line_based(streamlines, target_mask, affine=None, include=True):
    """Filters streamlines based on whether or not they pass through a ROI,
    using a line-based algorithm. Mostly used as a replacement of `target`
    for compressed streamlines.

    This function never returns single-point streamlines, whatever the
    value of `include`.

    Parameters
    ----------
    streamlines : iterable
        A sequence of streamlines. Each streamline should be a (N, 3) array,
        where N is the length of the streamline.
    target_mask : array-like
        A mask used as a target. Non-zero values are considered to be within
        the target region.
    affine : array (4, 4)
        The affine transform from voxel indices to streamline points.
    include : bool, default True
        If True, streamlines passing through `target_mask` are kept. If False,
        the streamlines not passing through `target_mask` are kept.

    Returns
    -------
    streamlines : generator
        A sequence of streamlines that pass through `target_mask`.

    References
    ----------
    [Bresenham5] Bresenham, Jack Elton. "Algorithm for computer control of a
                 digital plotter", IBM Systems Journal, vol 4, no. 1, 1965.
    [Houde15] Houde et al. How to avoid biased streamlines-based metrics for
              streamlines with variable step sizes, ISMRM 2015.

    See Also
    --------
    dipy.tracking.utils.density_map
    dipy.tracking.streamline.compress_streamlines
    """
    target_mask = np.array(target_mask, dtype=np.uint8, copy=True)
    lin_T, offset = _mapping_to_voxel(affine, voxel_size=None)
    streamline_index = _streamlines_in_mask(
        streamlines, target_mask, lin_T, offset)
    yield
    # End of initialization

    for idx in np.where(streamline_index == [0, 1][include])[0]:
        yield streamlines[idx]
Beispiel #5
0
def streamlines_in_mask(sft, target_mask):
    """
    Parameters
    ----------
    sft : StatefulTractogram
        StatefulTractogram containing the streamlines to segment.
    target_mask : numpy.ndarray
        Binary mask in which the streamlines should pass.
    Returns
    -------
    ids : list
        Ids of the streamlines passing through the mask.
    """
    sft.to_vox()
    sft.to_corner()
    # Copy-Paste from Dipy to get indices
    target_mask = np.array(target_mask, dtype=np.uint8, copy=True)

    streamlines_case = _streamlines_in_mask(list(sft.streamlines),
                                            target_mask, np.eye(3),
                                            [-0.5, -0.5, -0.5])

    return np.where(streamlines_case == [0, 1][True])[0].tolist()
Beispiel #6
0
def _processing_wrapper(args):
    hdf5_filename = args[0]
    labels_img = args[1]
    in_label, out_label = args[2]
    measures_to_compute = copy.copy(args[3])
    if args[4] is not None:
        similarity_directory = args[4][0]
    weighted = args[5]
    include_dps = args[6]
    min_lesion_vol = args[7]

    hdf5_file = h5py.File(hdf5_filename, 'r')
    key = '{}_{}'.format(in_label, out_label)
    if key not in hdf5_file:
        return
    streamlines = reconstruct_streamlines_from_hdf5(hdf5_file, key)
    if len(streamlines) == 0:
        return

    affine, dimensions, voxel_sizes, _ = get_reference_info(labels_img)
    measures_to_return = {}

    if not (np.allclose(hdf5_file.attrs['affine'], affine, atol=1e-03)
            and np.array_equal(hdf5_file.attrs['dimensions'], dimensions)):
        raise ValueError('Provided hdf5 have incompatible headers.')

    # Precompute to save one transformation, insert later
    if 'length' in measures_to_compute:
        streamlines_copy = list(streamlines)
        # scil_decompose_connectivity.py requires isotropic voxels
        mean_length = np.average(length(streamlines_copy))*voxel_sizes[0]

    # If density is not required, do not compute it
    # Only required for volume, similarity and any metrics
    if not ((len(measures_to_compute) == 1 and
             ('length' in measures_to_compute or
              'streamline_count' in measures_to_compute)) or
            (len(measures_to_compute) == 2 and
             ('length' in measures_to_compute and
              'streamline_count' in measures_to_compute))):

        density = compute_tract_counts_map(streamlines,
                                           dimensions)

    if 'volume' in measures_to_compute:
        measures_to_return['volume'] = np.count_nonzero(density) * \
            np.prod(voxel_sizes)
        measures_to_compute.remove('volume')
    if 'streamline_count' in measures_to_compute:
        measures_to_return['streamline_count'] = len(streamlines)
        measures_to_compute.remove('streamline_count')
    if 'length' in measures_to_compute:
        measures_to_return['length'] = mean_length
        measures_to_compute.remove('length')
    if 'similarity' in measures_to_compute and similarity_directory:
        density_sim = load_node_nifti(similarity_directory,
                                      in_label, out_label,
                                      labels_img)
        if density_sim is None:
            ba_vox = 0
        else:
            ba_vox = compute_bundle_adjacency_voxel(density, density_sim)

        measures_to_return['similarity'] = ba_vox
        measures_to_compute.remove('similarity')

    for measure in measures_to_compute:
        # Maps
        if isinstance(measure, str) and os.path.isdir(measure):
            map_dirname = measure
            map_data = load_node_nifti(map_dirname,
                                       in_label, out_label,
                                       labels_img)
            measures_to_return[map_dirname] = np.average(
                map_data[map_data > 0])
        elif isinstance(measure, tuple):
            if not isinstance(measure[0], tuple) \
                    and os.path.isfile(measure[0]):
                metric_filename = measure[0]
                metric_img = measure[1]
                if not is_header_compatible(metric_img, labels_img):
                    logging.error('{} do not have a compatible header'.format(
                        metric_filename))
                    raise IOError

                metric_data = metric_img.get_fdata(dtype=np.float64)
                if weighted:
                    avg_value = np.average(metric_data, weights=density)
                else:
                    avg_value = np.average(metric_data[density > 0])
                measures_to_return[metric_filename] = avg_value
            # lesion
            else:
                lesion_filename = measure[0][0]
                computed_lesion_labels = measure[0][1]
                lesion_img = measure[1]
                if not is_header_compatible(lesion_img, labels_img):
                    logging.error('{} do not have a compatible header'.format(
                        lesion_filename))
                    raise IOError

                voxel_sizes = lesion_img.header.get_zooms()[0:3]
                lesion_img.set_filename('tmp.nii.gz')
                lesion_atlas = get_data_as_label(lesion_img)
                tmp_dict = compute_lesion_stats(
                    density.astype(bool), lesion_atlas,
                    voxel_sizes=voxel_sizes, single_label=True,
                    min_lesion_vol=min_lesion_vol,
                    precomputed_lesion_labels=computed_lesion_labels)

                tmp_ind = _streamlines_in_mask(list(streamlines),
                                               lesion_atlas.astype(np.uint8),
                                               np.eye(3), [0, 0, 0])
                streamlines_count = len(
                    np.where(tmp_ind == [0, 1][True])[0].tolist())

                if tmp_dict:
                    measures_to_return[lesion_filename+'vol'] = \
                        tmp_dict['lesion_total_volume']
                    measures_to_return[lesion_filename+'count'] = \
                        tmp_dict['lesion_count']
                    measures_to_return[lesion_filename+'sc'] = \
                        streamlines_count
                else:
                    measures_to_return[lesion_filename+'vol'] = 0
                    measures_to_return[lesion_filename+'count'] = 0
                    measures_to_return[lesion_filename+'sc'] = 0

    if include_dps:
        for dps_key in hdf5_file[key].keys():
            if dps_key not in ['data', 'offsets', 'lengths']:
                out_file = os.path.join(include_dps, dps_key)
                if 'commit' in dps_key:
                    measures_to_return[out_file] = np.sum(
                        hdf5_file[key][dps_key])
                else:
                    measures_to_return[out_file] = np.average(
                        hdf5_file[key][dps_key])

    return {(in_label, out_label): measures_to_return}