Exemplo n.º 1
0
def test_patch_up_roi():
    roi_bad = np.zeros((10, 10, 10))
    roi_good = np.ones((10, 10, 10))

    afv.patch_up_roi(roi_good)
    with pytest.raises(ValueError):
        afv.patch_up_roi(roi_bad)
Exemplo n.º 2
0
    def get_mask(self, afq_object, row):
        if afq_object.use_prealign:
            reg_prealign = np.load(afq_object._reg_prealign(row))
            reg_prealign_inv = np.linalg.inv(reg_prealign)
        else:
            reg_prealign_inv = None
        mapping = reg.read_mapping(afq_object._mapping(row),
                                   row['dwi_file'],
                                   afq_object.reg_template_img,
                                   prealign=reg_prealign_inv)

        mask_data = None
        for bundle_name, bundle_info in afq_object.bundle_dict.items():
            for idx, roi in enumerate(bundle_info['ROIs']):
                if afq_object.bundle_dict[bundle_name]['rules'][idx]:
                    warped_roi = auv.patch_up_roi(mapping.transform_inverse(
                        roi.get_fdata().astype(np.float32),
                        interpolation='linear'),
                                                  bundle_name=bundle_name)

                    if mask_data is None:
                        mask_data = np.zeros(warped_roi.shape)
                    mask_data = np.logical_or(mask_data,
                                              warped_roi.astype(bool))
        return mask_data, afq_object["dwi_affine"], dict(source="ROIs")
Exemplo n.º 3
0
    def _get_bundle_info(self, bundle_idx, bundle):
        """
        Get fiber probabilites and ROIs for a given bundle.
        """
        rules = self.bundle_dict[bundle]['rules']
        include_rois = []
        exclude_rois = []
        for rule_idx, rule in enumerate(rules):
            roi = self.bundle_dict[bundle]['ROIs'][rule_idx]
            if not isinstance(roi, np.ndarray):
                roi = roi.get_fdata()
            warped_roi = auv.patch_up_roi(
                self.mapping.transform_inverse(roi.astype(np.float32),
                                               interpolation='linear'))

            if rule:
                # include ROI:
                include_rois.append(np.array(np.where(warped_roi)).T)
            else:
                # Exclude ROI:
                exclude_rois.append(np.array(np.where(warped_roi)).T)

        # The probability map if doesn't exist is all ones with the same
        # shape as the ROIs:
        prob_map = self.bundle_dict[bundle].get('prob_map', np.ones(roi.shape))

        if not isinstance(prob_map, np.ndarray):
            prob_map = prob_map.get_fdata()
        warped_prob_map = \
            self.mapping.transform_inverse(prob_map,
                                           interpolation='nearest')
        return warped_prob_map, include_rois, exclude_rois
Exemplo n.º 4
0
def _export_rois(row, bundle_dict, reg_template, force_recompute=False):
    reg_prealign = np.load(_reg_prealign(row, force_recompute=force_recompute))

    mapping = reg.read_mapping(_mapping(row, reg_template),
                               row['dwi_file'],
                               reg_template,
                               prealign=np.linalg.inv(reg_prealign))

    rois_dir = op.join(row['results_dir'], 'ROIs')
    os.makedirs(rois_dir, exist_ok=True)

    for bundle in bundle_dict:
        for ii, roi in enumerate(bundle_dict[bundle]['ROIs']):

            if bundle_dict[bundle]['rules'][ii]:
                inclusion = 'include'
            else:
                inclusion = 'exclude'
            fname = op.join(rois_dir,
                            '%s_roi%s_%s.nii.gz' % (bundle, ii + 1, inclusion))
            warped_roi = auv.patch_up_roi((mapping.transform_inverse(
                roi.get_data(), interpolation='linear')) > 0).astype(int)
            # Cast to float32, so that it can be read in by MI-Brain:
            nib.save(
                nib.Nifti1Image(warped_roi.astype(np.float32),
                                row['dwi_affine']), fname)
Exemplo n.º 5
0
def visualize_roi(roi,
                  affine_or_mapping=None,
                  static_img=None,
                  roi_affine=None,
                  static_affine=None,
                  reg_template=None,
                  scene=None,
                  color=np.array([1, 0, 0]),
                  opacity=1.0,
                  inline=False,
                  interact=False):
    """
    Render a region of interest into a VTK viz as a volume
    """
    if not isinstance(roi, np.ndarray):
        if isinstance(roi, str):
            roi = nib.load(roi).get_fdata()
        else:
            roi = roi.get_fdata()

    if affine_or_mapping is not None:
        if isinstance(affine_or_mapping, np.ndarray):
            # This is an affine:
            if (static_img is None or roi_affine is None
                    or static_affine is None):
                raise ValueError(
                    "If using an affine to transform an ROI, "
                    "need to also specify all of the following",
                    "inputs: `static_img`, `roi_affine`, ", "`static_affine`")
            roi = reg.resample(roi, static_img, roi_affine, static_affine)
        else:
            # Assume it is  a mapping:
            if (isinstance(affine_or_mapping, str)
                    or isinstance(affine_or_mapping, nib.Nifti1Image)):
                if reg_template is None or static_img is None:
                    raise ValueError(
                        "If using a mapping to transform an ROI, need to ",
                        "also specify all of the following inputs: ",
                        "`reg_template`, `static_img`")
                affine_or_mapping = reg.read_mapping(affine_or_mapping,
                                                     static_img, reg_template)

            roi = auv.patch_up_roi(
                affine_or_mapping.transform_inverse(
                    roi, interpolation='nearest')).astype(bool)

    if scene is None:
        scene = window.Scene()

    roi_actor = actor.contour_from_roi(roi, color=color, opacity=opacity)
    scene.add(roi_actor)

    if inline:
        tdir = tempfile.gettempdir()
        fname = op.join(tdir, "fig.png")
        window.snapshot(scene, fname=fname)
        display.display_png(display.Image(fname))

    return _inline_interact(scene, inline, interact)
Exemplo n.º 6
0
    def _export_rois(self, row):
        if self.use_prealign:
            reg_prealign = np.load(self._reg_prealign(row))
            reg_prealign_inv = np.linalg.inv(reg_prealign)
        else:
            reg_prealign_inv = None

        mapping = reg.read_mapping(self._mapping(row),
                                   row['dwi_file'],
                                   self.reg_template,
                                   prealign=reg_prealign_inv)

        rois_dir = op.join(row['results_dir'], 'ROIs')
        os.makedirs(rois_dir, exist_ok=True)

        for bundle in self.bundle_dict:
            for ii, roi in enumerate(self.bundle_dict[bundle]['ROIs']):

                if self.bundle_dict[bundle]['rules'][ii]:
                    inclusion = 'include'
                else:
                    inclusion = 'exclude'

                warped_roi = auv.patch_up_roi((mapping.transform_inverse(
                    roi.get_fdata(), interpolation='linear')) > 0).astype(int)

                fname = op.split(
                    self._get_fname(
                        row,
                        f'_desc-ROI-{bundle}-{ii + 1}-{inclusion}.nii.gz'))

                fname = op.join(fname[0], rois_dir, fname[1])

                # Cast to float32, so that it can be read in by MI-Brain:
                nib.save(
                    nib.Nifti1Image(warped_roi.astype(np.float32),
                                    row['dwi_affine']), fname)
                meta = dict()
                meta_fname = fname.split('.')[0] + '.json'
                afd.write_json(meta_fname, meta)
Exemplo n.º 7
0
    def _get_bundle_info(self, bundle_idx, bundle):
        """
        Get fiber probabilites and ROIs for a given bundle.
        """
        rules = self.bundle_dict[bundle]['rules']
        include_rois = []
        exclude_rois = []
        for rule_idx, rule in enumerate(rules):
            roi = self.bundle_dict[bundle]['ROIs'][rule_idx]
            if not isinstance(roi, np.ndarray):
                roi = roi.get_fdata()
            warped_roi = auv.patch_up_roi(
                self.mapping.transform_inverse(roi.astype(np.float32),
                                               interpolation='linear'))

            if rule:
                # include ROI:
                include_rois.append(np.array(np.where(warped_roi)).T)
            else:
                # Exclude ROI:
                exclude_rois.append(np.array(np.where(warped_roi)).T)


########for debugging: save the warped ROI that is actually used in segment_afq() ##########
#       path_for_debugging = '/debugpath/'
#            nib.save(nib.Nifti1Image(warped_roi.astype(np.float32),
#                                     self.img_affine),
#                     debugpath+'warpedROI_'+bundle+'as_used.nii.gz')
############################################################################################

# The probability map if doesn't exist is all ones with the same
# shape as the ROIs:
        prob_map = self.bundle_dict[bundle].get('prob_map', np.ones(roi.shape))

        if not isinstance(prob_map, np.ndarray):
            prob_map = prob_map.get_fdata()
        warped_prob_map = \
            self.mapping.transform_inverse(prob_map,
                                           interpolation='nearest')
        return warped_prob_map, include_rois, exclude_rois
Exemplo n.º 8
0
    def _get_bundle_info(self, bundle_idx, bundle):
        """
        Get fiber probabilites and ROIs for a given bundle.
        """
        rules = self.bundle_dict[bundle]['rules']
        include_rois = []
        exclude_rois = []
        for rule_idx, rule in enumerate(rules):
            roi = self.bundle_dict[bundle]['ROIs'][rule_idx]
            if not isinstance(roi, np.ndarray):
                roi = roi.get_fdata()
            warped_roi = auv.patch_up_roi(
                self.mapping.transform_inverse(roi.astype(np.float32),
                                               interpolation='linear'))

            if rule:
                # include ROI:
                include_rois.append(np.array(np.where(warped_roi)).T)
            else:
                # Exclude ROI:
                exclude_rois.append(np.array(np.where(warped_roi)).T)

            # For debugging purposes, we can save the variable as it is:
            if self.save_intermediates is not None:
                nib.save(
                    nib.Nifti1Image(warped_roi.astype(np.float32),
                                    self.img_affine),
                    op.join(self.save_intermediates, 'warpedROI_', bundle,
                            'as_used.nii.gz'))

        # The probability map if doesn't exist is all ones with the same
        # shape as the ROIs:
        prob_map = self.bundle_dict[bundle].get('prob_map', np.ones(roi.shape))

        if not isinstance(prob_map, np.ndarray):
            prob_map = prob_map.get_fdata()
        warped_prob_map = \
            self.mapping.transform_inverse(prob_map,
                                           interpolation='nearest')
        return warped_prob_map, include_rois, exclude_rois
Exemplo n.º 9
0
#   - Each step is 0.5 mm
#
# .. note::
#   In this example tractography results in a large number of candidate
#   streamlines for the anterior forceps, but not many streamlines anywhere
#   else.

print("Tracking...")

if not op.exists(op.join(working_dir, 'dti_streamlines.trk')):
    seed_roi = np.zeros(img.shape[:-1])
    for bundle in bundles:
        for idx, roi in enumerate(bundles[bundle]['ROIs']):
            if bundles[bundle]['rules'][idx]:
                warped_roi = patch_up_roi(mapping.transform_inverse(
                    roi.get_fdata().astype(np.float32),
                    interpolation='linear'),
                                          bundle_name=bundle)

                nib.save(nib.Nifti1Image(warped_roi.astype(float), img.affine),
                         op.join(working_dir, f"{bundle}_{idx+1}.nii.gz"))

                warped_roi_img = nib.load(
                    op.join(working_dir, f"{bundle}_{idx+1}.nii.gz"))
                show_anatomical_slices(warped_roi_img.get_fdata(),
                                       f'warped {bundle}_{idx+1} ROI')

                # Add voxels that aren't there yet:
                seed_roi = np.logical_or(seed_roi, warped_roi)

    seed_roi_img = nib.Nifti1Image(seed_roi.astype(float), img.affine)
    nib.save(seed_roi_img, op.join(working_dir, 'seed_roi.nii.gz'))
Exemplo n.º 10
0
def segment(fdata, fbval, fbvec, streamlines, bundle_dict, mapping,
            reg_prealign=None, b0_threshold=0, reg_template=None,
            prob_threshold=0):
    """
    Segment streamlines into bundles based on inclusion ROIs.

    Parameters
    ----------
    fdata, fbval, fbvec : str
        Full path to data, bvals, bvecs

    streamlines : list of 2D arrays
        Each array is a streamline, shape (3, N).

    bundle_dict: dict
        The format is something like::

            {'name': {'ROIs':[img1, img2],
            'rules':[True, True]},
            'prob_map': img3,
            'cross_midline': False}

    mapping : a DiffeomorphicMapping object
        Used to align the ROIs to the data.

    reg_template : str or nib.Nifti1Image, optional.
        Template to use for registration (defaults to the MNI T2)

    mapping : DiffeomorphicMap object, str or nib.Nifti1Image, optional
        A mapping between DWI space and a template. Defaults to generate
        this.

    prob_threshold : float.
        Initial cleaning of fiber groups is done using probability maps from
        [Hua2008]_. Here, we choose an average probability that needs to be
        exceeded for an individual streamline to be retained. Default: 0.

    References
    ----------
    .. [Hua2008] Hua K, Zhang J, Wakana S, Jiang H, Li X, et al. (2008)
       Tract probability maps in stereotaxic spaces: analyses of white
       matter anatomy and tract-specific quantification. Neuroimage 39:
       336-347
    """
    img, _, gtab, _ = ut.prepare_data(fdata, fbval, fbvec,
                                      b0_threshold=b0_threshold)

    tol = dts.dist_to_corner(img.affine)

    if reg_template is None:
        reg_template = dpd.read_mni_template()

    # Classify the streamlines and split those that: 1) cross the
    # midline, and 2) pass under 10 mm below the mid-point of their
    # representation in the template space:
    xform_sl, crosses = split_streamlines(streamlines, img)

    if isinstance(mapping, str) or isinstance(mapping, nib.Nifti1Image):
        if reg_prealign is None:
            reg_prealign = np.eye(4)
        mapping = reg.read_mapping(mapping, img, reg_template,
                                   prealign=reg_prealign)

    fiber_probabilities = np.zeros((len(xform_sl), len(bundle_dict)))

    # For expedience, we approximate each streamline as a 100 point curve:
    fgarray = _resample_bundle(xform_sl, 100)
    streamlines_in_bundles = np.zeros((len(xform_sl), len(bundle_dict)))
    min_dist_coords = np.zeros((len(xform_sl), len(bundle_dict), 2))

    fiber_groups = {}

    for bundle_idx, bundle in enumerate(bundle_dict):
        rules = bundle_dict[bundle]['rules']
        include_rois = []
        exclude_rois = []
        for rule_idx, rule in enumerate(rules):
            roi = bundle_dict[bundle]['ROIs'][rule_idx]
            if not isinstance(roi, np.ndarray):
                roi = roi.get_data()
            warped_roi = auv.patch_up_roi(
                (mapping.transform_inverse(
                    roi,
                    interpolation='linear')) > 0)

            if rule:
                # include ROI:
                include_rois.append(np.array(np.where(warped_roi)).T)
            else:
                # Exclude ROI:
                exclude_rois.append(np.array(np.where(warped_roi)).T)

        crosses_midline = bundle_dict[bundle]['cross_midline']

        # The probability map if doesn't exist is all ones with the same
        # shape as the ROIs:
        prob_map = bundle_dict[bundle].get('prob_map', np.ones(roi.shape))

        if not isinstance(prob_map, np.ndarray):
            prob_map = prob_map.get_data()
        warped_prob_map = mapping.transform_inverse(prob_map,
                                                    interpolation='nearest')
        fiber_probabilities = dts.values_from_volume(warped_prob_map,
                                                     fgarray)
        fiber_probabilities = np.mean(fiber_probabilities, -1)

        for sl_idx, sl in enumerate(xform_sl):
            if fiber_probabilities[sl_idx] > prob_threshold:
                if crosses_midline is not None:
                    if crosses[sl_idx]:
                        # This means that the streamline does
                        # cross the midline:
                        if crosses_midline:
                            # This is what we want, keep going
                            pass
                        else:
                            # This is not what we want, skip to next streamline
                            continue

                is_close, dist = _check_sl_with_inclusion(sl, include_rois,
                                                          tol)
                if is_close:
                    is_far = _check_sl_with_exclusion(sl, exclude_rois,
                                                      tol)
                    if is_far:
                        min_dist_coords[sl_idx, bundle_idx, 0] =\
                            np.argmin(dist[0], 0)[0]
                        min_dist_coords[sl_idx, bundle_idx, 1] =\
                            np.argmin(dist[1], 0)[0]
                        streamlines_in_bundles[sl_idx, bundle_idx] =\
                            fiber_probabilities[sl_idx]

    # Eliminate any fibers not selected using the plane ROIs:
    possible_fibers = np.sum(streamlines_in_bundles, -1) > 0
    xform_sl = xform_sl[possible_fibers]
    streamlines_in_bundles = streamlines_in_bundles[possible_fibers]
    min_dist_coords = min_dist_coords[possible_fibers]
    bundle_choice = np.argmax(streamlines_in_bundles, -1)

    # We do another round through, so that we can orient all the
    # streamlines within a bundle in the same orientation with respect to
    # the ROIs. This order is ARBITRARY but CONSISTENT (going from ROI0
    # to ROI1).
    for bundle_idx, bundle in enumerate(bundle_dict):
        select_idx = np.where(bundle_choice == bundle_idx)
        # Use a list here, because Streamlines don't support item assignment:
        select_sl = list(xform_sl[select_idx])
        if len(select_sl) == 0:
            fiber_groups[bundle] = dts.Streamlines([])
            # There's nothing here, move to the next bundle:
            continue

        # Sub-sample min_dist_coords:
        min_dist_coords_bundle = min_dist_coords[select_idx]
        for idx in range(len(select_sl)):
            min0 = min_dist_coords_bundle[idx, bundle_idx, 0]
            min1 = min_dist_coords_bundle[idx, bundle_idx, 1]
            if min0 > min1:
                select_sl[idx] = select_sl[idx][::-1]
        # Set this to nibabel.Streamlines object for output:
        select_sl = dts.Streamlines(select_sl)
        fiber_groups[bundle] = select_sl

    return fiber_groups