Forked from
Swain Lab / aliby / aliby-mirror
1222 commits behind the upstream repository.
-
Alán Muñoz authoredAlán Muñoz authored
cell.py 4.47 KiB
"""
Base functions to extract information from a single cell
These functions are automatically read, so only add new functions with
the same arguments as the existing ones.
Input:
:cell_mask: (x,y) 2-D cell mask
:trap_image: (x,y) 2-D or (x,y,z) 3-D cell mask
np.where is used to cover for cases where z>1
"""
import math
import numpy as np
from scipy import ndimage
from sklearn.cluster import KMeans
from skimage.filters import threshold_otsu
# Basic extraction functions
def area(cell_mask, trap_image=None):
return np.sum(cell_mask, dtype=int)
def eccentricity(cell_mask, trap_image=None):
min_ax, maj_ax = min_maj_approximation(cell_mask)
return np.sqrt(maj_ax ** 2 - min_ax ** 2) / maj_ax
def mean(cell_mask, trap_image):
return np.mean(trap_image[np.where(cell_mask)], dtype=float)
def median(cell_mask, trap_image):
return np.median(trap_image[np.where(cell_mask)])
def max2p5pc(cell_mask, trap_image):
npixels = cell_mask.sum()
top_pixels = int(np.ceil(npixels * 0.025))
sorted_vals = np.sort(trap_image[np.where(cell_mask)], axis=None)
top_vals = sorted_vals[-top_pixels:]
max2p5pc = np.mean(top_vals, dtype=float)
return max2p5pc
def max5px(cell_mask, trap_image):
sorted_vals = np.sort(trap_image[np.where(cell_mask)], axis=None)
top_vals = sorted_vals[-5:]
max5px = np.mean(top_vals, dtype=float)
return max5px
def max5px_med(cell_mask, trap_image):
sorted_vals = np.sort(trap_image[np.where(cell_mask)], axis=None)
top_vals = sorted_vals[-5:]
max5px = np.mean(top_vals, dtype=float)
med = sorted_vals[len(sorted_vals) // 2] if len(sorted_vals) else 1
return max5px / med if med else max5px
def max2p5pc_med(cell_mask, trap_image):
npixels = cell_mask.sum()
top_pixels = int(np.ceil(npixels * 0.025))
sorted_vals = np.sort(trap_image[np.where(cell_mask)], axis=None)
top_vals = sorted_vals[-top_pixels:]
max2p5pc = np.mean(top_vals, dtype=float)
med = sorted_vals[len(sorted_vals) // 2] if len(sorted_vals) else 1
return max2p5pc / med if med else max2p5pc
def std(cell_mask, trap_image):
return np.std(trap_image[np.where(cell_mask)], dtype=float)
## Specialised extraction functions
def foci_area_otsu(cell_mask, trap_image):
# Use otsu threshold to calculate the are of high-expression blobs inside a cell.
cell_pixels = trap_image[cell_mask]
cell_pixels = cell_pixels[~np.isnan(cell_pixels)]
threshold = threshold_otsu(cell_pixels)
return np.sum(cell_pixels > threshold)
def k2_top_median(cell_mask, trap_image):
# Use kmeans to cluster the contents of a cell in two, return the high median
# Useful when a big non-tagged organelle (e.g. vacuole) occupies a big fraction
# of the cell
if not np.any(cell_mask):
return np.nan
X = trap_image[np.where(cell_mask)].reshape(-1, 1)
kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
high_clust_id = kmeans.cluster_centers_.argmax()
major_cluster = X[kmeans.predict(X) == high_clust_id]
k2_top_median = np.median(major_cluster, axis=None)
return k2_top_median
def membraneMax5(cell_mask, trap_image):
pass
def membraneMedian(cell_mask, trap_image):
pass
def volume(cell_mask, trap_image=None):
"""Volume from a cell mask, assuming an ellipse.
Assumes the mask is the median plane of the ellipsoid.
Assumes rotational symmetry around the major axis.
"""
min_ax, maj_ax = min_maj_approximation(cell_mask, trap_image)
return (4 * math.pi * min_ax ** 2 * maj_ax) / 3
def conical_volume(cell_mask, trap_image=None):
padded = np.pad(cell_mask, 1, mode="constant", constant_values=0)
nearest_neighbor = ndimage.morphology.distance_transform_edt(padded == 1) * padded
return 4 * (nearest_neighbor.sum())
def spherical_volume(cell_mask, trap_image=None):
area = cell_mask.sum()
r = np.sqrt(area / np.pi)
return (4 * np.pi * r ** 3) / 3
def min_maj_approximation(cell_mask, trap_image=None):
"""Length approximation of minor and major axes of an ellipse from mask.
:param cell_mask:
:param trap_image:
:return:
"""
padded = np.pad(cell_mask, 1, mode="constant", constant_values=0)
nn = ndimage.morphology.distance_transform_edt(padded == 1) * padded
dn = ndimage.morphology.distance_transform_edt(nn - nn.max()) * padded
cone_top = ndimage.morphology.distance_transform_edt(dn == 0) * padded
min_ax = np.round(nn.max())
maj_ax = np.round(dn.max() + cone_top.sum() / 2)
return min_ax, maj_ax