Module to count number of cells within a radius

I am trying to create a pipeline were I can plot nuclear staining intensity versus local population density. I was thinking of using a module/pipeline that could simply count the number of nuclei within a specific radius. Is this possible with any of the current modules out there?

I have tried this with MeasureObjectNeighbours however it doesn’t behave like I expected it to, it works okay as a rough estimation but manually looking at the images it hugely underestimates the number of neighbors and sometimes is off completely. I think this module is meant to measure something else, so I was wondering if there were any alternatives.

MeasureObjectNeighbours is definitely intended for that purpose. The “NumberOfNeighbors” metric should be correct for each object for the given distance you specify.

Do you mind uploading an image (set) and pipeline so we can reproduce what you are seeing and talk you through it? You could also try using the ShowDataOnImage to see what that metric looks like on a real image.

Hi Anne, thank you so much for your reply, sorry I have not got back to you in a while. I think the problem was that if there was two objects behind each other then it wouldn’t identify the one behind it, i don’t know if this is some problem with your expand edges thing. For example:
If it was looking at an image such as this, it would suggest there were 3 neighbours, which is a good approximation, however within this radius there are actually 5 neighbours because two were hidden by other nuclei.
So anyway I dug up an old forum post where someone had a similar problem, and they suggested to convert the nuclear point objects masks to a binary image and apply a Circle-average-filter in the Smooth module with my radius of choice. Using this I then measure the intensities at each of the points and since they overlap this gives a indication to the number of neighbours based on the intensity. (I also rescale the image at this point to lower processing time) It looks something like this:

This works quite well, and produces some very smooth graphs.

My question now, is do you think that this is a valid way to measure local density?
My other question is, is there a way to be able to convert the intensity values directly into neighbour counts using the math module. For example, at the moment I am sorting the excel sheet by these intensities and then dividing the values by the smallest value in the sheet -1, to make counts. I could do this in CellProfiler automatically, however this value seems to change from experiment to experiment, I was wondering how the convert to binary image works and why i get different intensity values for this minimum intensity.

Finally I just want to say a massive thanks to everyone working on CellProfiler and these forums, this is some amazing software and is so powerful. I hope to use it long into the future of my career.

Also I have attached my current pipeline:
Local Density V8.cppipe (46.2 KB)

Interesting! I definitely thought MeasureObjectNeighbours would count 5, not 3. It looks like we need someone with more expertise in this to guide you!

Hi @jackhenry,

I’m struggling to replicate the initial issue. Looking at your pipeline, it looks like MeasureObjectNeighbours is set to ‘Adjacent’ mode. This would only consider neighbours that are in direct contact, but the ‘Within a Specified Distance’ mode should be able to evaluate neighbours within a specified radius of the object of interest. I think this would be more in line with what you’re trying to achieve - did you try this?

You may also want to look into using the RelateObjects module to associate cells with your enlarged objects.

Hi @DStirling, thanks for your response,

The measure object neighbours in this pipeline is being used to ask a different question, ie, how many cells is each cell touching.

What I am having trouble with is the question: how many cells are in a radius of x um. Which would give a good measurement of local density. The idea was that from this, I can then ask, is this because the cells are touching etc.

I think that the issue with the module I am having is that the ‘Within a Specified Distance’ option uses some sort of expanding the edges of objects to measure the number of neighbours. Which is good for some uses but not the specific question i am trying to ask.
From the wiki:“The Neighbor distance is the number of pixels that each object is expanded for the neighbor calculation. Expanded objects that touch are considered neighbors.”

So if i am correct it should look something like this:

Where what i am doing with the smooth and circle average filter on the left, and what Within a Specified Distance from Measure Object Neighbours is doing on the right.

So i use a radius of 6px in Within a Specified Distance (half the radius of circle average filter), and i get wildly different results. I have attached an excel file (and pipeline) to show this. While the local density column (green) shows increasing density up to 6 neighbours, which looks correct. The measure object neighbours (yellow) shows neighbours of only 0/1 and doesn’t correspond to the circle average filter numbers either. (224.1 KB) Local Density V8.cppipe (44.9 KB)

Hi @jackhenry,

Looking at the code, it appears that the “within a specified distance” option actually behaves more similarly to your example on the left, rather than the one on the right. Each object is expanded individually before looking for it’s (unexpanded) neighbours. It’s only in “Expand until adjacent” mode that all of the objects are expanded prior to searching for neighbours.

Taking a quick look at your pipeline, your local density appears to analyse a radius of 12 pixels from the centroid, while the MeasureObjectNeighbours module is only set to expand each centroid by 6 pixels. If I’m understanding this correctly I therefore wouldn’t expect these measurements to be comparable. More importantly, your local density measurement looks like it expands all objects before searching for neighbours, since the neighbour is also expanded this effectively doubles the range in which you’re evaluating for neighbours. I’ve illustrated below:


1 Like