Skip to content

tissue_components

Segment background and foreground masks from H&E image. Uses k-means clustering.

Parameters:

Name Type Description Default
img ndarray

The input H&E image. Shape (H, W, 3).

required
label ndarray

The nuclei label mask. Shape (H, W). This is used to mask out the nuclei when extracting tissue components. If None, the entire image is used.

None
device str

Device to use for computation. Options are 'cpu' or 'cuda'. If set to 'cuda', Cupy will be used for GPU acceleration.

'cpu'

Returns:

Type Description
Tuple[ndarray, ndarray]

Tuple[np.ndarray, np.ndarray]: The background and foreground masks. Shapes (H, W).

Source code in src/histolytics/utils/im.py
def tissue_components(
    img: np.ndarray, label: np.ndarray = None, device: str = "cpu"
) -> Tuple[np.ndarray, np.ndarray]:
    """Segment background and foreground masks from H&E image. Uses k-means clustering.

    Parameters:
        img (np.ndarray):
            The input H&E image. Shape (H, W, 3).
        label (np.ndarray):
            The nuclei label mask. Shape (H, W). This is used to mask out the nuclei when
            extracting tissue components. If None, the entire image is used.
        device (str):
            Device to use for computation. Options are 'cpu' or 'cuda'. If set to 'cuda',
            Cupy will be used for GPU acceleration.

    Returns:
        Tuple[np.ndarray, np.ndarray]:
            The background and foreground masks. Shapes (H, W).
    """
    # mask out dark pixels
    kmasks = kmeans_img(img, n_clust=3, device=device)

    if not np.any(kmasks):
        bg_mask = np.zeros(kmasks.shape[:2], dtype=bool)
        dark_mask = np.zeros(kmasks.shape[:2], dtype=bool)
        return bg_mask, dark_mask

    if _has_cp and device == "cuda":
        bg_mask, dark_mask = _get_tissue_bg_fg_cp(img, kmasks, label)
    else:
        bg_mask, dark_mask = _get_tissue_bg_fg_np(img, kmasks, label)

    bg_mask = rm_objects_mask(
        erosion(bg_mask, footprint_rectangle((3, 3))), min_size=1000, device=device
    )
    dark_mask = rm_objects_mask(
        dilation(dark_mask, footprint_rectangle((3, 3))), min_size=200, device=device
    )

    # couldn't get this work with cupyx.ndimage..
    bg_mask = ndimage.binary_fill_holes(bg_mask)
    dark_mask = ndimage.binary_fill_holes(dark_mask)

    return bg_mask, dark_mask