Example #1
0
def main():
    parser = _build_arg_parser()
    args = parser.parse_args()
    if args.verbose:
        logging.basicConfig(level=logging.INFO)

    # Checking args
    assert_outputs_exist(parser, args, args.out_sh)
    assert_inputs_exist(parser, args.in_sh)

    # Prepare data
    sh_img = nib.load(args.in_sh)
    data = sh_img.get_fdata(dtype=np.float32)

    sh_order, full_basis = get_sh_order_and_fullness(data.shape[-1])

    logging.info('Executing local asymmetric filtering.')
    filtered_sh = local_asym_filtering(data,
                                       sh_order=sh_order,
                                       sh_basis=args.sh_basis,
                                       in_full_basis=full_basis,
                                       sphere_str=args.sphere,
                                       dot_sharpness=args.sharpness,
                                       sigma=args.sigma)

    logging.info('Saving filtered SH to file {0}.'.format(args.out_sh))
    nib.save(nib.Nifti1Image(filtered_sh, sh_img.affine), args.out_sh)

    if args.out_sym:
        _, orders = sph_harm_ind_list(sh_order, full_basis=True)
        logging.info('Saving symmetric SH to file {0}.'.format(args.out_sym))
        nib.save(
            nib.Nifti1Image(filtered_sh[..., orders % 2 == 0], sh_img.affine),
            args.out_sym)
Example #2
0
def main():
    parser = _build_arg_parser()
    args = _parse_args(parser)
    data = _get_data_from_inputs(args)
    sph = get_sphere(args.sphere)
    sh_order, full_basis = get_sh_order_and_fullness(data['fodf'].shape[-1])

    actors = []

    # Retrieve the mask if supplied
    if 'mask' in data:
        mask = data['mask']
    else:
        mask = None

    # Instantiate the ODF slicer actor
    odf_actor = create_odf_slicer(data['fodf'], args.axis_name,
                                  args.slice_index, mask, sph,
                                  args.sph_subdivide, sh_order, args.sh_basis,
                                  full_basis, args.scale,
                                  not args.radial_scale_off, not args.norm_off,
                                  args.colormap)
    actors.append(odf_actor)

    # Instantiate a texture slicer actor if a background image is supplied
    if 'bg' in data:
        bg_actor = create_texture_slicer(data['bg'], args.axis_name,
                                         args.slice_index, mask, args.bg_range,
                                         args.bg_opacity, args.bg_offset,
                                         args.bg_interpolation)
        actors.append(bg_actor)

    # Instantiate a peaks slicer actor if peaks are supplied
    if 'peaks' in data:
        peaks_values = None
        if 'peaks_values' in data:
            peaks_values = data['peaks_values']
        else:
            peaks_values =\
                np.ones(data['peaks'].shape[:-1]) * args.peaks_length
        peaks_actor = create_peaks_slicer(data['peaks'], args.axis_name,
                                          args.slice_index, peaks_values, mask,
                                          args.peaks_color, args.peaks_width,
                                          not full_basis)

        actors.append(peaks_actor)

    # Prepare and display the scene
    scene = create_scene(actors, args.axis_name, args.slice_index,
                         data['fodf'].shape[:3])
    render_scene(scene, args.win_dims, args.interactor, args.output,
                 args.silent)
Example #3
0
def main():
    parser = _build_arg_parser()
    args = parser.parse_args()
    if args.verbose:
        logging.basicConfig(level=logging.INFO)

    # Checking args
    outputs = [args.out_sh]
    if args.out_sym:
        outputs.append(args.out_sym)
    assert_outputs_exist(parser, args, outputs)
    assert_inputs_exist(parser, args.in_sh)

    nbr_processes = validate_nbr_processes(parser, args)

    # Prepare data
    sh_img = nib.load(args.in_sh)
    data = sh_img.get_fdata(dtype=np.float32)

    sh_order, full_basis = get_sh_order_and_fullness(data.shape[-1])

    t0 = time.perf_counter()
    logging.info('Executing angle-aware bilateral filtering.')
    asym_sh = angle_aware_bilateral_filtering(
        data, sh_order=sh_order,
        sh_basis=args.sh_basis,
        in_full_basis=full_basis,
        sphere_str=args.sphere,
        sigma_spatial=args.sigma_spatial,
        sigma_angular=args.sigma_angular,
        sigma_range=args.sigma_range,
        use_gpu=args.use_gpu,
        nbr_processes=nbr_processes)
    t1 = time.perf_counter()
    logging.info('Elapsed time (s): {0}'.format(t1 - t0))

    logging.info('Saving filtered SH to file {0}.'.format(args.out_sh))
    nib.save(nib.Nifti1Image(asym_sh, sh_img.affine), args.out_sh)

    if args.out_sym:
        _, orders = sph_harm_ind_list(sh_order, full_basis=True)
        logging.info('Saving symmetric SH to file {0}.'.format(args.out_sym))
        nib.save(nib.Nifti1Image(asym_sh[..., orders % 2 == 0], sh_img.affine),
                 args.out_sym)
Example #4
0
    def __init__(self,
                 dataset,
                 step_size,
                 rk_order,
                 algo,
                 basis,
                 sf_threshold,
                 sf_threshold_init,
                 theta,
                 dipy_sphere='symmetric724',
                 min_separation_angle=np.pi / 16.):
        """

        Parameters
        ----------
        dataset: scilpy.image.datasets.DataVolume
            Trackable Dataset object.
        step_size: float
            The step size for tracking.
        rk_order: int
            Order for the Runge Kutta integration.
        theta: float
            Maximum angle (radians) between two steps.
        dipy_sphere: string, optional
            If necessary, name of the DIPY sphere object to use to evaluate
            directions.
        basis: string
            SH basis name. One of 'tournier07' or 'descoteaux07'
        sf_threshold: float
            Threshold on spherical function (SF).
        sf_threshold_init: float
            Threshold on spherical function when initializing a new streamline.
        theta: float
            Maximum angle (radians) between two steps.
        dipy_sphere: string, optional
            Name of the DIPY sphere object to use for evaluating SH. Can't be
            None.
        min_separation_angle: float, optional
            Minimum separation angle (in radians) for peaks extraction. Used
            for deterministic tracking. A candidate direction is a maximum if
            its SF value is greater than all other SF values in its
            neighbourhood, where the neighbourhood includes all the sphere
            directions located at most `min_separation_angle` from the
            candidate direction.
        """
        super().__init__(dataset, step_size, rk_order, dipy_sphere)

        # Propagation params
        self.theta = theta
        if algo not in ['det', 'prob']:
            raise ValueError("ODFPropagator algo should be 'det' or 'prob'.")
        self.algo = algo
        self.tracking_neighbours = get_sphere_neighbours(
            self.sphere, self.theta)
        # For deterministic tracking:
        self.maxima_neighbours = get_sphere_neighbours(self.sphere,
                                                       min_separation_angle)

        # ODF params
        self.sf_threshold = sf_threshold
        self.sf_threshold_init = sf_threshold_init
        sh_order, full_basis =\
            get_sh_order_and_fullness(self.dataset.data.shape[-1])
        self.basis = basis
        self.B = sh_to_sf_matrix(self.sphere,
                                 sh_order,
                                 self.basis,
                                 smooth=0.006,
                                 return_inv=False,
                                 full_basis=full_basis)
Example #5
0
def bingham_fit_sh(sh,
                   max_lobes=5,
                   abs_th=0.,
                   rel_th=0.,
                   min_sep_angle=25.,
                   max_fit_angle=15,
                   mask=None,
                   nbr_processes=None):
    """
    Approximate SH field by fitting Bingham distributions to
    up to ``max_lobes`` lobes per voxel, sorted in descending order
    by the amplitude of their peak direction.

    Parameters
    ----------
    sh: ndarray (X, Y, Z, ncoeffs)
        SH coefficients array.
    max_lobes: unsigned int, optional
        Maximum number of lobes to fit per voxel.
    abs_th: float, optional
        Absolute threshold for peak extraction.
    rel_th: float, optional
        Relative threshold for peak extraction in the range [0, 1].
    min_sep_angle: float, optional
        Minimum separation angle between two adjacent peaks in degrees.
    max_fit_angle: float, optional
        The maximum distance in degrees around a peak direction for
        fitting the Bingham function.
    mask: ndarray (X, Y, Z), optional
        Mask to apply to the data.
    nbr_processes: unsigned int, optional
        The number of processes to use. If None, than
        ``multiprocessing.cpu_count()`` processes are executed.

    Returns
    -------
    out: ndarray (X, Y, Z, max_lobes*9)
        Bingham functions array.
    """
    order, full_basis = get_sh_order_and_fullness(sh.shape[-1])
    shape = sh.shape

    sphere = get_sphere('symmetric724').subdivide(2)
    B_mat = sh_to_sf_matrix(sphere,
                            order,
                            full_basis=full_basis,
                            return_inv=False)

    nbr_processes = multiprocessing.cpu_count()\
        if nbr_processes is None \
        or nbr_processes < 0 \
        or nbr_processes > multiprocessing.cpu_count() \
        else nbr_processes

    if mask is not None:
        sh = sh[mask]
    else:
        sh = sh.reshape((-1, shape[-1]))

    sh = np.array_split(sh, nbr_processes)
    pool = multiprocessing.Pool(nbr_processes)
    out = pool.map(
        _bingham_fit_sh_chunk,
        zip(sh, itertools.repeat(B_mat), itertools.repeat(sphere),
            itertools.repeat(abs_th), itertools.repeat(min_sep_angle),
            itertools.repeat(rel_th), itertools.repeat(max_lobes),
            itertools.repeat(max_fit_angle)))
    pool.close()
    pool.join()

    out = np.concatenate(out, axis=0)
    if mask is not None:
        bingham = np.zeros(shape[:3] + (max_lobes, NB_PARAMS))
        bingham[mask] = out
        return bingham

    out = out.reshape(shape[:3] + (max_lobes, NB_PARAMS))
    return out
Example #6
0
def main():
    parser = _build_arg_parser()
    args = parser.parse_args()

    if not args.not_all:
        args.cos_asym_map = args.cos_asym_map or 'cos_asym_map.nii.gz'
        args.odd_power_map = args.odd_power_map or 'odd_power_map.nii.gz'
        args.peaks = args.peaks or 'asym_peaks.nii.gz'
        args.peak_values = args.peak_values or 'asym_peak_values.nii.gz'
        args.peak_indices = args.peak_indices or 'asym_peak_indices.nii.gz'
        args.nupeaks = args.nupeaks or 'nupeaks.nii.gz'

    arglist = [
        args.cos_asym_map, args.odd_power_map, args.peaks, args.peak_values,
        args.peak_indices, args.nupeaks
    ]
    if args.not_all and not any(arglist):
        parser.error('When using --not_all, you need to specify at least '
                     'one file to output.')

    inputs = [args.in_sh]
    if args.mask:
        inputs.append(args.mask)

    assert_inputs_exist(parser, inputs)
    assert_outputs_exist(parser, args, arglist)

    sh_img = nib.load(args.in_sh)
    sh = sh_img.get_fdata()

    sphere = get_sphere(args.sphere)

    sh_order, full_basis = get_sh_order_and_fullness(sh.shape[-1])
    if not full_basis:
        parser.error('Invalid SH image. A full SH basis is expected.')

    if args.mask:
        mask = get_data_as_mask(nib.load(args.mask), dtype=bool)
    else:
        mask = np.sum(np.abs(sh), axis=-1) > 0

    if args.cos_asym_map:
        cos_asym_map = compute_cos_asym_map(sh, sh_order, mask)
        nib.save(nib.Nifti1Image(cos_asym_map, sh_img.affine),
                 args.cos_asym_map)

    if args.odd_power_map:
        odd_power_map = compute_odd_power_map(sh, sh_order, mask)
        nib.save(nib.Nifti1Image(odd_power_map, sh_img.affine),
                 args.odd_power_map)

    if args.peaks or args.peak_values or args.peak_indices or args.nupeaks:
        peaks, values, indices =\
            peaks_from_sh(sh, sphere, mask=mask,
                          relative_peak_threshold=args.r_threshold,
                          absolute_threshold=args.a_threshold,
                          min_separation_angle=25,
                          normalize_peaks=False,
                          # because v and -v are unique, we want twice
                          # the usual default value (5) of npeaks
                          npeaks=10,
                          sh_basis_type=args.sh_basis,
                          nbr_processes=args.nbr_processes,
                          full_basis=True,
                          is_symmetric=False)

        if args.peaks:
            nib.save(
                nib.Nifti1Image(reshape_peaks_for_visualization(peaks),
                                sh_img.affine), args.peaks)

        if args.peak_values:
            nib.save(nib.Nifti1Image(values, sh_img.affine), args.peak_values)

        if args.peak_indices:
            nib.save(nib.Nifti1Image(indices.astype(np.uint8), sh_img.affine),
                     args.peak_indices)

        if args.nupeaks:
            nupeaks = np.count_nonzero(values, axis=-1).astype(np.uint8)
            nib.save(nib.Nifti1Image(nupeaks, sh_img.affine), args.nupeaks)