Save cell center points in _seg.py
I was wondering if it would be possible to save more metadata about cells.
I am in need of cell center points for downstream computation and they are already calculated as far as I can understand.
Current workaround
Right now I am trying to do something based on a modification of masks_to_flows_cpu()
# From CellPose docs
dat = np.load('_seg.npy', allow_pickle=True).item()
# Assuming (hoping) this loads the correct information
masks = dat['masks']
centers = calculate_centers(masks)
# Modified from masks_to_flow_cpu()
def calculate_centers(masks):
slices = scipy.ndimage.find_objects(masks)
# Initiate centers in appropriate format
for i,si in enumerate(slices):
if si is not None:
sr,sc = si
y,x = np.nonzero(masks[sr, sc] == (i+1))
y = y.astype(np.int32) + 1
x = x.astype(np.int32) + 1
ymed = np.median(y)
xmed = np.median(x)
center = (ymed, xmed)
# Append center to centers
return centers
Actual question
Would it be possible to save this in the output _seg.py files and load it into dat['centers']? Or possibly include a function for like calculate_centers()?
Update: Current (working) workaround for recalculating center points to plots, although I am not sure this will be correct always since it isn't calculated in the same way as in CellPose from what I can tell.
# Function for calculating centerpoints (again)
def calculate_centers(masks):
slices = scipy.ndimage.find_objects(masks)
centers = list()
for i, si in enumerate(slices):
if si is not None:
sr, sc = si
mask = masks[sr, sc]
center = scipy.ndimage.center_of_mass(mask)
center_rounded = (round(center[0]) + sr.start, round(center[1]) + sc.start)
centers.append(center_rounded)
return centers
# Load information and calculate center positions
dat = np.load('_seg.npy', allow_pickle=True).item()
masks = dat['masks']
image = dat['img']
centers = calculate_centers(masks)
# Initialize plot
plt.imshow(image)
# Add blue dots for every cell centra
for center in centers:
y, x = center
if xmin <= x <= xmax and ymin <= y <= ymax:
plt.plot(x, y, marker = "o", markersize = 1, markeredgecolor = "blue", markerfacecolor = "blue")
# Show plot
plt.show()
hey @FrickTobias I think there are several different ways to compute centers so we aren't going to support a specific function, but we could return the cell centers in the _seg.npy according to our function?
If that would be possible that would be great!
Another workaround may be like this:
from scipy import ndimage
result = ndimage.center_of_mass(masks, masks, np.unique(masks))
resultList = list(result)
df = pd.DataFrame(
resultList, columns=['row', 'column'])
df.drop(0, inplace=True, axis=0) #remove background NA
print(df)
df.to_csv("Centroid.csv")
Hope that helps.
hi, I used a very similar workaround and used ndimage center of mass function. My problem is that even if cellpose masks are detected well - showing up in different colors on the tiff image, when masks are connected to each other - only 1 center of mass is detected. So I really would be in a favor of a ready function builder inside cellpose - to take their centers.
ANyone else had that problem - maybe I could use someones else hack?
Hi, some update to the issue raised above: After looking in more detail on the code of ppl above I used what rocketeer1998 posted: in the function center of mass use - your mask image poth as input and label. Those arrays should have same size, I have previously used labels function from ndimage to create label (2nd argument in center of mass function) and this resulted in an issue of some masks being treated as one big masks instead of separate masks.
@rocketeer1998 Minor point: you may want to pass np.unique(masks)[1:] to avoid calculating a center of mass for the zero-valued pixels.