How to calculate the distance between cells?

Hi everyone, when I measure the distance between microglias, I donnot know how to define the distance? I mean a microglia can have several adjacent microglia, Of course it is impossible that each distance are calculated, can someone give me some advice? thank you.

Hi @Totoro_Xie,

First, what is the goal of this measurement? By that I mean, is this a common thing to do when studying microglia? You are looking for a certain insight into the spatial organization of the microglia?

In fact, it is also possible to calculate each distance, say, of one point with respect to all the others. Manually, you can:

  1. open multi-point tool, click on all points you judge to be microglia

  2. go to Analyze > Measure to the a summary of the selected points, with x and y coordinates being the last two columns

  3. extract only the x and y coordinates from the results table

  4. Calculate the distance between each point with respect to all the remaining points. The equaion os simply the Euclidean distance,

    Distance = sqrt((x2-x1)^2+(y2-y1)^2)

This is the fastest way to answer your question, but there are better ways (more reproductible) to do that. For example,

  1. binarize the image to get only the microglia cells

  2. then calculate the center of mass or centroids of each cell through 3D Objects counter.

  3. extract only the x and y coordinates of centroids or Center of mass from the results table

  4. Finally, use these coordinates to determine the distance between one center of mass with respect to all the others. you could do that outsite of imageJ if you wish. It can be shown as a n by n matrix with n being the number of points, and the matrix will be simmetric with the main diagonal of zeros. The total number of unique distances follows the triangular sequence of n-1.

    number of unique distances = n*(n-1)/2

I’m still learning how to do some macro programming, so in case I end up trying to solve your problem I will post here. I hope this helped.

UPDATE: This is far from being an optimal macro, but with this you can save the distance matrix as a text file and work on it as you like…

run("Duplicate...", "title=example.png");
//normalized image intensity (just for the sake of visualization)
run("Enhance Contrast...", "saturated=0.5 normalize");
//set threshold - did it manually but you can try autoTreshold with a method of your choice
setThreshold(150, 255);
run("Convert to Mask");
run("Invert LUT");

// used 3D objects counter to get center of mass xM yM or centroids X and Y
// if the threshold was not perfect, you can set a size threshold for your objects, i set to compute objects with area higher than 100 pixels
run("3D Objects Counter", "threshold=128 slice=1 min.=100 max.=583696 exclude_objects_on_edges objects centroids centres_of_masses statistics summary");

// I did this just to rename to the results window to "Results". I was not sure if it was going to work with the old name
IJ.renameResults("Statistics for example.png","Results");

// To work with a matrix, i created a 16-bit image to compute the distances of the objects
// the "Distances" Image is n by n where n is the number of detected objects, I chose 16-bit so the distance can be up to 65535
newImage("Distances", "16-bit black", nResults, nResults, 1);

//for loops to compute the distances with Euclidean distance equation
for(cont=0;cont<nResults;cont++){
	x1=getResult("X",cont);	
	y1=getResult("Y",cont);
		
	for(cont2=cont;cont2<nResults;cont2++){
			x2=getResult("X",cont2);	
			y2=getResult("Y",cont2);
			if(cont==cont2){
				distance=0;	
			}
			else{
			distance=round(sqrt((x2-x2)^2)+(y2-y1)^2);
			}

			// set value of pixels with the distance, for both matrix elements cont,cont2 and cont2,cont since the distance is the same regardless of the order.
			selectWindow("Distances");
			setPixel(cont,cont2,distance);
			setPixel(cont2,cont,distance);
	}
}
// save the "Distances" image to a text image, which has all the distance values
dir=getDirectory("Choose a Directory")
saveAs("Text Image", dir+"/Distances.txt");
3 Likes

Thank you very much @leandroscholz. The goal of this measurement is comparing whether the distance between microglias has changed after brain injury. Now this is just a T-series imaging, average intensity projection. I used the first method you mentioned, this is really simple and practical. I have not tried the second method, macro programming is new to me, I will try it at a later time and tell you the results.

1 Like

You could look into Graph Theory and try different types of graphs or networks and look at their edges statistics (your nodes would be the centroid of the detected cells and the edges join different nodes in a variety of ways, depending on the graph you work with, e.g. minimal spanning tree, relative neighbour graph, k-neighbour graph, Gabriel graph (no not mine) and many others).

6 Likes

The previous comments are good - and my suggestion may require more programming work than you can bring to the project, but I’ll mention a few concepts that might be useful here. First - computing all of the point-to-point distances is not our of the question (based on the image you provided). The question is: how to analyze the data once you have done that. A very simple measure is to look at the MINIMUM distance from each point to another point. This tells you the distance to the nearest neighbor. Moving up in complexity, there is a method called Density Recovery Profile. This starts with a histogram of point-to-point distances and does a bit more processing. It can give you a better idea of the average distance to “nearby” neighbors, and it can also reveal the presence of a regular pattern to the packing. Finally, my favorite, you can compute the Voronoi Diagram of the set of points. This identifies, for each point, the set of “near neighbors”. This is slightly better than simply taking the nearEST neighbor. But, both the DRP and the Voronoi Diagram go well beyond what I would expect to find as a standard measurement tool in ImageJ - you would have to roll your own. The simplest method would involve computing ALL point-to-point distances, and then analyzing the resulting histogram. I suspect that this would give you a reliable result for the least amount of effort.

7 Likes

You can achieve a “morphological” version of the Voronoi diagram using the Find Maxima command and selecting the “segmented particles” as the Output type.

1 Like

@Totoro_Xie

I found something that could provide inccorrect distance calculation and corrected.

I changed the distance calculation line of code to:

distance=round(sqrt(pow((x2-x2),2))+pow((y2-y1),2));

instead of:

distance=round(sqrt((x2-x2)^2)+(y2-y1)^2);

I found this syntax issue when I was doing something for myself. (if your’re interested see here).

run("Duplicate...", "title=example.png");
//normalized image intensity (just for the sake of visualization)
run("Enhance Contrast...", "saturated=0.5 normalize");
//set threshold - did it manually but you can try autoTreshold with a method of your choice
setThreshold(150, 255);
run("Convert to Mask");
run("Invert LUT");

// used 3D objects counter to get center of mass xM yM or centroids X and Y
// if the threshold was not perfect, you can set a size threshold for your objects, i set to compute objects with area higher than 100 pixels
run("3D Objects Counter", "threshold=128 slice=1 min.=100 max.=583696 exclude_objects_on_edges objects centroids centres_of_masses statistics summary");

// I did this just to rename to the results window to "Results". I was not sure if it was going to work with the old name
IJ.renameResults("Statistics for example.png","Results");

// To work with a matrix, i created a 16-bit image to compute the distances of the objects
// the "Distances" Image is n by n where n is the number of detected objects, I chose 16-bit so the distance can be up to 65535
newImage("Distances", "16-bit black", nResults, nResults, 1);

//for loops to compute the distances with Euclidean distance equation
for(cont=0;cont&lt;nResults;cont++){
	x1=getResult("X",cont);	
	y1=getResult("Y",cont);

	for(cont2=cont;cont2&lt;nResults;cont2++){
			x2=getResult("X",cont2);	
			y2=getResult("Y",cont2);
			if(cont==cont2){
				distance=0;	
			}
			else{
			distance=round(sqrt(pow((x2-x2),2))+pow((y2-y1),2));
			}

			// set value of pixels with the distance, for both matrix elements cont,cont2 and cont2,cont since the distance is the same regardless of the order.
			selectWindow("Distances");
			setPixel(cont,cont2,distance);
			setPixel(cont2,cont,distance);
	}
}
// save the "Distances" image to a text image, which has all the distance values
dir=getDirectory("Choose a Directory")
saveAs("Text Image", dir+"/Distances.txt");
1 Like

In case anyone bumps into this thread and is tempted to copy-paste the Euclidean distance line of code from @leandroscholz (like I blindly did…), I wanted to note that one parenthesis is actually misplaced, as I ended up realizing when printing the distance to the Log. Maybe this’ll be useful for others.

Original line of code (misplaced parenthesis in single quotes), resulting in the sqrt only being applied to the first term (x2-x1)^2:
distance=round(sqrt(pow((x2-x2),2)')'+pow((y2-y1),2));

Adjusted line of code (edit: parenthesis was relocated to the end of the equation):
distance=round(sqrt(pow((x2-x1),2)+pow((y2-y1),2)));

2 Likes

From a simple centroid-to-centroid point of view, I wrote ImageJ macro code a while back that may be useful as a model. http://microscopynotes.com/imagej/macros/shortest_distances_and_clustering/index.html

However, as a biological problem, not sure this is a great metric as microglia send out long and likely asymmetric processes that are probably functional at the peripheries.

Cheers-
Michael