Exemple #1
0
def _carve_segs(roi, blobs):
    # carve out background from segmented area
    carved = roi
    if blobs is None:
        # clean up by using simple threshold to remove all background
        carved, _ = cv_nd.carve(carved)
    else:
        # use blobs as ellipsoids to identify background to remove; 
        # TODO: consider setting spacing in config since depends on 
        # microscopy characteristics, such as elongation from 
        # thick lightsheet
        thresholded = plot_3d.build_ground_truth(
            np.zeros(carved.shape, dtype=bool), blobs, ellipsoid=True)
        #thresholded = thresholded.astype(bool)
        carved[~thresholded] = 0
    return carved
Exemple #2
0
def segment_from_labels(edges,
                        markers,
                        labels_img,
                        atlas_img=None,
                        exclude_labels=None,
                        mask_filt=config.SmoothingModes.opening,
                        mask_filt_size=2):
    """Segment an image using markers from a labels image.
    
    Labels images may have been generally manually and thus may not 
    perfectly match the underlying image. As a way to check or 
    augment the label image, segment the underlying image using 
    the labels as the seeds to prescribe the number and initial 
    location of each label.
    
    Args:
        edges (:obj:`np.ndarray`): Image as a Numpy array to segment,
            typically an edge-detected image of the main atlas.
        markers (:obj:`np.ndarray`): Image as an integer Numpy array of same
            shape as ``img`` to use as seeds for the watershed segmentation.
            This array is generally constructed from an array similar to
            ``labels_img``.
        labels_img (:obj:`np.ndarray`): Labels image as Numpy array of same
            shape as ``img``, used to generate a mask for the watershed.
            If None, a mask will be generated from a thresholded version of
            ``atlas_img``, so should only be None if ``atlas_img`` is not None. 
        atlas_img (:obj:`np.ndarray`): Atlas image as a Numpy array to use
            for finding foreground; defaults to None. If both ``labels_img``
            and ``atlas_img`` are not None, their combined volume will be
            used as a mask.
        exclude_labels (List[int]): Sequence of labels to exclude from the
            segmentation; defaults to None.
        mask_filt (:obj:`config.SmoothingModes`): Enumeration for a filter
            mode to use for the watershed mask; defaults to
            :obj:`config.SmoothingModes.opening`. Ignored if ``atlas_img``
            or both ``atlas_img`` and ``labels_img`` are given to generate
            the mask.
        mask_filt_size (int): Size of structuring element for the filter
            specified by ``mask_filt``; defaults to 2.
    
    Returns:
        :obj:`np.ndarray`: Segmented image of the same shape as ``img`` with
        the same number of labels as in ``markers``.
    
    """
    # generate mask for watershed
    if atlas_img is not None and labels_img is not None:
        # broad mask from both atlas and labels
        mask = mask_atlas(atlas_img, labels_img)
    elif atlas_img is not None:
        # otsu seems to give more inclusive threshold for these atlases
        _, mask = cv_nd.carve(atlas_img,
                              thresh=filters.threshold_otsu(atlas_img),
                              holes_area=5000)
    else:
        # default to using label foreground
        mask = labels_img != 0
        fn_mask = None
        if mask_filt is config.SmoothingModes.opening:
            # default filter opens the mask to prevent spillover across
            # artifacts that may bridge otherwise separate structures
            fn_mask = morphology.binary_opening
        elif mask_filt is config.SmoothingModes.closing:
            fn_mask = morphology.binary_closing
        if fn_mask and mask_filt_size:
            print("Filtering watershed mask with {}, size {}".format(
                fn_mask, mask_filt_size))
            mask = fn_mask(mask,
                           cv_nd.get_selem(labels_img.ndim)(mask_filt_size))

    exclude = None
    if exclude_labels is not None:
        # remove excluded labels from mask
        exclude = np.isin(labels_img, exclude_labels)
        mask[exclude] = False
        # WORKAROUND: remove excluded markers from marker image itself for
        # apparent Scikit-image bug (see PR 3809, fixed in 0.15)
        markers[np.isin(markers, exclude_labels)] = 0

    watershed = watershed_distance(edges == 0,
                                   markers,
                                   compactness=0.005,
                                   mask=mask)
    if exclude is not None:
        # add excluded labels directly to watershed image
        watershed[exclude] = labels_img[exclude]
    return watershed
Exemple #3
0
def segment_from_labels(edges, markers, labels_img, atlas_img=None,
                        exclude_labels=None):
    """Segment an image using markers from a labels image.
    
    Labels images may have been generally manually and thus may not 
    perfectly match the underlying image. As a way to check or 
    augment the label image, segment the underlying image using 
    the labels as the seeds to prescribe the number and initial 
    location of each label.
    
    Args:
        edges (:obj:`np.ndarray`): Image as a Numpy array to segment,
            typically an edge-detected image of the main atlas.
        markers (:obj:`np.ndarray`): Image as an integer Numpy array of same
            shape as ``img`` to use as seeds for the watershed segmentation.
            This array is generally constructed from an array similar to
            ``labels_img``.
        labels_img (:obj:`np.ndarray`): Labels image as Numpy array of same
            shape as ``img``, used to generate a mask for the watershed.
            If None, a mask will be generated from a thresholded version of
            ``atlas_img``, so should only be None if ``atlas_img`` is not None. 
        atlas_img (:obj:`np.ndarray`): Atlas image as a Numpy array to use
            for finding foreground; defaults to None. If both ``labels_img``
            and ``atlas_img`` are not None, their combined volume will be
            used as a mask.
        exclude_labels (List[int]): Sequence of labels to exclude from the
            segmentation; defaults to None.
    
    Returns:
        :obj:`np.ndarray`: Segmented image of the same shape as ``img`` with
        the same number of labels as in ``markers``.
    """
    if atlas_img is not None and labels_img is not None:
        # broad mask from both atlas and labels
        mask = mask_atlas(atlas_img, labels_img)
    elif atlas_img is not None:
        # otsu seems to give more inclusive threshold for these atlases
        _, mask = cv_nd.carve(
            atlas_img, thresh=filters.threshold_otsu(atlas_img), 
            holes_area=5000)
    else:
        # default to using labels, opening them up small holes to prevent 
        # spillover across artifacts that may bridge them
        fn_selem = cv_nd.get_selem(labels_img.ndim)
        mask = morphology.binary_opening(labels_img != 0, fn_selem(2))
    
    exclude = None
    if exclude_labels is not None:
        # remove excluded labels from mask
        exclude = np.isin(labels_img, exclude_labels)
        mask[exclude] = False
        # WORKAROUND: remove excluded markers from marker image itself for
        # apparent Scikit-image bug (see PR 3809, fixed in 0.15)
        markers[np.isin(markers, exclude_labels)] = 0
    
    watershed = watershed_distance(
        edges == 0, markers, compactness=0.005, mask=mask)
    if exclude is not None:
        # add excluded labels directly to watershed image
        watershed[exclude] = labels_img[exclude]
    return watershed