| |
| |
| """ |
| Created on Thu Apr 7 10:51:48 2022 |
| |
| @author: jma |
| """ |
|
|
| import numpy as np |
| from skimage import segmentation, measure, exposure, morphology |
| import scipy.ndimage as nd |
| from tqdm import tqdm |
| import skimage |
| import colorsys |
|
|
| def fill_holes(label_img, size=10, connectivity=1): |
| output_image = np.copy(label_img) |
| props = measure.regionprops(np.squeeze(label_img.astype('int')), cache=False) |
| for prop in props: |
| if prop.euler_number < 1: |
|
|
| patch = output_image[prop.slice] |
|
|
| filled = morphology.remove_small_holes( |
| ar=(patch == prop.label), |
| area_threshold=size, |
| connectivity=connectivity) |
|
|
| output_image[prop.slice] = np.where(filled, prop.label, patch) |
|
|
| return output_image |
|
|
| def watershed_post(distmaps, interiors, dist_thre=0.1, interior_thre=0.2): |
| """ |
| Parameters |
| ---------- |
| distmaps : float (N, H, W) N is the number of cells |
| distance transform map of cell/nuclear [0,1]. |
| interiors : float (N, H, W) |
| interior map of cell/nuclear [0,1]. |
| |
| Returns |
| ------- |
| label_images : uint (N, H, W) |
| cell/nuclear instance segmentation. |
| |
| """ |
| |
| label_images = [] |
| for maxima, interior in zip(distmaps, interiors): |
| interior = nd.gaussian_filter(interior.astype(np.float32), 2) |
| |
| if skimage.__version__ > '0.18.2': |
| markers = measure.label(morphology.h_maxima(image=maxima, h=dist_thre, footprint=morphology.disk(2))) |
| else: |
| markers = measure.label(morphology.h_maxima(image=maxima, h=dist_thre, selem=morphology.disk(2))) |
| |
| |
| label_image = segmentation.watershed(-1 * interior, markers, |
| mask=interior > interior_thre, |
| watershed_line=0) |
|
|
| label_image = morphology.remove_small_objects(label_image, min_size=15) |
| |
| label_image = fill_holes(label_image, size=15) |
|
|
| |
| label_image, _, _ = segmentation.relabel_sequential(label_image) |
| label_images.append(label_image) |
| label_images = np.stack(label_images, axis=0).astype(np.uint) |
| return label_images |
|
|
|
|
|
|
| def hsv_to_rgb(arr): |
| hsv_to_rgb_channels = np.vectorize(colorsys.hsv_to_rgb) |
| h, s, v = np.rollaxis(arr, axis=-1) |
| r, g, b = hsv_to_rgb_channels(h, s, v) |
| rgb = np.stack((r,g,b), axis=-1) |
| return rgb |
|
|
| def mask_overlay(img, masks): |
| """ overlay masks on image (set image to grayscale) |
| Adapted from https://github.com/MouseLand/cellpose/blob/06df602fbe074be02db3d716e280f0990816c726/cellpose/plot.py#L172 |
| Parameters |
| ---------------- |
| |
| img: int or float, 2D or 3D array |
| img is of size [Ly x Lx (x nchan)] |
| |
| masks: int, 2D array |
| masks where 0=NO masks; 1,2,...=mask labels |
| |
| Returns |
| ---------------- |
| |
| RGB: uint8, 3D array |
| array of masks overlaid on grayscale image |
| |
| """ |
|
|
| if img.ndim>2: |
| img = img.astype(np.float32).mean(axis=-1) |
| else: |
| img = img.astype(np.float32) |
| |
| HSV = np.zeros((img.shape[0], img.shape[1], 3), np.float32) |
| HSV[:,:,2] = np.clip((img / 255. if img.max() > 1 else img) * 1.5, 0, 1) |
| hues = np.linspace(0, 1, masks.max()+1)[np.random.permutation(masks.max())] |
| for n in range(int(masks.max())): |
| ipix = (masks==n+1).nonzero() |
| HSV[ipix[0],ipix[1],0] = hues[n] |
|
|
| HSV[ipix[0],ipix[1],1] = 1.0 |
| RGB = (hsv_to_rgb(HSV) * 255).astype(np.uint8) |
| return RGB |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|