| | |
| | |
| | """ |
| | 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 |
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|