Exemplo n.º 1
0
    def test_cdog(self):

        im_nuclei_stain_data = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_nuclei_stain.npz'))
        im_nuclei_stain = im_nuclei_stain_data['Easy1_nuclei_stain']

        im_nuclei_fgnd_mask_data = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_nuclei_fgnd_mask.npz'))
        im_nuclei_fgnd_mask = im_nuclei_fgnd_mask_data[
            'Easy1_nuclei_fgnd_mask']

        sigma_min = 10.0 / np.sqrt(2.0)
        sigma_max = 40.0 / np.sqrt(2.0)

        im_dog_max, im_sigma_max = cdog(im_nuclei_stain, im_nuclei_fgnd_mask,
                                        sigma_min, sigma_max)

        im_dog_max_gtruth_data = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_cdog_max.npz'))
        im_dog_max_gtruth = im_dog_max_gtruth_data['Easy1_cdog_max']
        assert_array_almost_equal_neighborhood_lines(im_dog_max,
                                                     im_dog_max_gtruth,
                                                     decimal=4)
        compare_maxima(im_dog_max, im_dog_max_gtruth)

        im_sigma_max_gtruth_data = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_cdog_sigma_max.npz'))
        im_sigma_max_gtruth = im_sigma_max_gtruth_data['Easy1_cdog_sigma_max']
        assert_array_almost_equal_neighborhood_lines(im_sigma_max,
                                                     im_sigma_max_gtruth,
                                                     decimal=4)
Exemplo n.º 2
0
    def test_cdog(self):

        im_nuclei_stain = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_nuclei_stain.npy'))

        im_nuclei_fgnd_mask = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_nuclei_fgnd_mask.npy'))

        sigma_min = 10.0 / np.sqrt(2.0)
        sigma_max = 40.0 / np.sqrt(2.0)

        im_dog_max, im_sigma_max = cdog(im_nuclei_stain, im_nuclei_fgnd_mask,
                                        sigma_min, sigma_max)

        im_dog_max_gtruth = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_cdog_max.npy'))

        np.testing.assert_array_almost_equal(im_dog_max.astype(np.float16),
                                             im_dog_max_gtruth,
                                             decimal=4)

        im_sigma_max_gtruth = np.load(
            os.path.join(TEST_DATA_DIR, 'Easy1_cdog_sigma_max.npy'))

        np.testing.assert_array_almost_equal(im_sigma_max.astype(np.float16),
                                             im_sigma_max_gtruth,
                                             decimal=4)
Exemplo n.º 3
0
def detect_nuclei_kofahi(im_nuclei_stain, args):

    # segment nuclear foreground mask
    # (assumes nuclei are darker on a bright background)
    im_nuclei_fgnd_mask = im_nuclei_stain < args.foreground_threshold

    # smooth foreground mask with closing and opening
    im_nuclei_fgnd_mask = skimage.morphology.closing(
        im_nuclei_fgnd_mask, skimage.morphology.disk(3))

    im_nuclei_fgnd_mask = skimage.morphology.opening(
        im_nuclei_fgnd_mask, skimage.morphology.disk(3))

    im_nuclei_fgnd_mask = sp.ndimage.morphology.binary_fill_holes(
        im_nuclei_fgnd_mask)

    # run adaptive multi-scale LoG filter
    im_log_max, im_sigma_max = htk_shape_filters.cdog(
        im_nuclei_stain, im_nuclei_fgnd_mask,
        sigma_min=args.min_radius / np.sqrt(2),
        sigma_max=args.max_radius / np.sqrt(2)
    )

    # apply local maximum clustering
    im_nuclei_seg_mask, seeds, maxima = htk_seg.nuclear.max_clustering(
        im_log_max, im_nuclei_fgnd_mask, args.local_max_search_radius)

    # split any objects with disconnected fragments
    im_nuclei_seg_mask = htk_seg.label.split(im_nuclei_seg_mask, conn=8)

    # filter out small objects
    im_nuclei_seg_mask = htk_seg.label.area_open(
        im_nuclei_seg_mask, args.min_nucleus_area).astype(np.int)

    return im_nuclei_seg_mask
Exemplo n.º 4
0
def detect_nuclei_kofahi(im_nuclei_stain, args):

    # segment foreground (assumes nuclei are darker on a bright background)
    im_nuclei_fgnd_mask = sp.ndimage.morphology.binary_fill_holes(
        im_nuclei_stain < args.foreground_threshold)

    # run adaptive multi-scale LoG filter
    im_log_max, im_sigma_max = htk_shape_filters.cdog(
        im_nuclei_stain,
        im_nuclei_fgnd_mask,
        sigma_min=args.min_radius / np.sqrt(2),
        sigma_max=args.max_radius / np.sqrt(2))

    # apply local maximum clustering
    im_nuclei_seg_mask, seeds, maxima = htk_seg.nuclear.max_clustering(
        im_log_max, im_nuclei_fgnd_mask, args.local_max_search_radius)

    # filter out small objects
    im_nuclei_seg_mask = htk_seg.label.area_open(
        im_nuclei_seg_mask, args.min_nucleus_area).astype(np.int)

    return im_nuclei_seg_mask
def detect_nuclei(im_input, min_radius=6, max_radius=10, display_result=False):

    # color normalization
    ref_mu_lab = (8.63234435, -0.11501964, 0.03868433)
    ref_std_lab = (0.57506023, 0.10403329, 0.01364062)

    im_nmzd = htk_cnorm.reinhard(im_input, ref_mu_lab, ref_std_lab)

    # color deconvolution
    w_est = htk_cdeconv.rgb_separate_stains_macenko_pca(im_nmzd, 255)
    nuclear_chid = htk_cdeconv.find_stain_index(
        htk_cdeconv.stain_color_map['hematoxylin'], w_est)
    im_nuclei_stain = htk_cdeconv.color_deconvolution(im_nmzd, w_est,
                                                      255).Stains[:, :,
                                                                  nuclear_chid]

    # segment nuclei foreground
    th = skimage.filters.threshold_li(im_nuclei_stain) * 0.8
    # th = skimage.filters.threshold_otsu(im_nuclei_stain)
    im_fgnd_mask = im_nuclei_stain < th
    im_fgnd_mask = skimage.morphology.opening(im_fgnd_mask,
                                              skimage.morphology.disk(2))
    im_fgnd_mask = skimage.morphology.closing(im_fgnd_mask,
                                              skimage.morphology.disk(1))

    # detect nuclei
    im_dog, im_dog_sigma = htk_shape_filters.cdog(
        im_nuclei_stain,
        im_fgnd_mask,
        sigma_min=min_radius / np.sqrt(2),
        sigma_max=max_radius / np.sqrt(2))

    nuclei_coord = skimage.feature.peak_local_max(im_dog,
                                                  min_distance=min_radius / 2,
                                                  threshold_rel=0.1)

    nuclei_coord = nuclei_coord[im_fgnd_mask[nuclei_coord[:, 0],
                                             nuclei_coord[:, 1]], :]

    nuclei_rad = np.array([
        im_dog_sigma[nuclei_coord[i, 0], nuclei_coord[i, 1]] * np.sqrt(2)
        for i in range(nuclei_coord.shape[0])
    ])

    # display result
    if display_result:

        print 'Number of nuclei = ', nuclei_coord.shape[0]

        plt.figure(figsize=(30, 20))
        plt.subplot(2, 2, 1)
        plt.imshow(im_input)
        plt.title('Input', fontsize=labelsize)
        plt.axis('off')

        plt.subplot(2, 2, 2)
        plt.imshow(im_nuclei_stain)
        plt.title('Deconv nuclei stain', fontsize=labelsize)
        plt.axis('off')

        plt.subplot(2, 2, 3)
        plt.imshow(im_fgnd_mask)
        plt.title('Foreground mask', fontsize=labelsize)
        plt.axis('off')

        plt.subplot(2, 2, 4)
        plt.imshow(im_nmzd)
        plt.plot(nuclei_coord[:, 1], nuclei_coord[:, 0], 'k+')

        for i in range(nuclei_coord.shape[0]):

            cx = nuclei_coord[i, 1]
            cy = nuclei_coord[i, 0]
            r = nuclei_rad[i]

            mcircle = mpatches.Circle((cx, cy), r, color='g', fill=False)
            plt.gca().add_patch(mcircle)

        plt.title('Nuclei detection', fontsize=labelsize)
        plt.axis('off')

        plt.tight_layout()

    return nuclei_coord, nuclei_rad
Exemplo n.º 6
0
def detect_nuclei_kofahi(im_nuclei_stain, im_nuclei_fgnd_mask, min_radius,
                         max_radius, min_nucleus_area,
                         local_max_search_radius):
    """Performs a nuclear segmentation using kofahi's method.

    This method uses scale-adaptive multi-scale Laplacian-of-Gaussian filtering
    for blob enhancement and a local maximum clustering for segmentation. The
    original implementation described by Al-Kofahi et al. uses Laplacian of Gaussian
    but this function replaces it with Difference of Gaussian to improve speed.

    Parameters
    ----------
    im_nuclei_stain : array_like
        A hematoxylin intensity image obtained from ColorDeconvolution.
    im_nuclei_fgnd_mask: array_like
        A binary mask of the nuclear foreground typically obtained by applying
        a threshold on the hematoxylin/nuclei stain image
    min_radius : float
        Minimum nuclear radius (used to set min sigma of the multiscale LoG filter)
    max_radius : float
        Maximum nuclear radius (used to set max sigma of the multiscale LoG filter)
    min_nucleus_area : int
        Minimum area that each nucleus should have
    local_max_search_radius : float
        Local max search radius used for detection seed points in nuclei

    Returns
    -------
    im_nuclei_seg_mask : array_like
        A 2D array mask of the nuclei segmentation.

    References
    ----------
    .. [#] Y. Al-Kofahi et al "Improved Automatic Detection and Segmentation of
       Cell Nuclei in Histopathology Images" in IEEE Transactions on Biomedical
       Engineering, Volume: 57, Issue: 4, doi: 10.1109/TBME.2009.2035102,
       April 2010.

    """

    # smooth foreground mask with closing and opening
    im_nuclei_fgnd_mask = skimage.morphology.closing(
        im_nuclei_fgnd_mask, skimage.morphology.disk(3))

    im_nuclei_fgnd_mask = skimage.morphology.opening(
        im_nuclei_fgnd_mask, skimage.morphology.disk(3))

    im_nuclei_fgnd_mask = sp.ndimage.morphology.binary_fill_holes(
        im_nuclei_fgnd_mask)

    if not np.any(im_nuclei_fgnd_mask):
        return im_nuclei_fgnd_mask

    # run adaptive multi-scale LoG filter
    im_log_max, im_sigma_max = htk_shape_filters.cdog(
        im_nuclei_stain,
        im_nuclei_fgnd_mask,
        sigma_min=min_radius / np.sqrt(2),
        sigma_max=max_radius / np.sqrt(2))

    # apply local maximum clustering
    im_nuclei_seg_mask, seeds, maxima = htk.segmentation.nuclear.max_clustering(
        im_log_max, im_nuclei_fgnd_mask, local_max_search_radius)

    if seeds is None:
        return im_nuclei_seg_mask

    # split any objects with disconnected fragments
    im_nuclei_seg_mask = htk.segmentation.label.split(im_nuclei_seg_mask,
                                                      conn=8)

    # filter out small objects
    im_nuclei_seg_mask = htk.segmentation.label.area_open(
        im_nuclei_seg_mask, min_nucleus_area).astype(np.int)

    return im_nuclei_seg_mask