Source code for pywsi.segmentation.max_clustering

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
#import pyximport; pyximport.install()
import numpy as np
import skimage.measure

from ._max_clustering_cython import _max_clustering_cython
"""
This and _max_clustering_cython.pyx moudles are courtesy of
https://github.com/DigitalSlideArchive/HistomicsTK/tree/master/histomicstk
(Apache Licensed, see: https://github.com/DigitalSlideArchive/HistomicsTK/blob/dcd0d53f0cdc1424e1bedc0f0c0871a7a0e9fd70/LICENSE)
"""


[docs]def max_clustering(im_response, im_fgnd_mask, r=10): """Local max clustering pixel aggregation for nuclear segmentation. Takes as input a constrained log or other filtered nuclear image, a binary nuclear mask, and a clustering radius. For each pixel in the nuclear mask, the local max is identified. A hierarchy of local maxima is defined, and the root nodes used to define the label image. References [#]_ and [#]_ Parameters ---------- im_response : array_like A filtered-smoothed image where the maxima correspond to nuclear center. Typically obtained by constrained-LoG filtering on a hematoxylin intensity image obtained from ColorDeconvolution. im_fgnd_mask : array_like A binary mask of type boolean where nuclei pixels have value 'True', and non-nuclear pixels have value 'False'. r : float A scalar defining the clustering radius. Default value = 10. Returns ------- im_label : array_like im_label image where positive values correspond to foreground pixels that share mutual sinks. seeds : array_like An N x 2 array defining the (x,y) coordinates of nuclei seeds. max_response : array_like An N x 1 array containing the maximum response value corresponding to seeds. References ---------- .. [#] XW. Wu et al "The local maximum clustering method and its application in microarray gene expression data analysis," EURASIP J. Appl. Signal Processing, volume 2004, no.1, pp.53-63, 2004. .. [#] Y. Al-Kofahi et al "Improved Automatic Detection and Segmentation of Cell Nuclei in Histopathology Images" in IEEE Transactions on Biomedical Engineering,vol.57,no.4,pp.847-52, 2010. """ # find local maxima of all foreground pixels mval, mind = _max_clustering_cython(im_response, im_fgnd_mask.astype(np.int32), r) # identify connected regions of local maxima and define their seeds im_label = skimage.measure.label(im_fgnd_mask & (im_response == mval)) # compute normalized response min_resp = np.nanmin(im_response) max_resp = np.nanmin(im_response) resp_range = max_resp - min_resp im_response_nmzd = (im_response - min_resp) / resp_range # compute object properties obj_props = skimage.measure.regionprops(im_label, im_response_nmzd) obj_props = [ prop for prop in obj_props if np.isfinite(prop.weighted_centroid).all() ] num_labels = len(obj_props) # extract object seeds seeds = np.array( [obj_props[i].weighted_centroid for i in range(num_labels)]) seeds = np.round(seeds).astype(np.int) # fix seeds outside the object region - happens for non-convex objects for i in range(num_labels): sy = seeds[i, 0] sx = seeds[i, 1] if im_label[sy, sx] == obj_props[i].label: continue # find object point with closest manhattan distance to center of mass pts = obj_props[i].coords ydist = np.abs(pts[:, 0] - sy) xdist = np.abs(pts[:, 1] - sx) seeds[i, :] = pts[np.argmin(xdist + ydist), :] assert im_label[seeds[i, 0], seeds[i, 1]] == obj_props[i].label # get seed responses assert im_response.shape[1] >= 1, 'im_response.shape: {}'.format( im_response.shape) try: max_response = im_response[seeds[:, 0], seeds[:, 1]] except IndexError: # No seeds found! max_response = np.array([]) # set label of each foreground pixel to the label of its nearest peak im_label_flat = im_label.ravel() pind = np.flatnonzero(im_fgnd_mask) mind_flat = mind.ravel() im_label_flat[pind] = im_label_flat[mind_flat[pind]] # return return im_label, seeds, max_response