cellpose icon indicating copy to clipboard operation
cellpose copied to clipboard

Save cell center points in _seg.py

Open FrickTobias opened this issue 4 years ago • 7 comments

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()?

FrickTobias avatar Apr 13 '22 02:04 FrickTobias

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()

FrickTobias avatar Apr 13 '22 09:04 FrickTobias

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?

carsen-stringer avatar Apr 14 '22 16:04 carsen-stringer

If that would be possible that would be great!

FrickTobias avatar Apr 15 '22 02:04 FrickTobias

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.

rocketeer1998 avatar Jul 28 '22 02:07 rocketeer1998

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?

matrama avatar Jan 18 '23 20:01 matrama

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.

matrama avatar Jan 18 '23 20:01 matrama

@rocketeer1998 Minor point: you may want to pass np.unique(masks)[1:] to avoid calculating a center of mass for the zero-valued pixels.

asrvsn avatar Mar 04 '23 14:03 asrvsn